From be933ef2241d79558f91796cc5b3a161f72ebf9c Mon Sep 17 00:00:00 2001 From: manuel Date: Mon, 19 Oct 2020 00:52:24 +0200 Subject: sync with upstream --- cmake/addons/CMakeLists.txt | 72 +- cmake/addons/README.md | 12 +- cmake/cpack/deb/packages/kodi.txt.in | 2 +- cmake/installdata/common/addons.txt | 2 + cmake/installdata/rbpi/lirc.txt | 1 - cmake/modules/FindClangTidy.cmake | 26 + cmake/modules/FindCppcheck.cmake | 32 + cmake/modules/FindEGL.cmake | 8 +- cmake/modules/FindIncludeWhatYouUse.cmake | 26 + cmake/modules/FindLibDRM.cmake | 2 +- cmake/modules/FindLibDvd.cmake | 15 +- cmake/modules/FindMMAL.cmake | 55 - cmake/modules/FindOpenGLES.cmake | 8 +- cmake/modules/FindPlist.cmake | 4 +- cmake/platform/freebsd/rbpi.cmake | 1 - cmake/platform/linux/rbpi.cmake | 3 - cmake/platform/linux/wayland.cmake | 6 +- cmake/platform/windows/defines.txt | 2 +- cmake/platform/windowsstore/defines.txt | 2 +- cmake/scripts/android/ArchSetup.cmake | 1 + cmake/scripts/common/ArchSetup.cmake | 17 + cmake/scripts/common/HandleDepends.cmake | 8 +- cmake/scripts/common/Macros.cmake | 9 +- cmake/scripts/common/ProjectMacros.cmake | 8 +- cmake/scripts/darwin_embedded/ExtraTargets.cmake | 11 +- cmake/scripts/linux/ArchSetup.cmake | 10 - cmake/scripts/linux/Install.cmake | 2 +- cmake/scripts/osx/Install.cmake | 19 +- cmake/treedata/common/rbpi/rbpi.txt | 2 - cmake/treedata/common/subdirs.txt | 30 +- cmake/treedata/freebsd/subdirs.txt | 2 - cmake/treedata/linux/subdirs.txt | 2 - version.txt | 9 +- xbmc/addons/AddonBindings.cmake | 7 +- .../kodi-addon-dev-kit/include/kodi/AddonBase.h | 1288 -------- .../kodi-addon-dev-kit/include/kodi/AudioEngine.h | 618 ---- .../kodi-addon-dev-kit/include/kodi/CMakeLists.txt | 16 - .../kodi-addon-dev-kit/include/kodi/Filesystem.h | 2321 ------------- .../kodi-addon-dev-kit/include/kodi/General.h | 834 ----- .../kodi-addon-dev-kit/include/kodi/Network.h | 282 -- .../kodi-addon-dev-kit/include/kodi/StreamCodec.h | 126 - .../kodi-addon-dev-kit/include/kodi/StreamCrypto.h | 42 - .../include/kodi/addon-instance/AudioDecoder.h | 363 --- .../include/kodi/addon-instance/AudioEncoder.h | 218 -- .../include/kodi/addon-instance/CMakeLists.txt | 16 - .../include/kodi/addon-instance/Game.h | 2360 -------------- .../include/kodi/addon-instance/ImageDecoder.h | 315 -- .../include/kodi/addon-instance/Inputstream.h | 881 ----- .../include/kodi/addon-instance/PVR.h | 3423 -------------------- .../include/kodi/addon-instance/Peripheral.h | 847 ----- .../include/kodi/addon-instance/PeripheralUtils.h | 735 ----- .../include/kodi/addon-instance/Screensaver.h | 460 --- .../include/kodi/addon-instance/VFS.h | 1265 -------- .../include/kodi/addon-instance/VideoCodec.h | 246 -- .../include/kodi/addon-instance/Visualization.h | 789 ----- .../include/kodi/addon-instance/pvr/CMakeLists.txt | 13 - .../kodi/addon-instance/pvr/ChannelGroups.h | 271 -- .../include/kodi/addon-instance/pvr/Channels.h | 518 --- .../include/kodi/addon-instance/pvr/EDL.h | 90 - .../include/kodi/addon-instance/pvr/EPG.h | 500 --- .../include/kodi/addon-instance/pvr/General.h | 511 --- .../include/kodi/addon-instance/pvr/MenuHook.h | 130 - .../include/kodi/addon-instance/pvr/Recordings.h | 520 --- .../include/kodi/addon-instance/pvr/Stream.h | 330 -- .../include/kodi/addon-instance/pvr/Timers.h | 896 ----- .../include/kodi/c-api/CMakeLists.txt | 9 - .../kodi/c-api/addon-instance/CMakeLists.txt | 6 - .../kodi/c-api/addon-instance/image_decoder.h | 78 - .../include/kodi/c-api/addon-instance/pvr.h | 327 -- .../kodi/c-api/addon-instance/pvr/CMakeLists.txt | 14 - .../c-api/addon-instance/pvr/pvr_channel_groups.h | 54 - .../kodi/c-api/addon-instance/pvr/pvr_channels.h | 104 - .../kodi/c-api/addon-instance/pvr/pvr_defines.h | 61 - .../kodi/c-api/addon-instance/pvr/pvr_edl.h | 62 - .../kodi/c-api/addon-instance/pvr/pvr_epg.h | 653 ---- .../kodi/c-api/addon-instance/pvr/pvr_general.h | 288 -- .../kodi/c-api/addon-instance/pvr/pvr_menu_hook.h | 72 - .../kodi/c-api/addon-instance/pvr/pvr_recordings.h | 143 - .../kodi/c-api/addon-instance/pvr/pvr_stream.h | 155 - .../kodi/c-api/addon-instance/pvr/pvr_timers.h | 407 --- .../include/kodi/c-api/addon_base.h | 252 -- .../include/kodi/c-api/audio_engine.h | 308 -- .../include/kodi/c-api/filesystem.h | 299 -- .../include/kodi/c-api/general.h | 123 - .../include/kodi/c-api/network.h | 43 - .../include/kodi/gui/CMakeLists.txt | 9 - .../kodi-addon-dev-kit/include/kodi/gui/General.h | 175 - .../kodi-addon-dev-kit/include/kodi/gui/ListItem.h | 366 --- .../kodi-addon-dev-kit/include/kodi/gui/Window.h | 909 ------ .../include/kodi/gui/controls/Button.h | 171 - .../include/kodi/gui/controls/CMakeLists.txt | 16 - .../include/kodi/gui/controls/Edit.h | 275 -- .../include/kodi/gui/controls/FadeLabel.h | 153 - .../include/kodi/gui/controls/Image.h | 116 - .../include/kodi/gui/controls/Label.h | 121 - .../include/kodi/gui/controls/Progress.h | 114 - .../include/kodi/gui/controls/RadioButton.h | 167 - .../include/kodi/gui/controls/Rendering.h | 205 -- .../include/kodi/gui/controls/SettingsSlider.h | 326 -- .../include/kodi/gui/controls/Slider.h | 339 -- .../include/kodi/gui/controls/Spin.h | 365 --- .../include/kodi/gui/controls/TextBox.h | 168 - .../include/kodi/gui/definitions.h | 433 --- .../include/kodi/gui/dialogs/CMakeLists.txt | 14 - .../include/kodi/gui/dialogs/ContextMenu.h | 185 -- .../include/kodi/gui/dialogs/ExtendedProgress.h | 250 -- .../include/kodi/gui/dialogs/FileBrowser.h | 310 -- .../include/kodi/gui/dialogs/Keyboard.h | 422 --- .../include/kodi/gui/dialogs/Numeric.h | 362 --- .../include/kodi/gui/dialogs/OK.h | 99 - .../include/kodi/gui/dialogs/Progress.h | 255 -- .../include/kodi/gui/dialogs/Select.h | 269 -- .../include/kodi/gui/dialogs/TextViewer.h | 108 - .../include/kodi/gui/dialogs/YesNo.h | 188 -- .../include/kodi/gui/gl/CMakeLists.txt | 7 - .../kodi-addon-dev-kit/include/kodi/gui/gl/GL.h | 111 - .../include/kodi/gui/gl/GLonDX.h | 369 --- .../include/kodi/gui/gl/Shader.h | 594 ---- .../include/kodi/gui/renderHelper.h | 78 - .../include/kodi/platform/android/System.h | 114 - .../include/kodi/tools/CMakeLists.txt | 5 - .../include/kodi/tools/DllHelper.h | 211 -- .../kodi-addon-dev-kit/include/kodi/versions.h | 482 --- xbmc/addons/kodi-dev-kit/include/kodi/AddonBase.h | 1322 ++++++++ .../addons/kodi-dev-kit/include/kodi/AudioEngine.h | 619 ++++ .../kodi-dev-kit/include/kodi/CMakeLists.txt | 16 + xbmc/addons/kodi-dev-kit/include/kodi/Filesystem.h | 2367 ++++++++++++++ xbmc/addons/kodi-dev-kit/include/kodi/General.h | 834 +++++ xbmc/addons/kodi-dev-kit/include/kodi/Network.h | 282 ++ .../addons/kodi-dev-kit/include/kodi/StreamCodec.h | 126 + .../kodi-dev-kit/include/kodi/StreamCrypto.h | 42 + .../include/kodi/addon-instance/AudioDecoder.h | 595 ++++ .../include/kodi/addon-instance/AudioEncoder.h | 353 ++ .../include/kodi/addon-instance/CMakeLists.txt | 15 + .../include/kodi/addon-instance/Game.h | 1190 +++++++ .../include/kodi/addon-instance/ImageDecoder.h | 315 ++ .../include/kodi/addon-instance/Inputstream.h | 934 ++++++ .../kodi-dev-kit/include/kodi/addon-instance/PVR.h | 3423 ++++++++++++++++++++ .../include/kodi/addon-instance/Peripheral.h | 907 ++++++ .../include/kodi/addon-instance/Screensaver.h | 470 +++ .../kodi-dev-kit/include/kodi/addon-instance/VFS.h | 1226 +++++++ .../include/kodi/addon-instance/VideoCodec.h | 249 ++ .../include/kodi/addon-instance/Visualization.h | 992 ++++++ .../kodi/addon-instance/peripheral/CMakeLists.txt | 5 + .../addon-instance/peripheral/PeripheralUtils.h | 1277 ++++++++ .../include/kodi/addon-instance/pvr/CMakeLists.txt | 13 + .../kodi/addon-instance/pvr/ChannelGroups.h | 271 ++ .../include/kodi/addon-instance/pvr/Channels.h | 518 +++ .../include/kodi/addon-instance/pvr/EDL.h | 90 + .../include/kodi/addon-instance/pvr/EPG.h | 500 +++ .../include/kodi/addon-instance/pvr/General.h | 511 +++ .../include/kodi/addon-instance/pvr/MenuHook.h | 130 + .../include/kodi/addon-instance/pvr/Recordings.h | 520 +++ .../include/kodi/addon-instance/pvr/Stream.h | 330 ++ .../include/kodi/addon-instance/pvr/Timers.h | 896 +++++ .../kodi-dev-kit/include/kodi/c-api/CMakeLists.txt | 13 + .../kodi/c-api/addon-instance/CMakeLists.txt | 13 + .../kodi/c-api/addon-instance/audio_decoder.h | 92 + .../kodi/c-api/addon-instance/audio_encoder.h | 67 + .../include/kodi/c-api/addon-instance/game.h | 1212 +++++++ .../kodi/c-api/addon-instance/image_decoder.h | 83 + .../include/kodi/c-api/addon-instance/peripheral.h | 709 ++++ .../include/kodi/c-api/addon-instance/pvr.h | 332 ++ .../kodi/c-api/addon-instance/pvr/CMakeLists.txt | 14 + .../c-api/addon-instance/pvr/pvr_channel_groups.h | 59 + .../kodi/c-api/addon-instance/pvr/pvr_channels.h | 109 + .../kodi/c-api/addon-instance/pvr/pvr_defines.h | 66 + .../kodi/c-api/addon-instance/pvr/pvr_edl.h | 67 + .../kodi/c-api/addon-instance/pvr/pvr_epg.h | 658 ++++ .../kodi/c-api/addon-instance/pvr/pvr_general.h | 295 ++ .../kodi/c-api/addon-instance/pvr/pvr_menu_hook.h | 77 + .../kodi/c-api/addon-instance/pvr/pvr_recordings.h | 148 + .../kodi/c-api/addon-instance/pvr/pvr_stream.h | 160 + .../kodi/c-api/addon-instance/pvr/pvr_timers.h | 412 +++ .../kodi/c-api/addon-instance/screensaver.h | 75 + .../include/kodi/c-api/addon-instance/vfs.h | 149 + .../kodi/c-api/addon-instance/visualization.h | 117 + .../kodi-dev-kit/include/kodi/c-api/addon_base.h | 264 ++ .../kodi-dev-kit/include/kodi/c-api/audio_engine.h | 314 ++ .../kodi-dev-kit/include/kodi/c-api/filesystem.h | 325 ++ .../kodi-dev-kit/include/kodi/c-api/general.h | 130 + .../include/kodi/c-api/gui/CMakeLists.txt | 8 + .../include/kodi/c-api/gui/controls/CMakeLists.txt | 16 + .../include/kodi/c-api/gui/controls/button.h | 35 + .../include/kodi/c-api/gui/controls/edit.h | 79 + .../include/kodi/c-api/gui/controls/fade_label.h | 34 + .../include/kodi/c-api/gui/controls/image.h | 37 + .../include/kodi/c-api/gui/controls/label.h | 32 + .../include/kodi/c-api/gui/controls/progress.h | 32 + .../include/kodi/c-api/gui/controls/radio_button.h | 35 + .../include/kodi/c-api/gui/controls/rendering.h | 38 + .../kodi/c-api/gui/controls/settings_slider.h | 48 + .../include/kodi/c-api/gui/controls/slider.h | 48 + .../include/kodi/c-api/gui/controls/spin.h | 58 + .../include/kodi/c-api/gui/controls/text_box.h | 36 + .../include/kodi/c-api/gui/definitions.h | 106 + .../include/kodi/c-api/gui/dialogs/CMakeLists.txt | 14 + .../include/kodi/c-api/gui/dialogs/context_menu.h | 33 + .../kodi/c-api/gui/dialogs/extended_progress.h | 43 + .../include/kodi/c-api/gui/dialogs/filebrowser.h | 77 + .../include/kodi/c-api/gui/dialogs/keyboard.h | 74 + .../include/kodi/c-api/gui/dialogs/numeric.h | 54 + .../include/kodi/c-api/gui/dialogs/ok.h | 37 + .../include/kodi/c-api/gui/dialogs/progress.h | 45 + .../include/kodi/c-api/gui/dialogs/select.h | 42 + .../include/kodi/c-api/gui/dialogs/text_viewer.h | 30 + .../include/kodi/c-api/gui/dialogs/yes_no.h | 50 + .../kodi-dev-kit/include/kodi/c-api/gui/general.h | 37 + .../include/kodi/c-api/gui/input/CMakeLists.txt | 5 + .../include/kodi/c-api/gui/input/action_ids.h | 763 +++++ .../include/kodi/c-api/gui/list_item.h | 54 + .../kodi-dev-kit/include/kodi/c-api/gui/window.h | 183 ++ .../kodi-dev-kit/include/kodi/c-api/network.h | 48 + .../include/kodi/c-api/platform/android/system.h | 34 + .../kodi-dev-kit/include/kodi/gui/CMakeLists.txt | 8 + .../addons/kodi-dev-kit/include/kodi/gui/General.h | 176 + .../kodi-dev-kit/include/kodi/gui/ListItem.h | 345 ++ xbmc/addons/kodi-dev-kit/include/kodi/gui/Window.h | 915 ++++++ .../include/kodi/gui/controls/Button.h | 166 + .../include/kodi/gui/controls/CMakeLists.txt | 16 + .../kodi-dev-kit/include/kodi/gui/controls/Edit.h | 217 ++ .../include/kodi/gui/controls/FadeLabel.h | 148 + .../kodi-dev-kit/include/kodi/gui/controls/Image.h | 112 + .../kodi-dev-kit/include/kodi/gui/controls/Label.h | 118 + .../include/kodi/gui/controls/Progress.h | 112 + .../include/kodi/gui/controls/RadioButton.h | 214 ++ .../include/kodi/gui/controls/Rendering.h | 217 ++ .../include/kodi/gui/controls/SettingsSlider.h | 314 ++ .../include/kodi/gui/controls/Slider.h | 326 ++ .../kodi-dev-kit/include/kodi/gui/controls/Spin.h | 416 +++ .../include/kodi/gui/controls/TextBox.h | 164 + .../include/kodi/gui/dialogs/CMakeLists.txt | 14 + .../include/kodi/gui/dialogs/ContextMenu.h | 186 ++ .../include/kodi/gui/dialogs/ExtendedProgress.h | 242 ++ .../include/kodi/gui/dialogs/FileBrowser.h | 302 ++ .../include/kodi/gui/dialogs/Keyboard.h | 404 +++ .../include/kodi/gui/dialogs/Numeric.h | 346 ++ .../kodi-dev-kit/include/kodi/gui/dialogs/OK.h | 101 + .../include/kodi/gui/dialogs/Progress.h | 244 ++ .../kodi-dev-kit/include/kodi/gui/dialogs/Select.h | 269 ++ .../include/kodi/gui/dialogs/TextViewer.h | 109 + .../kodi-dev-kit/include/kodi/gui/dialogs/YesNo.h | 188 ++ .../include/kodi/gui/gl/CMakeLists.txt | 7 + xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GL.h | 112 + .../kodi-dev-kit/include/kodi/gui/gl/GLonDX.h | 389 +++ .../kodi-dev-kit/include/kodi/gui/gl/Shader.h | 571 ++++ .../include/kodi/gui/input/ActionIDs.h | 11 + .../include/kodi/gui/input/CMakeLists.txt | 5 + .../kodi-dev-kit/include/kodi/gui/renderHelper.h | 82 + .../include/kodi/platform/android/System.h | 105 + .../kodi-dev-kit/include/kodi/tools/CMakeLists.txt | 9 + .../kodi-dev-kit/include/kodi/tools/DllHelper.h | 211 ++ .../kodi-dev-kit/include/kodi/tools/EndTime.h | 215 ++ .../kodi-dev-kit/include/kodi/tools/StringUtils.h | 3086 ++++++++++++++++++ .../kodi-dev-kit/include/kodi/tools/Thread.h | 399 +++ .../addons/kodi-dev-kit/include/kodi/tools/Timer.h | 315 ++ xbmc/addons/kodi-dev-kit/include/kodi/versions.h | 492 +++ .../VideoPlayer/Interface/Addon/DemuxPacket.h | 2 +- xbmc/interfaces/json-rpc/schema/version.txt | 2 +- xbmc/utils/ActorProtocol.cpp | 371 +++ xbmc/utils/ActorProtocol.h | 114 + xbmc/utils/AlarmClock.cpp | 148 + xbmc/utils/AlarmClock.h | 67 + xbmc/utils/AliasShortcutUtils.cpp | 93 + xbmc/utils/AliasShortcutUtils.h | 14 + xbmc/utils/Archive.cpp | 461 +++ xbmc/utils/Archive.h | 182 ++ xbmc/utils/Base64.cpp | 128 + xbmc/utils/Base64.h | 27 + xbmc/utils/BitstreamConverter.cpp | 1219 +++++++ xbmc/utils/BitstreamConverter.h | 139 + xbmc/utils/BitstreamReader.cpp | 96 + xbmc/utils/BitstreamReader.h | 49 + xbmc/utils/BitstreamStats.cpp | 70 + xbmc/utils/BitstreamStats.h | 40 + xbmc/utils/BitstreamWriter.cpp | 113 + xbmc/utils/BitstreamWriter.h | 50 + xbmc/utils/BooleanLogic.cpp | 122 + xbmc/utils/BooleanLogic.h | 90 + xbmc/utils/BufferObject.cpp | 61 + xbmc/utils/BufferObject.h | 43 + xbmc/utils/BufferObjectFactory.cpp | 42 + xbmc/utils/BufferObjectFactory.h | 48 + xbmc/utils/CMakeLists.txt | 227 ++ xbmc/utils/CPUInfo.cpp | 62 + xbmc/utils/CPUInfo.h | 120 + xbmc/utils/CharsetConverter.cpp | 871 +++++ xbmc/utils/CharsetConverter.h | 169 + xbmc/utils/CharsetDetection.cpp | 639 ++++ xbmc/utils/CharsetDetection.h | 94 + xbmc/utils/Color.h | 32 + xbmc/utils/ColorUtils.cpp | 19 + xbmc/utils/ColorUtils.h | 23 + xbmc/utils/Crc32.cpp | 110 + xbmc/utils/Crc32.h | 31 + xbmc/utils/CryptThreading.cpp | 84 + xbmc/utils/CryptThreading.h | 45 + xbmc/utils/DMAHeapBufferObject.cpp | 186 ++ xbmc/utils/DMAHeapBufferObject.h | 38 + xbmc/utils/DatabaseUtils.cpp | 745 +++++ xbmc/utils/DatabaseUtils.h | 181 ++ xbmc/utils/Digest.cpp | 169 + xbmc/utils/Digest.h | 138 + xbmc/utils/DumbBufferObject.cpp | 160 + xbmc/utils/DumbBufferObject.h | 38 + xbmc/utils/EGLFence.cpp | 70 + xbmc/utils/EGLFence.h | 43 + xbmc/utils/EGLImage.cpp | 197 ++ xbmc/utils/EGLImage.h | 58 + xbmc/utils/EGLUtils.cpp | 615 ++++ xbmc/utils/EGLUtils.h | 232 ++ xbmc/utils/EmbeddedArt.cpp | 72 + xbmc/utils/EmbeddedArt.h | 49 + xbmc/utils/EndianSwap.cpp | 30 + xbmc/utils/EndianSwap.h | 90 + xbmc/utils/EventStream.h | 100 + xbmc/utils/EventStreamDetail.h | 69 + xbmc/utils/Fanart.cpp | 175 + xbmc/utils/Fanart.h | 107 + xbmc/utils/FileExtensionProvider.cpp | 182 ++ xbmc/utils/FileExtensionProvider.h | 79 + xbmc/utils/FileOperationJob.cpp | 353 ++ xbmc/utils/FileOperationJob.h | 85 + xbmc/utils/FileUtils.cpp | 351 ++ xbmc/utils/FileUtils.h | 31 + xbmc/utils/GBMBufferObject.cpp | 98 + xbmc/utils/GBMBufferObject.h | 48 + xbmc/utils/GLUtils.cpp | 267 ++ xbmc/utils/GLUtils.h | 46 + xbmc/utils/Geometry.h | 484 +++ xbmc/utils/GlobalsHandling.h | 202 ++ xbmc/utils/GroupUtils.cpp | 157 + xbmc/utils/GroupUtils.h | 32 + xbmc/utils/HTMLUtil.cpp | 229 ++ xbmc/utils/HTMLUtil.h | 23 + xbmc/utils/HttpHeader.cpp | 239 ++ xbmc/utils/HttpHeader.h | 53 + xbmc/utils/HttpParser.cpp | 236 ++ xbmc/utils/HttpParser.h | 98 + xbmc/utils/HttpRangeUtils.cpp | 424 +++ xbmc/utils/HttpRangeUtils.h | 187 ++ xbmc/utils/HttpResponse.cpp | 166 + xbmc/utils/HttpResponse.h | 125 + xbmc/utils/IArchivable.h | 22 + xbmc/utils/IBufferObject.h | 131 + xbmc/utils/ILocalizer.h | 23 + xbmc/utils/IPlatformLog.h | 40 + xbmc/utils/IRssObserver.h | 25 + xbmc/utils/IScreenshotSurface.h | 36 + xbmc/utils/ISerializable.h | 21 + xbmc/utils/ISortable.h | 23 + xbmc/utils/IXmlDeserializable.h | 19 + xbmc/utils/InfoLoader.cpp | 59 + xbmc/utils/InfoLoader.h | 33 + xbmc/utils/JSONVariantParser.cpp | 217 ++ xbmc/utils/JSONVariantParser.h | 22 + xbmc/utils/JSONVariantWriter.cpp | 92 + xbmc/utils/JSONVariantWriter.h | 21 + xbmc/utils/Job.h | 160 + xbmc/utils/JobManager.cpp | 423 +++ xbmc/utils/JobManager.h | 373 +++ xbmc/utils/LabelFormatter.cpp | 479 +++ xbmc/utils/LabelFormatter.h | 76 + xbmc/utils/LangCodeExpander.cpp | 1738 ++++++++++ xbmc/utils/LangCodeExpander.h | 143 + xbmc/utils/LegacyPathTranslation.cpp | 105 + xbmc/utils/LegacyPathTranslation.h | 47 + xbmc/utils/Literals.h | 29 + xbmc/utils/Locale.cpp | 284 ++ xbmc/utils/Locale.h | 161 + xbmc/utils/MathUtils.h | 215 ++ xbmc/utils/MemUtils.h | 30 + xbmc/utils/Mime.cpp | 699 ++++ xbmc/utils/Mime.h | 46 + xbmc/utils/Observer.cpp | 72 + xbmc/utils/Observer.h | 91 + xbmc/utils/POUtils.cpp | 305 ++ xbmc/utils/POUtils.h | 162 + xbmc/utils/ProgressJob.cpp | 185 ++ xbmc/utils/ProgressJob.h | 163 + xbmc/utils/Random.h | 26 + xbmc/utils/RecentlyAddedJob.cpp | 390 +++ xbmc/utils/RecentlyAddedJob.h | 30 + xbmc/utils/RegExp.cpp | 642 ++++ xbmc/utils/RegExp.h | 165 + xbmc/utils/RingBuffer.cpp | 246 ++ xbmc/utils/RingBuffer.h | 40 + xbmc/utils/RssManager.cpp | 198 ++ xbmc/utils/RssManager.h | 68 + xbmc/utils/RssReader.cpp | 413 +++ xbmc/utils/RssReader.h | 63 + xbmc/utils/SaveFileStateJob.cpp | 211 ++ xbmc/utils/SaveFileStateJob.h | 21 + xbmc/utils/ScopeGuard.h | 111 + xbmc/utils/ScraperParser.cpp | 616 ++++ xbmc/utils/ScraperParser.h | 78 + xbmc/utils/ScraperUrl.cpp | 432 +++ xbmc/utils/ScraperUrl.h | 122 + xbmc/utils/Screenshot.cpp | 116 + xbmc/utils/Screenshot.h | 28 + xbmc/utils/SortUtils.cpp | 1324 ++++++++ xbmc/utils/SortUtils.h | 224 ++ xbmc/utils/Speed.cpp | 582 ++++ xbmc/utils/Speed.h | 116 + xbmc/utils/StaticLoggerBase.cpp | 20 + xbmc/utils/StaticLoggerBase.h | 21 + xbmc/utils/Stopwatch.cpp | 47 + xbmc/utils/Stopwatch.h | 100 + xbmc/utils/StreamDetails.cpp | 627 ++++ xbmc/utils/StreamDetails.h | 137 + xbmc/utils/StreamUtils.cpp | 32 + xbmc/utils/StreamUtils.h | 17 + xbmc/utils/StringUtils.cpp | 1808 +++++++++++ xbmc/utils/StringUtils.h | 403 +++ xbmc/utils/StringValidation.cpp | 49 + xbmc/utils/StringValidation.h | 25 + xbmc/utils/SystemInfo.cpp | 1395 ++++++++ xbmc/utils/SystemInfo.h | 156 + xbmc/utils/Temperature.cpp | 481 +++ xbmc/utils/Temperature.h | 103 + xbmc/utils/TextSearch.cpp | 146 + xbmc/utils/TextSearch.h | 37 + xbmc/utils/TimeUtils.cpp | 101 + xbmc/utils/TimeUtils.h | 45 + xbmc/utils/TransformMatrix.h | 246 ++ xbmc/utils/UDMABufferObject.cpp | 201 ++ xbmc/utils/UDMABufferObject.h | 39 + xbmc/utils/URIUtils.cpp | 1441 ++++++++ xbmc/utils/URIUtils.h | 228 ++ xbmc/utils/UrlOptions.cpp | 169 + xbmc/utils/UrlOptions.h | 46 + xbmc/utils/Utf8Utils.cpp | 148 + xbmc/utils/Utf8Utils.h | 42 + xbmc/utils/VC1BitstreamParser.cpp | 149 + xbmc/utils/VC1BitstreamParser.h | 31 + xbmc/utils/Variant.cpp | 885 +++++ xbmc/utils/Variant.h | 170 + xbmc/utils/Vector.cpp | 32 + xbmc/utils/Vector.h | 39 + xbmc/utils/XBMCTinyXML.cpp | 264 ++ xbmc/utils/XBMCTinyXML.h | 59 + xbmc/utils/XMLUtils.cpp | 343 ++ xbmc/utils/XMLUtils.h | 95 + xbmc/utils/XSLTUtils.cpp | 103 + xbmc/utils/XSLTUtils.h | 51 + xbmc/utils/XTimeUtils.h | 76 + xbmc/utils/auto_buffer.cpp | 84 + xbmc/utils/auto_buffer.h | 93 + xbmc/utils/log.cpp | 288 ++ xbmc/utils/log.h | 217 ++ xbmc/utils/logtypes.h | 18 + xbmc/utils/params_check_macros.h | 62 + xbmc/utils/rfft.cpp | 72 + xbmc/utils/rfft.h | 39 + xbmc/utils/test/CMakeLists.txt | 53 + xbmc/utils/test/CXBMCTinyXML-test.xml | 6 + xbmc/utils/test/TestAlarmClock.cpp | 25 + xbmc/utils/test/TestAliasShortcutUtils.cpp | 91 + xbmc/utils/test/TestArchive.cpp | 411 +++ xbmc/utils/test/TestBase64.cpp | 77 + xbmc/utils/test/TestBitstreamStats.cpp | 58 + xbmc/utils/test/TestCPUInfo.cpp | 72 + xbmc/utils/test/TestCharsetConverter.cpp | 401 +++ xbmc/utils/test/TestCrc32.cpp | 50 + xbmc/utils/test/TestCryptThreading.cpp | 79 + xbmc/utils/test/TestDatabaseUtils.cpp | 1376 ++++++++ xbmc/utils/test/TestDigest.cpp | 99 + xbmc/utils/test/TestEndianSwap.cpp | 133 + xbmc/utils/test/TestFileOperationJob.cpp | 288 ++ xbmc/utils/test/TestFileUtils.cpp | 41 + xbmc/utils/test/TestGlobalsHandling.cpp | 25 + xbmc/utils/test/TestGlobalsHandlingPattern1.h | 40 + xbmc/utils/test/TestHTMLUtil.cpp | 36 + xbmc/utils/test/TestHttpHeader.cpp | 505 +++ xbmc/utils/test/TestHttpParser.cpp | 49 + xbmc/utils/test/TestHttpRangeUtils.cpp | 887 +++++ xbmc/utils/test/TestHttpResponse.cpp | 43 + xbmc/utils/test/TestJSONVariantParser.cpp | 189 ++ xbmc/utils/test/TestJSONVariantWriter.cpp | 151 + xbmc/utils/test/TestJobManager.cpp | 215 ++ xbmc/utils/test/TestLabelFormatter.cpp | 69 + xbmc/utils/test/TestLangCodeExpander.cpp | 29 + xbmc/utils/test/TestLocale.cpp | 272 ++ xbmc/utils/test/TestMathUtils.cpp | 59 + xbmc/utils/test/TestMime.cpp | 29 + xbmc/utils/test/TestPOUtils.cpp | 47 + xbmc/utils/test/TestRegExp.cpp | 169 + xbmc/utils/test/TestRingBuffer.cpp | 33 + xbmc/utils/test/TestScraperParser.cpp | 26 + xbmc/utils/test/TestScraperUrl.cpp | 34 + xbmc/utils/test/TestSortUtils.cpp | 123 + xbmc/utils/test/TestStopwatch.cpp | 64 + xbmc/utils/test/TestStreamDetails.cpp | 76 + xbmc/utils/test/TestStreamUtils.cpp | 23 + xbmc/utils/test/TestStringUtils.cpp | 605 ++++ xbmc/utils/test/TestSystemInfo.cpp | 326 ++ xbmc/utils/test/TestURIUtils.cpp | 585 ++++ xbmc/utils/test/TestUrlOptions.cpp | 193 ++ xbmc/utils/test/TestVariant.cpp | 334 ++ xbmc/utils/test/TestXBMCTinyXML.cpp | 58 + xbmc/utils/test/TestXMLUtils.cpp | 356 ++ xbmc/utils/test/Testlog.cpp | 102 + xbmc/utils/test/Testrfft.cpp | 41 + xbmc/utils/test/data/language/Spanish/strings.po | 26 + 504 files changed, 89894 insertions(+), 33691 deletions(-) delete mode 120000 cmake/installdata/rbpi/lirc.txt create mode 100644 cmake/modules/FindClangTidy.cmake create mode 100644 cmake/modules/FindCppcheck.cmake create mode 100644 cmake/modules/FindIncludeWhatYouUse.cmake delete mode 100644 cmake/modules/FindMMAL.cmake delete mode 100644 cmake/platform/freebsd/rbpi.cmake delete mode 100644 cmake/platform/linux/rbpi.cmake delete mode 100644 cmake/treedata/common/rbpi/rbpi.txt delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/AudioEngine.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/CMakeLists.txt delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/Filesystem.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/General.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/Network.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCodec.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCrypto.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/AudioDecoder.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/AudioEncoder.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/CMakeLists.txt delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Game.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/ImageDecoder.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/PVR.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Peripheral.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/PeripheralUtils.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Screensaver.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VFS.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VideoCodec.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Visualization.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/CMakeLists.txt delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/ChannelGroups.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Channels.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/EDL.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/EPG.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/General.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/MenuHook.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Recordings.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Stream.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Timers.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/CMakeLists.txt delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/CMakeLists.txt delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/image_decoder.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/CMakeLists.txt delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channel_groups.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channels.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_defines.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_edl.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_epg.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_general.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_menu_hook.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_recordings.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_stream.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_timers.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon_base.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/audio_engine.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/filesystem.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/general.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/network.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/CMakeLists.txt delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/General.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/ListItem.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/Window.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Button.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/CMakeLists.txt delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Edit.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/FadeLabel.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Image.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Label.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Progress.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/RadioButton.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Rendering.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/SettingsSlider.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Slider.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Spin.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/TextBox.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/definitions.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/CMakeLists.txt delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/ContextMenu.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/ExtendedProgress.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/FileBrowser.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Keyboard.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Numeric.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/OK.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Progress.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Select.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/TextViewer.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/YesNo.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/CMakeLists.txt delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GL.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GLonDX.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/Shader.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/renderHelper.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/platform/android/System.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/tools/CMakeLists.txt delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/tools/DllHelper.h delete mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/AddonBase.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/AudioEngine.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/Filesystem.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/General.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/Network.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/StreamCodec.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/StreamCrypto.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/AudioDecoder.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/AudioEncoder.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Game.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/ImageDecoder.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Inputstream.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/PVR.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Peripheral.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Screensaver.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/VFS.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/VideoCodec.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Visualization.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/peripheral/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/peripheral/PeripheralUtils.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/ChannelGroups.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Channels.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/EDL.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/EPG.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/General.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/MenuHook.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Recordings.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Stream.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Timers.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/audio_decoder.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/audio_encoder.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/game.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/image_decoder.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/peripheral.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channel_groups.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channels.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_defines.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_edl.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_epg.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_general.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_menu_hook.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_recordings.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_stream.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_timers.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/screensaver.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/vfs.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/visualization.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon_base.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/audio_engine.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/filesystem.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/general.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/button.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/edit.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/fade_label.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/image.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/label.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/progress.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/radio_button.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/rendering.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/settings_slider.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/slider.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/spin.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/text_box.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/definitions.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/context_menu.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/extended_progress.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/filebrowser.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/keyboard.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/numeric.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/ok.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/progress.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/select.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/text_viewer.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/yes_no.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/general.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input/action_ids.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/list_item.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/window.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/network.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/c-api/platform/android/system.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/General.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/ListItem.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/Window.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Button.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Edit.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/FadeLabel.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Image.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Label.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Progress.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/RadioButton.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Rendering.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/SettingsSlider.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Slider.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Spin.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/TextBox.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/ContextMenu.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/ExtendedProgress.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/FileBrowser.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Keyboard.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Numeric.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/OK.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Progress.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Select.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/TextViewer.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/YesNo.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GL.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GLonDX.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/Shader.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/input/ActionIDs.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/input/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/gui/renderHelper.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/platform/android/System.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/tools/CMakeLists.txt create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/tools/DllHelper.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/tools/EndTime.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/tools/StringUtils.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/tools/Thread.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/tools/Timer.h create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/versions.h create mode 100644 xbmc/utils/ActorProtocol.cpp create mode 100644 xbmc/utils/ActorProtocol.h create mode 100644 xbmc/utils/AlarmClock.cpp create mode 100644 xbmc/utils/AlarmClock.h create mode 100644 xbmc/utils/AliasShortcutUtils.cpp create mode 100644 xbmc/utils/AliasShortcutUtils.h create mode 100644 xbmc/utils/Archive.cpp create mode 100644 xbmc/utils/Archive.h create mode 100644 xbmc/utils/Base64.cpp create mode 100644 xbmc/utils/Base64.h create mode 100644 xbmc/utils/BitstreamConverter.cpp create mode 100644 xbmc/utils/BitstreamConverter.h create mode 100644 xbmc/utils/BitstreamReader.cpp create mode 100644 xbmc/utils/BitstreamReader.h create mode 100644 xbmc/utils/BitstreamStats.cpp create mode 100644 xbmc/utils/BitstreamStats.h create mode 100644 xbmc/utils/BitstreamWriter.cpp create mode 100644 xbmc/utils/BitstreamWriter.h create mode 100644 xbmc/utils/BooleanLogic.cpp create mode 100644 xbmc/utils/BooleanLogic.h create mode 100644 xbmc/utils/BufferObject.cpp create mode 100644 xbmc/utils/BufferObject.h create mode 100644 xbmc/utils/BufferObjectFactory.cpp create mode 100644 xbmc/utils/BufferObjectFactory.h create mode 100644 xbmc/utils/CMakeLists.txt create mode 100644 xbmc/utils/CPUInfo.cpp create mode 100644 xbmc/utils/CPUInfo.h create mode 100644 xbmc/utils/CharsetConverter.cpp create mode 100644 xbmc/utils/CharsetConverter.h create mode 100644 xbmc/utils/CharsetDetection.cpp create mode 100644 xbmc/utils/CharsetDetection.h create mode 100644 xbmc/utils/Color.h create mode 100644 xbmc/utils/ColorUtils.cpp create mode 100644 xbmc/utils/ColorUtils.h create mode 100644 xbmc/utils/Crc32.cpp create mode 100644 xbmc/utils/Crc32.h create mode 100644 xbmc/utils/CryptThreading.cpp create mode 100644 xbmc/utils/CryptThreading.h create mode 100644 xbmc/utils/DMAHeapBufferObject.cpp create mode 100644 xbmc/utils/DMAHeapBufferObject.h create mode 100644 xbmc/utils/DatabaseUtils.cpp create mode 100644 xbmc/utils/DatabaseUtils.h create mode 100644 xbmc/utils/Digest.cpp create mode 100644 xbmc/utils/Digest.h create mode 100644 xbmc/utils/DumbBufferObject.cpp create mode 100644 xbmc/utils/DumbBufferObject.h create mode 100644 xbmc/utils/EGLFence.cpp create mode 100644 xbmc/utils/EGLFence.h create mode 100644 xbmc/utils/EGLImage.cpp create mode 100644 xbmc/utils/EGLImage.h create mode 100644 xbmc/utils/EGLUtils.cpp create mode 100644 xbmc/utils/EGLUtils.h create mode 100644 xbmc/utils/EmbeddedArt.cpp create mode 100644 xbmc/utils/EmbeddedArt.h create mode 100644 xbmc/utils/EndianSwap.cpp create mode 100644 xbmc/utils/EndianSwap.h create mode 100644 xbmc/utils/EventStream.h create mode 100644 xbmc/utils/EventStreamDetail.h create mode 100644 xbmc/utils/Fanart.cpp create mode 100644 xbmc/utils/Fanart.h create mode 100644 xbmc/utils/FileExtensionProvider.cpp create mode 100644 xbmc/utils/FileExtensionProvider.h create mode 100644 xbmc/utils/FileOperationJob.cpp create mode 100644 xbmc/utils/FileOperationJob.h create mode 100644 xbmc/utils/FileUtils.cpp create mode 100644 xbmc/utils/FileUtils.h create mode 100644 xbmc/utils/GBMBufferObject.cpp create mode 100644 xbmc/utils/GBMBufferObject.h create mode 100644 xbmc/utils/GLUtils.cpp create mode 100644 xbmc/utils/GLUtils.h create mode 100644 xbmc/utils/Geometry.h create mode 100644 xbmc/utils/GlobalsHandling.h create mode 100644 xbmc/utils/GroupUtils.cpp create mode 100644 xbmc/utils/GroupUtils.h create mode 100644 xbmc/utils/HTMLUtil.cpp create mode 100644 xbmc/utils/HTMLUtil.h create mode 100644 xbmc/utils/HttpHeader.cpp create mode 100644 xbmc/utils/HttpHeader.h create mode 100644 xbmc/utils/HttpParser.cpp create mode 100644 xbmc/utils/HttpParser.h create mode 100644 xbmc/utils/HttpRangeUtils.cpp create mode 100644 xbmc/utils/HttpRangeUtils.h create mode 100644 xbmc/utils/HttpResponse.cpp create mode 100644 xbmc/utils/HttpResponse.h create mode 100644 xbmc/utils/IArchivable.h create mode 100644 xbmc/utils/IBufferObject.h create mode 100644 xbmc/utils/ILocalizer.h create mode 100644 xbmc/utils/IPlatformLog.h create mode 100644 xbmc/utils/IRssObserver.h create mode 100644 xbmc/utils/IScreenshotSurface.h create mode 100644 xbmc/utils/ISerializable.h create mode 100644 xbmc/utils/ISortable.h create mode 100644 xbmc/utils/IXmlDeserializable.h create mode 100644 xbmc/utils/InfoLoader.cpp create mode 100644 xbmc/utils/InfoLoader.h create mode 100644 xbmc/utils/JSONVariantParser.cpp create mode 100644 xbmc/utils/JSONVariantParser.h create mode 100644 xbmc/utils/JSONVariantWriter.cpp create mode 100644 xbmc/utils/JSONVariantWriter.h create mode 100644 xbmc/utils/Job.h create mode 100644 xbmc/utils/JobManager.cpp create mode 100644 xbmc/utils/JobManager.h create mode 100644 xbmc/utils/LabelFormatter.cpp create mode 100644 xbmc/utils/LabelFormatter.h create mode 100644 xbmc/utils/LangCodeExpander.cpp create mode 100644 xbmc/utils/LangCodeExpander.h create mode 100644 xbmc/utils/LegacyPathTranslation.cpp create mode 100644 xbmc/utils/LegacyPathTranslation.h create mode 100644 xbmc/utils/Literals.h create mode 100644 xbmc/utils/Locale.cpp create mode 100644 xbmc/utils/Locale.h create mode 100644 xbmc/utils/MathUtils.h create mode 100644 xbmc/utils/MemUtils.h create mode 100644 xbmc/utils/Mime.cpp create mode 100644 xbmc/utils/Mime.h create mode 100644 xbmc/utils/Observer.cpp create mode 100644 xbmc/utils/Observer.h create mode 100644 xbmc/utils/POUtils.cpp create mode 100644 xbmc/utils/POUtils.h create mode 100644 xbmc/utils/ProgressJob.cpp create mode 100644 xbmc/utils/ProgressJob.h create mode 100644 xbmc/utils/Random.h create mode 100644 xbmc/utils/RecentlyAddedJob.cpp create mode 100644 xbmc/utils/RecentlyAddedJob.h create mode 100644 xbmc/utils/RegExp.cpp create mode 100644 xbmc/utils/RegExp.h create mode 100644 xbmc/utils/RingBuffer.cpp create mode 100644 xbmc/utils/RingBuffer.h create mode 100644 xbmc/utils/RssManager.cpp create mode 100644 xbmc/utils/RssManager.h create mode 100644 xbmc/utils/RssReader.cpp create mode 100644 xbmc/utils/RssReader.h create mode 100644 xbmc/utils/SaveFileStateJob.cpp create mode 100644 xbmc/utils/SaveFileStateJob.h create mode 100644 xbmc/utils/ScopeGuard.h create mode 100644 xbmc/utils/ScraperParser.cpp create mode 100644 xbmc/utils/ScraperParser.h create mode 100644 xbmc/utils/ScraperUrl.cpp create mode 100644 xbmc/utils/ScraperUrl.h create mode 100644 xbmc/utils/Screenshot.cpp create mode 100644 xbmc/utils/Screenshot.h create mode 100644 xbmc/utils/SortUtils.cpp create mode 100644 xbmc/utils/SortUtils.h create mode 100644 xbmc/utils/Speed.cpp create mode 100644 xbmc/utils/Speed.h create mode 100644 xbmc/utils/StaticLoggerBase.cpp create mode 100644 xbmc/utils/StaticLoggerBase.h create mode 100644 xbmc/utils/Stopwatch.cpp create mode 100644 xbmc/utils/Stopwatch.h create mode 100644 xbmc/utils/StreamDetails.cpp create mode 100644 xbmc/utils/StreamDetails.h create mode 100644 xbmc/utils/StreamUtils.cpp create mode 100644 xbmc/utils/StreamUtils.h create mode 100644 xbmc/utils/StringUtils.cpp create mode 100644 xbmc/utils/StringUtils.h create mode 100644 xbmc/utils/StringValidation.cpp create mode 100644 xbmc/utils/StringValidation.h create mode 100644 xbmc/utils/SystemInfo.cpp create mode 100644 xbmc/utils/SystemInfo.h create mode 100644 xbmc/utils/Temperature.cpp create mode 100644 xbmc/utils/Temperature.h create mode 100644 xbmc/utils/TextSearch.cpp create mode 100644 xbmc/utils/TextSearch.h create mode 100644 xbmc/utils/TimeUtils.cpp create mode 100644 xbmc/utils/TimeUtils.h create mode 100644 xbmc/utils/TransformMatrix.h create mode 100644 xbmc/utils/UDMABufferObject.cpp create mode 100644 xbmc/utils/UDMABufferObject.h create mode 100644 xbmc/utils/URIUtils.cpp create mode 100644 xbmc/utils/URIUtils.h create mode 100644 xbmc/utils/UrlOptions.cpp create mode 100644 xbmc/utils/UrlOptions.h create mode 100644 xbmc/utils/Utf8Utils.cpp create mode 100644 xbmc/utils/Utf8Utils.h create mode 100644 xbmc/utils/VC1BitstreamParser.cpp create mode 100644 xbmc/utils/VC1BitstreamParser.h create mode 100644 xbmc/utils/Variant.cpp create mode 100644 xbmc/utils/Variant.h create mode 100644 xbmc/utils/Vector.cpp create mode 100644 xbmc/utils/Vector.h create mode 100644 xbmc/utils/XBMCTinyXML.cpp create mode 100644 xbmc/utils/XBMCTinyXML.h create mode 100644 xbmc/utils/XMLUtils.cpp create mode 100644 xbmc/utils/XMLUtils.h create mode 100644 xbmc/utils/XSLTUtils.cpp create mode 100644 xbmc/utils/XSLTUtils.h create mode 100644 xbmc/utils/XTimeUtils.h create mode 100644 xbmc/utils/auto_buffer.cpp create mode 100644 xbmc/utils/auto_buffer.h create mode 100644 xbmc/utils/log.cpp create mode 100644 xbmc/utils/log.h create mode 100644 xbmc/utils/logtypes.h create mode 100644 xbmc/utils/params_check_macros.h create mode 100644 xbmc/utils/rfft.cpp create mode 100644 xbmc/utils/rfft.h create mode 100644 xbmc/utils/test/CMakeLists.txt create mode 100644 xbmc/utils/test/CXBMCTinyXML-test.xml create mode 100644 xbmc/utils/test/TestAlarmClock.cpp create mode 100644 xbmc/utils/test/TestAliasShortcutUtils.cpp create mode 100644 xbmc/utils/test/TestArchive.cpp create mode 100644 xbmc/utils/test/TestBase64.cpp create mode 100644 xbmc/utils/test/TestBitstreamStats.cpp create mode 100644 xbmc/utils/test/TestCPUInfo.cpp create mode 100644 xbmc/utils/test/TestCharsetConverter.cpp create mode 100644 xbmc/utils/test/TestCrc32.cpp create mode 100644 xbmc/utils/test/TestCryptThreading.cpp create mode 100644 xbmc/utils/test/TestDatabaseUtils.cpp create mode 100644 xbmc/utils/test/TestDigest.cpp create mode 100644 xbmc/utils/test/TestEndianSwap.cpp create mode 100644 xbmc/utils/test/TestFileOperationJob.cpp create mode 100644 xbmc/utils/test/TestFileUtils.cpp create mode 100644 xbmc/utils/test/TestGlobalsHandling.cpp create mode 100644 xbmc/utils/test/TestGlobalsHandlingPattern1.h create mode 100644 xbmc/utils/test/TestHTMLUtil.cpp create mode 100644 xbmc/utils/test/TestHttpHeader.cpp create mode 100644 xbmc/utils/test/TestHttpParser.cpp create mode 100644 xbmc/utils/test/TestHttpRangeUtils.cpp create mode 100644 xbmc/utils/test/TestHttpResponse.cpp create mode 100644 xbmc/utils/test/TestJSONVariantParser.cpp create mode 100644 xbmc/utils/test/TestJSONVariantWriter.cpp create mode 100644 xbmc/utils/test/TestJobManager.cpp create mode 100644 xbmc/utils/test/TestLabelFormatter.cpp create mode 100644 xbmc/utils/test/TestLangCodeExpander.cpp create mode 100644 xbmc/utils/test/TestLocale.cpp create mode 100644 xbmc/utils/test/TestMathUtils.cpp create mode 100644 xbmc/utils/test/TestMime.cpp create mode 100644 xbmc/utils/test/TestPOUtils.cpp create mode 100644 xbmc/utils/test/TestRegExp.cpp create mode 100644 xbmc/utils/test/TestRingBuffer.cpp create mode 100644 xbmc/utils/test/TestScraperParser.cpp create mode 100644 xbmc/utils/test/TestScraperUrl.cpp create mode 100644 xbmc/utils/test/TestSortUtils.cpp create mode 100644 xbmc/utils/test/TestStopwatch.cpp create mode 100644 xbmc/utils/test/TestStreamDetails.cpp create mode 100644 xbmc/utils/test/TestStreamUtils.cpp create mode 100644 xbmc/utils/test/TestStringUtils.cpp create mode 100644 xbmc/utils/test/TestSystemInfo.cpp create mode 100644 xbmc/utils/test/TestURIUtils.cpp create mode 100644 xbmc/utils/test/TestUrlOptions.cpp create mode 100644 xbmc/utils/test/TestVariant.cpp create mode 100644 xbmc/utils/test/TestXBMCTinyXML.cpp create mode 100644 xbmc/utils/test/TestXMLUtils.cpp create mode 100644 xbmc/utils/test/Testlog.cpp create mode 100644 xbmc/utils/test/Testrfft.cpp create mode 100644 xbmc/utils/test/data/language/Spanish/strings.po diff --git a/cmake/addons/CMakeLists.txt b/cmake/addons/CMakeLists.txt index 3dccc01..c1313d7 100644 --- a/cmake/addons/CMakeLists.txt +++ b/cmake/addons/CMakeLists.txt @@ -244,26 +244,80 @@ endif() # error either in ADDONS_TO_BUILD or in the directory configuration. set(SUPPORTED_ADDON_FOUND FALSE) +if(NOT ADDONS_TO_BUILD) + set(ADDONS_TO_BUILD "all") +endif() + +if(NOT ADDONS_TO_BUILD STREQUAL "all") + # Exact addon match list + set(REGEX_ADDONS_TO_BUILD ${ADDONS_TO_BUILD}) + set(EXACT_MATCH_ADDON_LIST "") + set(EXCLUDE_ADDONS "") + + foreach(addon ${ADDONS_TO_BUILD}) + set(FOUND_EXCLUSION "") + string(REGEX MATCH "^[-](.*)" FOUND_EXCLUSION "${addon}") + if(NOT FOUND_EXCLUSION STREQUAL "") + list(APPEND EXCLUDE_ADDONS ${CMAKE_MATCH_1}) + list(REMOVE_ITEM REGEX_ADDONS_TO_BUILD "-${CMAKE_MATCH_1}") + else() + foreach(addonrepoitem ${addons}) + if(NOT (addonrepoitem MATCHES platforms.txt)) + # need to strip regex chars, or the filter regex will use + string(REPLACE "*" "" strippedregex ${addon}) + if(${addonrepoitem} MATCHES "^.*\/(${strippedregex}).txt") + list(APPEND EXACT_MATCH_ADDON_LIST ${addon}) + # remove exact matches from addons_to_build + list(REMOVE_ITEM REGEX_ADDONS_TO_BUILD "${addon}") + endif() + endif() + endforeach() + endif() + endforeach() + + message(STATUS "Exclusion list: ${EXCLUDE_ADDONS}") + message(STATUS "Exact Match list: ${EXACT_MATCH_ADDON_LIST}") + message(STATUS "Regex list: ${REGEX_ADDONS_TO_BUILD}") +endif() + foreach(addon ${addons}) if(NOT (addon MATCHES platforms.txt)) file(STRINGS ${addon} def) string(REPLACE " " ";" def ${def}) list(GET def 0 id) - set(ADDON_FOUND FALSE) - # try to find a perfect match - list(FIND ADDONS_TO_BUILD ${id} idx) - if(idx GREATER -1 OR "${ADDONS_TO_BUILD}" STREQUAL "all") + if("${ADDONS_TO_BUILD}" STREQUAL "all") set(ADDON_FOUND TRUE) - # Maybe we have a regex else() - foreach(ADDONLISTITEM ${ADDONS_TO_BUILD}) - if(id MATCHES "${ADDONLISTITEM}") - message(STATUS "Pattern ${ADDONLISTITEM} matches ${id}, building addon") - set(ADDON_FOUND TRUE) + set(ADDON_EXCLUDE FALSE) + set(ADDON_FOUND FALSE) + foreach(exclusion ${EXCLUDE_ADDONS}) + if(id MATCHES "${exclusion}") + set(ADDON_EXCLUDE TRUE) + message(STATUS "Addon ${id} matches exclusion rule -${exclusion}") break() endif() endforeach() + + if(ADDON_EXCLUDE) + continue() + endif() + + list(FIND EXACT_MATCH_ADDON_LIST ${id} idx) + if(idx GREATER -1) + # exact match, so build + message(STATUS "Exact match ${id}, building addon") + set(ADDON_FOUND TRUE) + else() + # regex search + foreach(ADDONLISTITEM ${REGEX_ADDONS_TO_BUILD}) + if(id MATCHES "${ADDONLISTITEM}") + message(STATUS "Pattern ${ADDONLISTITEM} matches ${id}, building addon") + set(ADDON_FOUND TRUE) + break() + endif() + endforeach() + endif() endif() if(ADDON_FOUND) diff --git a/cmake/addons/README.md b/cmake/addons/README.md index 17e6460..ed1894e 100644 --- a/cmake/addons/README.md +++ b/cmake/addons/README.md @@ -18,16 +18,18 @@ where List of platforms to build an add-on for (or *all*). Negating platforms is supported using a leading exclamation mark, e.g. *!windows*. -Available platforms are: linux, windows, osx, ios, android, rbpi and freebsd. +Available platforms are: linux, windows, osx, ios, android and freebsd. #### Attention If no add-on definitions could be found, the buildsystem assumes that the bootstrapping of the add-on definition repositories hasn't been performed yet and automatically executes the add-on bootstrapping buildsystem located in the *bootstrap* sub-directory with the default settings (i.e. *all* add-ons from all pre-defined add-on definition repositories are bootstrapped into the directory pointed to by the *ADDONS_DEFINITION_DIR* option). ## Buildsystem variables The buildsystem uses the following addon-related variables (which can be passed into it when executing cmake with the -D`=` format) to manipulate the build process: -- `ADDONS_TO_BUILD` has two variations, which are tested in order: - - a quoted, space delimited list of `s` that you want to build (default is *all*) - - a regular expression that every `` is matched against (e.g. `ADDONS_TO_BUILD="pvr.*"`) to build all pvr add-ons +- `ADDONS_TO_BUILD` has four rules for matching a provided space delimited list: + - to build all addons, just use `all` (default is *all*) + - an exact match of an `` that you want to build (e.g. `ADDONS_TO_BUILD="game.libretro"`) + - a regular expression `` is matched against (e.g. `ADDONS_TO_BUILD="pvr.*"`) to build all pvr add-ons + - a regular expression exclusion can be made using `-` (e.g. `ADDONS_TO_BUILD="pvr.* -pvr.dvb"`) to exclude pvr.dvblink and pvr.dvbviewer, but build all other pvr add-ons - `ADDONS_DEFINITION_DIR` points to the directory containing the definitions for the addons to be built - `ADDON_SRC_PREFIX` can be used to override the add-on repository location. It must point to the locally available parent directory of the add-on(s) to build. `` will be appended to this path automatically - `CMAKE_INSTALL_PREFIX` points to the directory where the built add-ons and their additional files (addon.xml, resources, ...) will be installed to (defaults to ``) @@ -44,4 +46,4 @@ Buildsystem will print a warning if you use any of the below-listed variables. F ## Building The buildsystem makes some assumptions about the environment which must be met by whoever uses it: -- Any dependencies of the add-ons must already be built and their include and library files must be present in the path pointed to by `` (in *include* and *lib* sub-directories) \ No newline at end of file +- Any dependencies of the add-ons must already be built and their include and library files must be present in the path pointed to by `` (in *include* and *lib* sub-directories) diff --git a/cmake/cpack/deb/packages/kodi.txt.in b/cmake/cpack/deb/packages/kodi.txt.in index 78df46a..6cce5fd 100644 --- a/cmake/cpack/deb/packages/kodi.txt.in +++ b/cmake/cpack/deb/packages/kodi.txt.in @@ -15,7 +15,7 @@ PACKAGE_ARCHITECTURE all PACKAGE_SECTION video PACKAGE_PRIORITY optional PACKAGE_SHLIBDEPS -PACKAGE_DEPENDS @APP_NAME_LC@-bin (>= @CPACK_DEBIAN_PACKAGE_VERSION@), @APP_NAME_LC@-bin (<< @CPACK_DEBIAN_PACKAGE_VERSION@.1~), curl, libcurl4 | libcurl3, mesa-utils, x11-utils, fonts-liberation | ttf-liberation, fonts-dejavu-core | ttf-dejavu-core, python3-pil, python3-simplejson, libass9 | libass5 | libass4, libgif5 | libgif7, libnfs8 | libnfs4 | libnfs1, libbluray1 | libbluray2, libshairplay0, libvorbisfile3, libaacs0, libcec4, libgnutls30 | libgnutls-deb0-28 | libgnutls28 | libgnutls26, libxslt1.1 +PACKAGE_DEPENDS @APP_NAME_LC@-bin (>= @CPACK_DEBIAN_PACKAGE_VERSION@), @APP_NAME_LC@-bin (<< @CPACK_DEBIAN_PACKAGE_VERSION@.1~), curl, libcurl4 | libcurl3, mesa-utils, x11-utils, fonts-liberation | ttf-liberation, fonts-dejavu-core | ttf-dejavu-core, python3-pil, python3-simplejson, libass9 | libass5 | libass4, libgif5 | libgif7, libnfs8 | libnfs4 | libnfs1, libbluray1 | libbluray2, libshairplay0, libvorbisfile3, libaacs0, libcec6 | libcec4, libgnutls30 | libgnutls-deb0-28 | libgnutls28 | libgnutls26, libxslt1.1 PACKAGE_RECOMMENDS libvdpau1, libva-intel-vaapi-driver, libva1 PACKAGE_SUGGESTS @APP_NAME_LC@-pvr-mythtv, @APP_NAME_LC@-pvr-vuplus, @APP_NAME_LC@-pvr-vdr-vnsi, @APP_NAME_LC@-pvr-njoy, @APP_NAME_LC@-pvr-nextpvr, @APP_NAME_LC@-pvr-mediaportal-tvserver, @APP_NAME_LC@-pvr-tvheadend-hts, @APP_NAME_LC@-pvr-dvbviewer, @APP_NAME_LC@-pvr-argustv, @APP_NAME_LC@-pvr-iptvsimple, @APP_NAME_LC@-audioencoder-vorbis, @APP_NAME_LC@-audioencoder-flac, @APP_NAME_LC@-audioencoder-lame PACKAGE_BREAKS xbmc (<< 2:14.0~git20141019), xbmc-data, xbmc-standalone diff --git a/cmake/installdata/common/addons.txt b/cmake/installdata/common/addons.txt index 13dbab3..897420f 100644 --- a/cmake/installdata/common/addons.txt +++ b/cmake/installdata/common/addons.txt @@ -39,6 +39,8 @@ addons/metadata.common.imdb.com/* addons/metadata.common.musicbrainz.org/* addons/metadata.common.theaudiodb.com/* addons/metadata.common.themoviedb.org/* +addons/metadata.generic.albums/* +addons/metadata.generic.artists/* addons/metadata.themoviedb.org/* addons/metadata.tvshows.themoviedb.org/* addons/kodi.vfs/* diff --git a/cmake/installdata/rbpi/lirc.txt b/cmake/installdata/rbpi/lirc.txt deleted file mode 120000 index e89ae50..0000000 --- a/cmake/installdata/rbpi/lirc.txt +++ /dev/null @@ -1 +0,0 @@ -../linux/lirc.txt \ No newline at end of file diff --git a/cmake/modules/FindClangTidy.cmake b/cmake/modules/FindClangTidy.cmake new file mode 100644 index 0000000..6ea614d --- /dev/null +++ b/cmake/modules/FindClangTidy.cmake @@ -0,0 +1,26 @@ +#.rst: +# FindClangTidy +# ------------- +# Finds clang-tidy and sets it up to run along with the compiler for C and CXX. + +find_program(CLANG_TIDY_EXECUTABLE clang-tidy) + +if(CLANG_TIDY_EXECUTABLE) + execute_process(COMMAND "${CLANG_TIDY_EXECUTABLE}" --version + OUTPUT_VARIABLE CLANG_TIDY_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX MATCH "[^\n]* version [^\n]*" CLANG_TIDY_VERSION "${CLANG_TIDY_VERSION}") + string(REGEX REPLACE ".* version (.*)" "\\1" CLANG_TIDY_VERSION "${CLANG_TIDY_VERSION}") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ClangTidy REQUIRED_VARS CLANG_TIDY_EXECUTABLE + VERSION_VAR CLANG_TIDY_VERSION) + +if(CLANGTIDY_FOUND) + # Supports Unix Makefiles and Ninja + set(CMAKE_C_CLANG_TIDY "${CLANG_TIDY_EXECUTABLE}" PARENT_SCOPE) + set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXECUTABLE}" PARENT_SCOPE) +endif() + +mark_as_advanced(CLANG_TIDY_EXECUTABLE) diff --git a/cmake/modules/FindCppcheck.cmake b/cmake/modules/FindCppcheck.cmake new file mode 100644 index 0000000..d3b6e84 --- /dev/null +++ b/cmake/modules/FindCppcheck.cmake @@ -0,0 +1,32 @@ +#.rst: +# FindCppcheck +# ------------ +# Finds cppcheck and sets it up to run along with the compiler for C and CXX. + +find_program(CPPCHECK_EXECUTABLE cppcheck) + +if(CPPCHECK_EXECUTABLE) + execute_process(COMMAND "${CPPCHECK_EXECUTABLE}" --version + OUTPUT_VARIABLE CPPCHECK_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX REPLACE "Cppcheck (.*)" "\\1" CPPCHECK_VERSION "${CPPCHECK_VERSION}") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Cppcheck REQUIRED_VARS CPPCHECK_EXECUTABLE + VERSION_VAR CPPCHECK_VERSION) + +if(CPPCHECK_FOUND) + # CMake < 3.16 treats Objective-C (OBJC) files as C files and Objective-C++ (OBJCXX) files as C++ files, + # but cppcheck doesn't support Objective-C and Objective-C++. + # CMake >= 3.16 added support for Objective-C and Objective-C++ language, + # but doesn't support OBJC and OBJCXX for _CLANG_TIDY. + file(WRITE "${CMAKE_BINARY_DIR}/cppcheck" "case \"$@\" in *.m|*.mm) exit 0; esac\nexec \"${CPPCHECK_EXECUTABLE}\" --quiet --relative-paths=\"${CMAKE_SOURCE_DIR}\" \"$@\"\n") + execute_process(COMMAND chmod +x "${CMAKE_BINARY_DIR}/cppcheck") + + # Supports Unix Makefiles and Ninja + set(CMAKE_C_CPPCHECK "${CMAKE_BINARY_DIR}/cppcheck" PARENT_SCOPE) + set(CMAKE_CXX_CPPCHECK "${CMAKE_BINARY_DIR}/cppcheck" PARENT_SCOPE) +endif() + +mark_as_advanced(CPPCHECK_EXECUTABLE) diff --git a/cmake/modules/FindEGL.cmake b/cmake/modules/FindEGL.cmake index 0b73eb8..b00fe08 100644 --- a/cmake/modules/FindEGL.cmake +++ b/cmake/modules/FindEGL.cmake @@ -14,18 +14,14 @@ # # EGL::EGL - The EGL library -if(CORE_PLATFORM_NAME_LC STREQUAL rbpi) - set(_brcmprefix brcm) -endif() - if(PKG_CONFIG_FOUND) - pkg_check_modules(PC_EGL ${_brcmprefix}egl QUIET) + pkg_check_modules(PC_EGL egl QUIET) endif() find_path(EGL_INCLUDE_DIR EGL/egl.h PATHS ${PC_EGL_INCLUDEDIR}) -find_library(EGL_LIBRARY NAMES ${_brcmprefix}EGL egl +find_library(EGL_LIBRARY NAMES EGL egl PATHS ${PC_EGL_LIBDIR}) set(EGL_VERSION ${PC_EGL_VERSION}) diff --git a/cmake/modules/FindIncludeWhatYouUse.cmake b/cmake/modules/FindIncludeWhatYouUse.cmake new file mode 100644 index 0000000..b22225a --- /dev/null +++ b/cmake/modules/FindIncludeWhatYouUse.cmake @@ -0,0 +1,26 @@ +#.rst: +# FindIncludeWhatYouUse +# --------------------- +# Finds include-what-you-use and sets it up to run along with the compiler for C and CXX. + +find_program(IWYU_EXECUTABLE NAMES include-what-you-use iwyu) + +if(IWYU_EXECUTABLE) + execute_process(COMMAND "${IWYU_EXECUTABLE}" --version + OUTPUT_VARIABLE IWYU_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX MATCH "[^\n]*include-what-you-use [^\n]*" IWYU_VERSION "${IWYU_VERSION}") + string(REGEX REPLACE "include-what-you-use ([^ \n\r\t]+).*" "\\1" IWYU_VERSION "${IWYU_VERSION}") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(IncludeWhatYouUse REQUIRED_VARS IWYU_EXECUTABLE + VERSION_VAR IWYU_VERSION) + +if(INCLUDEWHATYOUUSE_FOUND) + # Supports Unix Makefiles and Ninja + set(CMAKE_C_INCLUDE_WHAT_YOU_USE "${IWYU_EXECUTABLE}" PARENT_SCOPE) + set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${IWYU_EXECUTABLE}" PARENT_SCOPE) +endif() + +mark_as_advanced(IWYU_EXECUTABLE) diff --git a/cmake/modules/FindLibDRM.cmake b/cmake/modules/FindLibDRM.cmake index 0d680f2..866565d 100644 --- a/cmake/modules/FindLibDRM.cmake +++ b/cmake/modules/FindLibDRM.cmake @@ -15,7 +15,7 @@ # LibDRM::LibDRM - The LibDRM library if(PKG_CONFIG_FOUND) - pkg_check_modules(PC_LIBDRM libdrm>=2.4.82 QUIET) + pkg_check_modules(PC_LIBDRM libdrm>=2.4.95 QUIET) endif() find_path(LIBDRM_INCLUDE_DIR NAMES drm.h diff --git a/cmake/modules/FindLibDvd.cmake b/cmake/modules/FindLibDvd.cmake index 44e7e92..58a7aab 100644 --- a/cmake/modules/FindLibDvd.cmake +++ b/cmake/modules/FindLibDvd.cmake @@ -96,6 +96,16 @@ else() set(LIBDVD_ADDITIONAL_ARGS "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}" "-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}") endif() + set(MAKE_COMMAND $(MAKE)) + if(CMAKE_GENERATOR STREQUAL Ninja) + set(MAKE_COMMAND make) + include(ProcessorCount) + ProcessorCount(N) + if(NOT N EQUAL 0) + set(MAKE_COMMAND make -j${N}) + endif() + endif() + if(ENABLE_DVDCSS) if(NOT CORE_SYSTEM_NAME MATCHES windows) set(DVDCSS_LIBRARY ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/libdvd/lib/libdvdcss.a) @@ -115,6 +125,7 @@ else() "CC=${CMAKE_C_COMPILER}" "CFLAGS=${CMAKE_C_FLAGS} ${DVDREAD_CFLAGS}" "LDFLAGS=${CMAKE_LD_FLAGS}" + BUILD_COMMAND ${MAKE_COMMAND} BUILD_BYPRODUCTS ${DVDCSS_LIBRARY}) ExternalProject_Add_Step(dvdcss autoreconf DEPENDEES download update patch @@ -156,7 +167,8 @@ else() "CC=${CMAKE_C_COMPILER}" "CFLAGS=${CMAKE_C_FLAGS} ${DVDREAD_CFLAGS}" "LDFLAGS=${CMAKE_LD_FLAGS}" - BUILD_BYPRODUCTS ${DVDREAD_LIBRARY}) + BUILD_COMMAND ${MAKE_COMMAND} + BUILD_BYPRODUCTS ${DVDREAD_LIBRARY}) ExternalProject_Add_Step(dvdread autoreconf DEPENDEES download update patch DEPENDERS configure @@ -203,6 +215,7 @@ else() "DVDREAD_CFLAGS=${DVDREAD_CFLAGS}" "DVDREAD_LIBS=${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/libdvd/lib/libdvdread.la" "LIBS=${DVDNAV_LIBS}" + BUILD_COMMAND ${MAKE_COMMAND} BUILD_BYPRODUCTS ${DVDNAV_LIBRARY}) ExternalProject_Add_Step(dvdnav autoreconf DEPENDEES download update patch diff --git a/cmake/modules/FindMMAL.cmake b/cmake/modules/FindMMAL.cmake deleted file mode 100644 index 0b5f556..0000000 --- a/cmake/modules/FindMMAL.cmake +++ /dev/null @@ -1,55 +0,0 @@ -# - Try to find MMAL -# Once done this will define -# -# MMAL_FOUND - system has MMAL -# MMAL_INCLUDE_DIRS - the MMAL include directory -# MMAL_LIBRARIES - The MMAL libraries - -if(PKG_CONFIG_FOUND) - pkg_check_modules(PC_MMAL mmal QUIET) -endif() - - -find_path(MMAL_INCLUDE_DIR NAMES interface/mmal/mmal.h PATHS ${PC_MMAL_INCLUDEDIR}) -find_library(MMAL_LIBRARY NAMES mmal libmmal PATHS ${PC_MMAL_LIBDIR}) -find_library(MMALCORE_LIBRARY NAMES mmal_core libmmal_core PATHS ${PC_MMAL_LIBDIR}) -find_library(MMALUTIL_LIBRARY NAMES mmal_util libmmal_util PATHS ${PC_MMAL_LIBDIR}) -find_library(MMALCLIENT_LIBRARY NAMES mmal_vc_client libmmal_vc_client PATHS ${PC_MMAL_LIBDIR}) -find_library(MMALCOMPONENT_LIBRARY NAMES mmal_components libmmal_components PATHS ${PC_MMAL_LIBDIR}) -find_library(BCM_LIBRARY NAMES bcm_host libbcm_host PATHS ${PC_MMAL_LIBDIR}) -find_library(VCHIQ_LIBRARY NAMES vchiq_arm libvchiq_arm PATHS ${PC_MMAL_LIBDIR}) -find_library(VCHOSTIF_LIBRARY NAMES vchostif libvchostif PATHS ${PC_MMAL_LIBDIR}) -find_library(VCILCS_LIBRARY NAMES vcilcs libvcilcs PATHS ${PC_MMAL_LIBDIR}) -find_library(VCOS_LIBRARY NAMES vcos libvcos PATHS ${PC_MMAL_LIBDIR}) -find_library(VCSM_LIBRARY NAMES vcsm libvcsm PATHS ${PC_MMAL_LIBDIR}) -find_library(CONTAINER_LIBRARY NAMES containers libcontainers PATHS ${PC_MMAL_LIBDIR}) - - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(MMAL REQUIRED_VARS MMAL_INCLUDE_DIR - MMAL_LIBRARY MMALCORE_LIBRARY MMALUTIL_LIBRARY - MMALCLIENT_LIBRARY MMALCOMPONENT_LIBRARY BCM_LIBRARY - VCHIQ_LIBRARY VCOS_LIBRARY VCSM_LIBRARY VCHOSTIF_LIBRARY - VCILCS_LIBRARY CONTAINER_LIBRARY) - - -if(MMAL_FOUND) - set(MMAL_INCLUDE_DIRS ${MMAL_INCLUDE_DIR}) - set(MMAL_LIBRARIES ${MMAL_LIBRARY} ${MMALCORE_LIBRARY} ${MMALUTIL_LIBRARY} - ${MMALCLIENT_LIBRARY} ${MMALCOMPONENT_LIBRARY} - ${BCM_LIBRARY} ${VCHIQ_LIBRARY} ${VCOS_LIBRARY} ${VCSM_LIBRARY} - ${VCHOSTIF_LIBRARY} ${VCILCS_LIBRARY} ${CONTAINER_LIBRARY} - CACHE STRING "mmal libraries" FORCE) - list(APPEND MMAL_DEFINITIONS -DHAVE_MMAL=1 -DHAS_MMAL=1) - - if(NOT TARGET MMAL::MMAL) - add_library(MMAL::MMAL UNKNOWN IMPORTED) - set_target_properties(MMAL::MMAL PROPERTIES - IMPORTED_LOCATION "${MMAL_LIBRARIES}" - INTERFACE_INCLUDE_DIRECTORIES "${MMAL_INCLUDE_DIR}") - endif() -endif() - -mark_as_advanced(MMAL_INCLUDE_DIRS MMAL_LIBRARIES MMAL_DEFINITIONS - MMAL_LIBRARY MMALCORE_LIBRARY MMALUTIL_LIBRARY MMALCLIENT_LIBRARY MMALCOMPONENT_LIBRARY BCM_LIBRARY - VCHIQ_LIBRARY VCOS_LIBRARY VCSM_LIBRARY VCHOSTIF_LIBRARY VCILCS_LIBRARY CONTAINER_LIBRARY) diff --git a/cmake/modules/FindOpenGLES.cmake b/cmake/modules/FindOpenGLES.cmake index 43a1367..3dbaa44 100644 --- a/cmake/modules/FindOpenGLES.cmake +++ b/cmake/modules/FindOpenGLES.cmake @@ -10,18 +10,14 @@ # OPENGLES_LIBRARIES - the OpenGLES libraries # OPENGLES_DEFINITIONS - the OpenGLES definitions -if(CORE_PLATFORM_NAME_LC STREQUAL rbpi) - set(_brcmprefix brcm) -endif() - if(PKG_CONFIG_FOUND) - pkg_check_modules(PC_OPENGLES ${_brcmprefix}glesv2 QUIET) + pkg_check_modules(PC_OPENGLES glesv2 QUIET) endif() if(NOT CORE_SYSTEM_NAME STREQUAL darwin_embedded) find_path(OPENGLES_INCLUDE_DIR GLES2/gl2.h PATHS ${PC_OPENGLES_INCLUDEDIR}) - find_library(OPENGLES_gl_LIBRARY NAMES ${_brcmprefix}GLESv2 + find_library(OPENGLES_gl_LIBRARY NAMES GLESv2 PATHS ${PC_OPENGLES_LIBDIR}) else() find_library(OPENGLES_gl_LIBRARY NAMES OpenGLES diff --git a/cmake/modules/FindPlist.cmake b/cmake/modules/FindPlist.cmake index 2c86b74..8f9b2d6 100644 --- a/cmake/modules/FindPlist.cmake +++ b/cmake/modules/FindPlist.cmake @@ -15,7 +15,7 @@ # Plist::Plist - The Plist library if(PKG_CONFIG_FOUND) - pkg_check_modules(PC_PLIST libplist QUIET) + pkg_search_module(PC_PLIST libplist-2.0 libplist QUIET) endif() find_path(PLIST_INCLUDE_DIR plist/plist.h @@ -23,7 +23,7 @@ find_path(PLIST_INCLUDE_DIR plist/plist.h set(PLIST_VERSION ${PC_PLIST_VERSION}) -find_library(PLIST_LIBRARY NAMES plist libplist +find_library(PLIST_LIBRARY NAMES plist-2.0 plist libplist-2.0 libplist PATHS ${PC_PLIST_LIBDIR}) include(FindPackageHandleStandardArgs) diff --git a/cmake/platform/freebsd/rbpi.cmake b/cmake/platform/freebsd/rbpi.cmake deleted file mode 100644 index f095693..0000000 --- a/cmake/platform/freebsd/rbpi.cmake +++ /dev/null @@ -1 +0,0 @@ -include(cmake/platform/linux/rbpi.cmake) diff --git a/cmake/platform/linux/rbpi.cmake b/cmake/platform/linux/rbpi.cmake deleted file mode 100644 index 3dde57d..0000000 --- a/cmake/platform/linux/rbpi.cmake +++ /dev/null @@ -1,3 +0,0 @@ -set(PLATFORM_REQUIRED_DEPS OpenGLES EGL MMAL LibInput Xkbcommon) -set(APP_RENDER_SYSTEM gles) -list(APPEND PLATFORM_DEFINES -D_ARMEL -DTARGET_RASPBERRY_PI) diff --git a/cmake/platform/linux/wayland.cmake b/cmake/platform/linux/wayland.cmake index 97cff67..916b578 100644 --- a/cmake/platform/linux/wayland.cmake +++ b/cmake/platform/linux/wayland.cmake @@ -1,13 +1,13 @@ -set(PLATFORM_REQUIRED_DEPS EGL WaylandProtocols>=1.7 Waylandpp>=0.2.2 LibDRM Xkbcommon>=0.4.1) +set(PLATFORM_REQUIRED_DEPS WaylandProtocols>=1.7 Waylandpp>=0.2.2 LibDRM Xkbcommon>=0.4.1) set(PLATFORM_OPTIONAL_DEPS VAAPI) set(WAYLAND_RENDER_SYSTEM "" CACHE STRING "Render system to use with Wayland: \"gl\" or \"gles\"") if(WAYLAND_RENDER_SYSTEM STREQUAL "gl") - list(APPEND PLATFORM_REQUIRED_DEPS OpenGl) + list(APPEND PLATFORM_REQUIRED_DEPS OpenGl EGL) set(APP_RENDER_SYSTEM gl) elseif(WAYLAND_RENDER_SYSTEM STREQUAL "gles") - list(APPEND PLATFORM_REQUIRED_DEPS OpenGLES) + list(APPEND PLATFORM_REQUIRED_DEPS OpenGLES EGL) set(APP_RENDER_SYSTEM gles) else() message(SEND_ERROR "You need to decide whether you want to use GL- or GLES-based rendering in combination with the Wayland windowing system. Please set WAYLAND_RENDER_SYSTEM to either \"gl\" or \"gles\". For normal desktop systems, you will usually want to use \"gl\".") diff --git a/cmake/platform/windows/defines.txt b/cmake/platform/windows/defines.txt index 1a7609a..137a3d6 100644 --- a/cmake/platform/windows/defines.txt +++ b/cmake/platform/windows/defines.txt @@ -1 +1 @@ --DTARGET_WINDOWS -DTARGET_WINDOWS_DESKTOP -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS -D_WINSOCKAPI_ \ No newline at end of file +-DTARGET_WINDOWS -DTARGET_WINDOWS_DESKTOP -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS \ No newline at end of file diff --git a/cmake/platform/windowsstore/defines.txt b/cmake/platform/windowsstore/defines.txt index e962feb..09e1b08 100644 --- a/cmake/platform/windowsstore/defines.txt +++ b/cmake/platform/windowsstore/defines.txt @@ -1 +1 @@ --DTARGET_WINDOWS -DTARGET_WINDOWS_STORE -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS -D_WINSOCKAPI_ \ No newline at end of file +-DTARGET_WINDOWS -DTARGET_WINDOWS_STORE -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS \ No newline at end of file diff --git a/cmake/scripts/android/ArchSetup.cmake b/cmake/scripts/android/ArchSetup.cmake index 1e529de..888d042 100644 --- a/cmake/scripts/android/ArchSetup.cmake +++ b/cmake/scripts/android/ArchSetup.cmake @@ -39,6 +39,7 @@ endif() list(APPEND SYSTEM_DEFINES -DHAS_ZEROCONF) set(ENABLE_X11 OFF CACHE BOOL "" FORCE) +set(ENABLE_CLANGTIDY OFF CACHE BOOL "Enable clang-tidy support?" FORCE) set(ENABLE_OPTICAL OFF CACHE BOOL "" FORCE) set(ENABLE_MDNS OFF CACHE BOOL "" FORCE) diff --git a/cmake/scripts/common/ArchSetup.cmake b/cmake/scripts/common/ArchSetup.cmake index 2e1eb12..978a7fa 100644 --- a/cmake/scripts/common/ArchSetup.cmake +++ b/cmake/scripts/common/ArchSetup.cmake @@ -108,6 +108,21 @@ if(HAVE_INTTYPES_H) list(APPEND SYSTEM_DEFINES -DHAVE_INTTYPES_H=1) endif() +set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE") +check_symbol_exists("STATX_BTIME" "linux/stat.h" HAVE_STATX) +if(HAVE_STATX) + check_function_exists("statx" FOUND_STATX_FUNCTION) + if(FOUND_STATX_FUNCTION) + message(STATUS "statx is available") + list(APPEND ARCH_DEFINES "-DHAVE_STATX=1") + else() + message(STATUS "statx flags found but no linkable function : C library too old ?") + endif() +else() + message(STATUS "statx() not found") +endif() +set(CMAKE_REQUIRED_DEFINITIONS "") + find_package(SSE) foreach(_sse SSE SSE2 SSE3 SSSE3 SSE4_1 SSE4_2 AVX AVX2) if(${${_sse}_FOUND}) @@ -144,3 +159,5 @@ if(NOT MSVC) add_options(ALL_LANGUAGES DEBUG "-g" "-D_DEBUG") endif() +# set for compile info to help detect binary addons +set(APP_SHARED_LIBRARY_SUFFIX "${CMAKE_SHARED_LIBRARY_SUFFIX}") diff --git a/cmake/scripts/common/HandleDepends.cmake b/cmake/scripts/common/HandleDepends.cmake index 7cacd25..c737c6a 100644 --- a/cmake/scripts/common/HandleDepends.cmake +++ b/cmake/scripts/common/HandleDepends.cmake @@ -185,7 +185,7 @@ function(add_addon_depends addon searchpath) set(EXTERNALPROJECT_SETUP PREFIX ${BUILD_DIR}/${id} CMAKE_ARGS ${extraflags} ${BUILD_ARGS} PATCH_COMMAND ${PATCH_COMMAND} - "${INSTALL_COMMAND}") + ${INSTALL_COMMAND}) if(CMAKE_VERSION VERSION_GREATER 3.5.9) list(APPEND EXTERNALPROJECT_SETUP GIT_SHALLOW 1) @@ -201,7 +201,7 @@ function(add_addon_depends addon searchpath) externalproject_add(${id} GIT_REPOSITORY ${url} GIT_TAG ${revision} - "${EXTERNALPROJECT_SETUP}") + ${EXTERNALPROJECT_SETUP}) # For patchfiles to work, disable (users globally set) autocrlf=true if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_GREATER 3.7) @@ -249,12 +249,12 @@ function(add_addon_depends addon searchpath) "${URL_HASH_COMMAND}" DOWNLOAD_DIR ${DOWNLOAD_DIR} CONFIGURE_COMMAND ${CONFIGURE_COMMAND} - "${EXTERNALPROJECT_SETUP}") + ${EXTERNALPROJECT_SETUP}) endif() else() externalproject_add(${id} SOURCE_DIR ${dir} - "${EXTERNALPROJECT_SETUP}") + ${EXTERNALPROJECT_SETUP}) endif() if(deps) diff --git a/cmake/scripts/common/Macros.cmake b/cmake/scripts/common/Macros.cmake index f7327e3..d896651 100644 --- a/cmake/scripts/common/Macros.cmake +++ b/cmake/scripts/common/Macros.cmake @@ -626,6 +626,9 @@ endfunction() # APP_VERSION_TAG_LC - lowercased app version tag # APP_VERSION - the app version (${APP_VERSION_MAJOR}.${APP_VERSION_MINOR}-${APP_VERSION_TAG}) # APP_ADDON_API - the addon API version in the form of 16.9.702 +# ADDON_REPOS - official addon repositories and their origin path delimited by pipe +# - e.g. repository.xbmc.org|https://mirrors.kodi.tv - +# (multiple repo/path-sets are delimited by comma) # FILE_VERSION - file version in the form of 16,9,702,0 - Windows only # JSONRPC_VERSION - the json api version in the form of 8.3.0 # @@ -646,6 +649,7 @@ macro(core_find_versions) string(REGEX REPLACE "([^ ;]*) ([^;]*)" "\\1;\\2" version_list "${version_list};${json_version}") set(version_props ADDON_API + ADDON_REPOS APP_NAME APP_PACKAGE COMPANY_NAME @@ -676,12 +680,13 @@ macro(core_find_versions) string(TOLOWER ${APP_VERSION_TAG} APP_VERSION_TAG_LC) endif() string(REPLACE "." "," FILE_VERSION ${APP_ADDON_API}.0) + set(ADDON_REPOS ${APP_ADDON_REPOS}) set(JSONRPC_VERSION ${APP_JSONRPC_VERSION}) # Set defines used in addon.xml.in and read from versions.h to set add-on # version parts automatically # This part is nearly identical to "AddonHelpers.cmake", except location of versions.h - file(STRINGS ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h BIN_ADDON_PARTS) + file(STRINGS ${CORE_SOURCE_DIR}/xbmc/addons/kodi-dev-kit/include/kodi/versions.h BIN_ADDON_PARTS) foreach(loop_var ${BIN_ADDON_PARTS}) string(FIND "${loop_var}" "#define ADDON_" matchres) if("${matchres}" EQUAL 0) @@ -748,5 +753,5 @@ macro(find_addon_xml_in_files) endforeach() # Append also versions.h to depends - list(APPEND ADDON_XML_DEPENDS "${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h") + list(APPEND ADDON_XML_DEPENDS "${CORE_SOURCE_DIR}/xbmc/addons/kodi-dev-kit/include/kodi/versions.h") endmacro() diff --git a/cmake/scripts/common/ProjectMacros.cmake b/cmake/scripts/common/ProjectMacros.cmake index fba5252..67d65b2 100644 --- a/cmake/scripts/common/ProjectMacros.cmake +++ b/cmake/scripts/common/ProjectMacros.cmake @@ -77,12 +77,12 @@ endfunction() function(sca_add_tests) find_program(CLANGCHECK_COMMAND clang-check) - find_program(CPPCHECK_COMMAND cppcheck) + find_program(CPPCHECK_EXECUTABLE cppcheck) if(CLANGCHECK_COMMAND AND CMAKE_EXPORT_COMPILE_COMMANDS) configure_file(${PROJECT_SOURCE_DIR}/cmake/scripts/linux/clang-check-test.sh.in ${CORE_BUILD_DIR}/clang-check-test.sh) endif() - if(CPPCHECK_COMMAND) + if(CPPCHECK_EXECUTABLE) configure_file(${PROJECT_SOURCE_DIR}/cmake/scripts/linux/cppcheck-test.sh.in ${CORE_BUILD_DIR}/cppcheck-test.sh) set(CPPCHECK_INCLUDES) @@ -99,9 +99,9 @@ function(sca_add_tests) COMMAND ${CORE_BUILD_DIR}/clang-check-test.sh ${CLANGCHECK_COMMAND} ${src} CONFIGURATIONS analyze clang-check) endif() - if(CPPCHECK_COMMAND) + if(CPPCHECK_EXECUTABLE) add_test(NAME cppcheck+${name} - COMMAND ${CORE_BUILD_DIR}/cppcheck-test.sh ${CPPCHECK_COMMAND} ${src} ${CPPCHECK_INCLUDES} + COMMAND ${CORE_BUILD_DIR}/cppcheck-test.sh ${CPPCHECK_EXECUTABLE} ${src} ${CPPCHECK_INCLUDES} CONFIGURATIONS analyze cppcheck) endif() endif() diff --git a/cmake/scripts/darwin_embedded/ExtraTargets.cmake b/cmake/scripts/darwin_embedded/ExtraTargets.cmake index 2b9980a..01ab632 100644 --- a/cmake/scripts/darwin_embedded/ExtraTargets.cmake +++ b/cmake/scripts/darwin_embedded/ExtraTargets.cmake @@ -7,9 +7,11 @@ if(CORE_PLATFORM_NAME_LC STREQUAL tvos) set(ENTITLEMENTS_OUT_PATH "${CMAKE_BINARY_DIR}/CMakeFiles/${TOPSHELF_EXTENSION_NAME}.dir/TopShelf.entitlements") set(SOURCES - ${TOPSHELF_DIR}/ServiceProvider.m - ${TOPSHELF_DIR}/../tvosShared.m) + ${TOPSHELF_DIR}/../../ios-common/DarwinEmbedUtils.mm + ${TOPSHELF_DIR}/ServiceProvider.mm + ${TOPSHELF_DIR}/../tvosShared.mm) set(HEADERS + ${TOPSHELF_DIR}/../../ios-common/DarwinEmbedUtils.h ${TOPSHELF_DIR}/ServiceProvider.h ${TOPSHELF_DIR}/../tvosShared.h) add_executable(${TOPSHELF_EXTENSION_NAME} MACOSX_BUNDLE ${SOURCES} ${HEADERS}) @@ -21,5 +23,10 @@ if(CORE_PLATFORM_NAME_LC STREQUAL tvos) XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${ENTITLEMENTS_OUT_PATH}) target_link_libraries(${TOPSHELF_EXTENSION_NAME} "-framework TVServices" "-framework Foundation") + add_custom_command(TARGET ${TOPSHELF_EXTENSION_NAME} POST_BUILD + COMMAND "NATIVEPREFIX=${NATIVEPREFIX}" + ${CMAKE_SOURCE_DIR}/tools/darwin/Support/Codesign-topshelf.command + ) + add_dependencies(${APP_NAME_LC} ${TOPSHELF_EXTENSION_NAME}) endif() diff --git a/cmake/scripts/linux/ArchSetup.cmake b/cmake/scripts/linux/ArchSetup.cmake index 04fc6e3..b68efe3 100644 --- a/cmake/scripts/linux/ArchSetup.cmake +++ b/cmake/scripts/linux/ArchSetup.cmake @@ -37,16 +37,6 @@ else() endif() endif() -# temp until further cleanup is done -# add Raspberry Pi 2 and 3 specific flags -if(CORE_PLATFORM_NAME_LC STREQUAL rbpi) - if(CPU MATCHES "cortex-a7") - set(NEON_FLAGS "-fPIC -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 -mvectorize-with-neon-quad") - elseif(CPU MATCHES "cortex-a53") - set(NEON_FLAGS "-fPIC -mcpu=cortex-a53 -mfloat-abi=hard -mfpu=neon-fp-armv8 -mvectorize-with-neon-quad") - endif() -endif() - if((CMAKE_BUILD_TYPE STREQUAL Release OR CMAKE_BUILD_TYPE STREQUAL MinSizeRel) AND CMAKE_COMPILER_IS_GNUCXX) # Make sure we strip binaries in Release build diff --git a/cmake/scripts/linux/Install.cmake b/cmake/scripts/linux/Install.cmake index 36c0299..acfd3ff 100644 --- a/cmake/scripts/linux/Install.cmake +++ b/cmake/scripts/linux/Install.cmake @@ -199,7 +199,7 @@ if(ENABLE_EVENTCLIENTS) COMPONENT kodi-eventclients-common) # Install kodi-eventclients-common python files - file(WRITE ${CMAKE_BINARY_DIR}/packages/deb/defs.py ICON_PATH="usr/share/pixmaps/${APP_NAME_LC}/") + file(WRITE ${CMAKE_BINARY_DIR}/packages/deb/defs.py ICON_PATH="/usr/share/pixmaps/${APP_NAME_LC}/") install(PROGRAMS ${CMAKE_BINARY_DIR}/packages/deb/defs.py ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/python/__init__.py ${CMAKE_SOURCE_DIR}/tools/EventClients/Clients/PS3BDRemote/ps3_remote.py diff --git a/cmake/scripts/osx/Install.cmake b/cmake/scripts/osx/Install.cmake index aca31b4..629bc09 100644 --- a/cmake/scripts/osx/Install.cmake +++ b/cmake/scripts/osx/Install.cmake @@ -30,12 +30,29 @@ add_dependencies(bundle ${APP_NAME_LC}) configure_file(${CMAKE_SOURCE_DIR}/tools/darwin/packaging/osx/mkdmg-osx.sh.in ${CMAKE_BINARY_DIR}/tools/darwin/packaging/osx/mkdmg-osx.sh @ONLY) +string(TOLOWER ${CORE_BUILD_CONFIG} CORE_BUILD_CONFIG_LOWERCASED) +if(${CORE_BUILD_CONFIG_LOWERCASED} STREQUAL "release") + set(ALLOW_DEBUGGER "false") +else() + set(ALLOW_DEBUGGER "true") +endif() +configure_file(${CMAKE_SOURCE_DIR}/tools/darwin/packaging/osx/Kodi.entitlements.in + ${CMAKE_BINARY_DIR}/tools/darwin/packaging/osx/Kodi.entitlements @ONLY) + add_custom_target(dmg COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/osx/ ${CMAKE_BINARY_DIR}/tools/darwin/packaging/osx/ COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/osx/ ${CMAKE_BINARY_DIR}/tools/darwin/packaging/media/osx/ - COMMAND ./mkdmg-osx.sh ${CORE_BUILD_CONFIG} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/tools/darwin/Support/Codesign.command + ${CMAKE_BINARY_DIR}/tools/darwin/packaging/osx/Codesign.command + COMMAND "CODESIGNING_FOLDER_PATH=${PACKAGE_OUTPUT_DIR}/${APP_NAME}.app" + "DEV_ACCOUNT=${DEV_ACCOUNT}" + "DEV_ACCOUNT_PASSWORD=${DEV_ACCOUNT_PASSWORD}" + "DEV_TEAM=${DEV_TEAM}" + "EXPANDED_CODE_SIGN_IDENTITY_NAME=${CODE_SIGN_IDENTITY}" + "PLATFORM_NAME=${PLATFORM}" + ./mkdmg-osx.sh ${CORE_BUILD_CONFIG_LOWERCASED} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tools/darwin/packaging/osx) set_target_properties(dmg PROPERTIES FOLDER "Build Utilities") add_dependencies(dmg bundle) diff --git a/cmake/treedata/common/rbpi/rbpi.txt b/cmake/treedata/common/rbpi/rbpi.txt deleted file mode 100644 index dc268e7..0000000 --- a/cmake/treedata/common/rbpi/rbpi.txt +++ /dev/null @@ -1,2 +0,0 @@ -xbmc/cores/omxplayer cores/omxplayer -xbmc/windowing/rpi windowing/rpi diff --git a/cmake/treedata/common/subdirs.txt b/cmake/treedata/common/subdirs.txt index 8131113..1988d5b 100644 --- a/cmake/treedata/common/subdirs.txt +++ b/cmake/treedata/common/subdirs.txt @@ -2,21 +2,28 @@ xbmc xbmc xbmc/addons addons xbmc/addons/addoninfo addons_addoninfo xbmc/addons/binary-addons addons_binary-addons +xbmc/addons/gui addons_gui xbmc/addons/interfaces addons_interfaces xbmc/addons/interfaces/gui addons_interfaces_gui xbmc/addons/interfaces/gui/controls addons_interfaces_gui_controls xbmc/addons/interfaces/gui/dialogs addons_interfaces_gui_dialogs -xbmc/addons/kodi-addon-dev-kit/include/kodi addons_kodi-addon-dev-kit_include_kodi -xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance addons_kodi-addon-dev-kit_include_kodi_addon-instance -xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr addons_kodi-addon-dev-kit_include_kodi_addon-instance_pvr -xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api addons_kodi-addon-dev-kit_include_kodi_c-api -xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance addons_kodi-addon-dev-kit_include_kodi_c-api_addon-instance -xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr addons_kodi-addon-dev-kit_include_kodi_c-api_addon-instance_pvr -xbmc/addons/kodi-addon-dev-kit/include/kodi/gui addons_kodi-addon-dev-kit_include_kodi_gui -xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls addons_kodi-addon-dev-kit_include_kodi_gui_controls -xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs addons_kodi-addon-dev-kit_include_kodi_gui_dialogs -xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl addons_kodi-addon-dev-kit_include_kodi_gui_gl -xbmc/addons/kodi-addon-dev-kit/include/kodi/tools addons_kodi-addon-dev-kit_include_kodi_tools +xbmc/addons/kodi-dev-kit/include/kodi addons_kodi-dev-kit_include_kodi +xbmc/addons/kodi-dev-kit/include/kodi/addon-instance addons_kodi-dev-kit_include_kodi_addon-instance +xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/peripheral addons_kodi-dev-kit_include_kodi_addon-instance_peripheral +xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr addons_kodi-dev-kit_include_kodi_addon-instance_pvr +xbmc/addons/kodi-dev-kit/include/kodi/c-api addons_kodi-dev-kit_include_kodi_c-api +xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance addons_kodi-dev-kit_include_kodi_c-api_addon-instance +xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr addons_kodi-dev-kit_include_kodi_c-api_addon-instance_pvr +xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui addons_kodi-dev-kit_include_kodi_c-api_gui +xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls addons_kodi-dev-kit_include_kodi_c-api_gui_controls +xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs addons_kodi-dev-kit_include_kodi_c-api_gui_dialogs +xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input addons_kodi-dev-kit_include_kodi_c-api_gui_input +xbmc/addons/kodi-dev-kit/include/kodi/gui addons_kodi-dev-kit_include_kodi_gui +xbmc/addons/kodi-dev-kit/include/kodi/gui/controls addons_kodi-dev-kit_include_kodi_gui_controls +xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs addons_kodi-dev-kit_include_kodi_gui_dialogs +xbmc/addons/kodi-dev-kit/include/kodi/gui/gl addons_kodi-dev-kit_include_kodi_gui_gl +xbmc/addons/kodi-dev-kit/include/kodi/gui/input addons_kodi-dev-kit_include_kodi_gui_input +xbmc/addons/kodi-dev-kit/include/kodi/tools addons_kodi-dev-kit_include_kodi_tools xbmc/addons/settings addons_settings xbmc/commons commons xbmc/dbwrappers dbwrappers @@ -26,6 +33,7 @@ xbmc/guilib guilib xbmc/guilib/guiinfo guilib_guiinfo xbmc/input input xbmc/input/actions input/actions +xbmc/input/button input/button xbmc/input/joysticks input/joysticks xbmc/input/joysticks/dialogs input/joysticks/dialogs xbmc/input/joysticks/generic input/joysticks/generic diff --git a/cmake/treedata/freebsd/subdirs.txt b/cmake/treedata/freebsd/subdirs.txt index 79e3462..a7433a5 100644 --- a/cmake/treedata/freebsd/subdirs.txt +++ b/cmake/treedata/freebsd/subdirs.txt @@ -1,5 +1,3 @@ -xbmc/cores/RetroPlayer/process/rbpi cores/RetroPlayer/process/rbpi -xbmc/cores/VideoPlayer/Process/rbpi cores/VideoPlayer/Process/rbpi xbmc/input/touch input/touch xbmc/input/touch/generic input/touch/generic xbmc/platform/freebsd platform/freebsd diff --git a/cmake/treedata/linux/subdirs.txt b/cmake/treedata/linux/subdirs.txt index 51a7cbd..35c8d88 100644 --- a/cmake/treedata/linux/subdirs.txt +++ b/cmake/treedata/linux/subdirs.txt @@ -1,5 +1,3 @@ -xbmc/cores/RetroPlayer/process/rbpi cores/RetroPlayer/process/rbpi -xbmc/cores/VideoPlayer/Process/rbpi cores/VideoPlayer/Process/rbpi xbmc/input/touch input/touch xbmc/input/touch/generic input/touch/generic xbmc/platform/linux platform/linux diff --git a/version.txt b/version.txt index 80f3277..260b336 100644 --- a/version.txt +++ b/version.txt @@ -1,12 +1,13 @@ APP_NAME Kodi COMPANY_NAME XBMC Foundation -COPYRIGHT_YEARS 2005-2018 +COPYRIGHT_YEARS 2005-2020 WEBSITE http://kodi.tv VERSION_MAJOR 19 VERSION_MINOR 0 -VERSION_TAG ALPHA1 -VERSION_CODE 18.9.701 -ADDON_API 18.9.701 +VERSION_TAG ALPHA2 +VERSION_CODE 18.9.702 +ADDON_API 18.9.702 +ADDON_REPOS repository.xbmc.org|https://mirrors.kodi.tv APP_PACKAGE org.xbmc.kodi PACKAGE_IDENTITY XBMCFoundation.Kodi PACKAGE_PUBLISHER C62BD90A-CDD8-477F-96C3-B25992247B97 diff --git a/xbmc/addons/AddonBindings.cmake b/xbmc/addons/AddonBindings.cmake index 7fb5aba..11cf190 100644 --- a/xbmc/addons/AddonBindings.cmake +++ b/xbmc/addons/AddonBindings.cmake @@ -1,15 +1,12 @@ # List contains only add-on related headers not present in -# ./addons/kodi-addon-dev-kit/include/kodi +# ./addons/kodi-dev-kit/include/kodi # # Keep this in alphabetical order set(CORE_ADDON_BINDINGS_FILES - ${CORE_SOURCE_DIR}/xbmc/cores/AudioEngine/Utils/AEChannelData.h - ${CORE_SOURCE_DIR}/xbmc/input/actions/ActionIDs.h - ${CORE_SOURCE_DIR}/xbmc/input/XBMC_vkeys.h ) set(CORE_ADDON_BINDINGS_DIRS - ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/ + ${CORE_SOURCE_DIR}/xbmc/addons/kodi-dev-kit/include/kodi/ ${CORE_SOURCE_DIR}/xbmc/cores/VideoPlayer/Interface/Addon ) diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h deleted file mode 100644 index b0fddda..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h +++ /dev/null @@ -1,1288 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "c-api/addon_base.h" -#include "versions.h" - -#include /* assert */ -#include -#include -#include -#include -#include /* va_list, va_start, va_arg, va_end */ -#include -#include -#include - -namespace kodi -{ - -namespace gui -{ -struct IRenderHelper; -} // namespace gui - -//============================================================================== -/// @ingroup cpp_kodi_addon_addonbase_Defs -/// @defgroup cpp_kodi_addon_addonbase_Defs_CSettingValue class CSettingValue -/// @brief Inside addon main instance used helper class to give settings value. -/// -/// This is used on @ref addon::CAddonBase::SetSetting() to inform addon about -/// settings change by used. This becomes then used to give the related value -/// name. -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_addonbase_Defs_CSettingValue_Help -/// -/// ---------------------------------------------------------------------------- -/// -/// **Here is a code example how this is used:** -/// -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// enum myEnumValue -/// { -/// valueA, -/// valueB, -/// valueC -/// }; -/// -/// std::string m_myStringValue; -/// int m_myIntegerValue; -/// bool m_myBooleanValue; -/// float m_myFloatingPointValue; -/// myEnumValue m_myEnumValue; -/// -/// -/// ADDON_STATUS CMyAddon::SetSetting(const std::string& settingName, const kodi::CSettingValue& settingValue) -/// { -/// if (settingName == "my_string_value") -/// m_myStringValue = settingValue.GetString(); -/// else if (settingName == "my_integer_value") -/// m_myIntegerValue = settingValue.GetInt(); -/// else if (settingName == "my_boolean_value") -/// m_myBooleanValue = settingValue.GetBoolean(); -/// else if (settingName == "my_float_value") -/// m_myFloatingPointValue = settingValue.GetFloat(); -/// else if (settingName == "my_enum_value") -/// m_myEnumValue = settingValue.GetEnum(); -/// } -/// ~~~~~~~~~~~~~ -/// -/// @note The asked type should match the type used on settings.xml. -/// -///@{ -class ATTRIBUTE_HIDDEN CSettingValue -{ -public: - explicit CSettingValue(const void* settingValue) : m_settingValue(settingValue) {} - - bool empty() const { return (m_settingValue == nullptr) ? true : false; } - - /// @defgroup cpp_kodi_addon_addonbase_Defs_CSettingValue_Help Value Help - /// @ingroup cpp_kodi_addon_addonbase_Defs_CSettingValue - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_addonbase_Defs_CSettingValue : - /// | Name | Type | Get call - /// |------|------|---------- - /// | **Settings value as string** | `std::string` | @ref CSettingValue::GetString "GetString" - /// | **Settings value as integer** | `int` | @ref CSettingValue::GetInt "GetInt" - /// | **Settings value as unsigned integer** | `unsigned int` | @ref CSettingValue::GetUInt "GetUInt" - /// | **Settings value as boolean** | `bool` | @ref CSettingValue::GetBoolean "GetBoolean" - /// | **Settings value as floating point** | `float` | @ref CSettingValue::GetFloat "GetFloat" - /// | **Settings value as enum** | `enum` | @ref CSettingValue::GetEnum "GetEnum" - - /// @addtogroup cpp_kodi_addon_addonbase_Defs_CSettingValue - ///@{ - - /// @brief To get settings value as string. - std::string GetString() const { return (const char*)m_settingValue; } - - /// @brief To get settings value as integer. - int GetInt() const { return *(const int*)m_settingValue; } - - /// @brief To get settings value as unsigned integer. - unsigned int GetUInt() const { return *(const unsigned int*)m_settingValue; } - - /// @brief To get settings value as boolean. - bool GetBoolean() const { return *(const bool*)m_settingValue; } - - /// @brief To get settings value as floating point. - float GetFloat() const { return *(const float*)m_settingValue; } - - /// @brief To get settings value as enum. - /// @note Inside settings.xml them stored as integer. - template - enumType GetEnum() const - { - return static_cast(*(const int*)m_settingValue); - } - - ///@} - -private: - const void* m_settingValue; -}; -///@} -//------------------------------------------------------------------------------ - -namespace addon -{ - -//============================================================================== -/* - * Internal class to control various instance types with general parts defined - * here. - * - * Mainly is this currently used to identify requested instance types. - * - * @note This class is not need to know during add-on development thats why - * commented with "*". - */ -class ATTRIBUTE_HIDDEN IAddonInstance -{ -public: - explicit IAddonInstance(ADDON_TYPE type, const std::string& version) - : m_type(type), m_kodiVersion(version) - { - } - virtual ~IAddonInstance() = default; - - virtual ADDON_STATUS CreateInstance(int instanceType, - const std::string& instanceID, - KODI_HANDLE instance, - const std::string& version, - KODI_HANDLE& addonInstance) - { - return ADDON_STATUS_NOT_IMPLEMENTED; - } - - const ADDON_TYPE m_type; - const std::string m_kodiVersion; - std::string m_id; -}; - -/* - * Internally used helper class to manage processing of a "C" structure in "CPP" - * class. - * - * At constant, the "C" structure is copied, otherwise the given pointer is - * superseded and is changeable. - * - * ----------------------------------------------------------------------------- - * - * Example: - * - * ~~~~~~~~~~~~~{.cpp} - * extern "C" typedef struct C_SAMPLE_DATA - * { - * unsigned int iUniqueId; - * } C_SAMPLE_DATA; - * - * class CPPSampleData : public CStructHdl - * { - * public: - * CPPSampleData() = default; - * CPPSampleData(const CPPSampleData& sample) : CStructHdl(sample) { } - * CPPSampleData(const C_SAMPLE_DATA* sample) : CStructHdl(sample) { } - * CPPSampleData(C_SAMPLE_DATA* sample) : CStructHdl(sample) { } - * - * void SetUniqueId(unsigned int uniqueId) { m_cStructure->iUniqueId = uniqueId; } - * unsigned int GetUniqueId() const { return m_cStructure->iUniqueId; } - * }; - * - * ~~~~~~~~~~~~~ - * - * It also works with the following example: - * - * ~~~~~~~~~~~~~{.cpp} - * CPPSampleData test; - * // Some work - * C_SAMPLE_DATA* data = test; - * // Give "data" to Kodi - * ~~~~~~~~~~~~~ - */ -template -class CStructHdl -{ -public: - CStructHdl() : m_cStructure(new C_STRUCT()), m_owner(true) {} - - CStructHdl(const CPP_CLASS& cppClass) - : m_cStructure(new C_STRUCT(*cppClass.m_cStructure)), m_owner(true) - { - } - - CStructHdl(const C_STRUCT* cStructure) : m_cStructure(new C_STRUCT(*cStructure)), m_owner(true) {} - - CStructHdl(C_STRUCT* cStructure) : m_cStructure(cStructure) { assert(cStructure); } - - const CStructHdl& operator=(const CStructHdl& right) - { - assert(&right.m_cStructure); - if (m_cStructure && !m_owner) - { - memcpy(m_cStructure, right.m_cStructure, sizeof(C_STRUCT)); - } - else - { - if (m_owner) - delete m_cStructure; - m_owner = true; - m_cStructure = new C_STRUCT(*right.m_cStructure); - } - return *this; - } - - const CStructHdl& operator=(const C_STRUCT& right) - { - assert(&right); - if (m_cStructure && !m_owner) - { - memcpy(m_cStructure, &right, sizeof(C_STRUCT)); - } - else - { - if (m_owner) - delete m_cStructure; - m_owner = true; - m_cStructure = new C_STRUCT(*right); - } - return *this; - } - - virtual ~CStructHdl() - { - if (m_owner) - delete m_cStructure; - } - - operator C_STRUCT*() { return m_cStructure; } - operator const C_STRUCT*() const { return m_cStructure; } - - const C_STRUCT* GetCStructure() const { return m_cStructure; } - -protected: - C_STRUCT* m_cStructure = nullptr; - -private: - bool m_owner = false; -}; - -/// Add-on main instance class. -class ATTRIBUTE_HIDDEN CAddonBase -{ -public: - CAddonBase() - { - m_interface->toAddon->destroy = ADDONBASE_Destroy; - m_interface->toAddon->get_status = ADDONBASE_GetStatus; - m_interface->toAddon->create_instance = ADDONBASE_CreateInstance; - m_interface->toAddon->destroy_instance = ADDONBASE_DestroyInstance; - m_interface->toAddon->set_setting = ADDONBASE_SetSetting; - } - - virtual ~CAddonBase() = default; - - virtual ADDON_STATUS Create() { return ADDON_STATUS_OK; } - - virtual ADDON_STATUS GetStatus() { return ADDON_STATUS_OK; } - - //============================================================================ - /// @ingroup cpp_kodi_addon_addonbase - /// @brief To inform addon about changed settings values. - /// - /// This becomes called for every entry defined inside his settings.xml and - /// as **last** call the one where last in xml (to identify end of calls). - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_addonbase_Defs_CSettingValue_Help - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Here is a code example how this is used:** - /// - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// enum myEnumValue - /// { - /// valueA, - /// valueB, - /// valueC - /// }; - /// - /// std::string m_myStringValue; - /// int m_myIntegerValue; - /// bool m_myBooleanValue; - /// float m_myFloatingPointValue; - /// myEnumValue m_myEnumValue; - /// - /// - /// ADDON_STATUS CMyAddon::SetSetting(const std::string& settingName, const kodi::CSettingValue& settingValue) - /// { - /// if (settingName == "my_string_value") - /// m_myStringValue = settingValue.GetString(); - /// else if (settingName == "my_integer_value") - /// m_myIntegerValue = settingValue.GetInt(); - /// else if (settingName == "my_boolean_value") - /// m_myBooleanValue = settingValue.GetBoolean(); - /// else if (settingName == "my_float_value") - /// m_myFloatingPointValue = settingValue.GetFloat(); - /// else if (settingName == "my_enum_value") - /// m_myEnumValue = settingValue.GetEnum(); - /// } - /// ~~~~~~~~~~~~~ - /// - /// @note The asked type should match the type used on settings.xml. - /// - virtual ADDON_STATUS SetSetting(const std::string& settingName, - const kodi::CSettingValue& settingValue) - { - return ADDON_STATUS_UNKNOWN; - } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_addon_addonbase - /// @brief Instance created - /// - /// @param[in] instanceType The requested type of required instance, see \ref ADDON_TYPE. - /// @param[in] instanceID An individual identification key string given by Kodi. - /// @param[in] instance The instance handler used by Kodi must be passed to - /// the classes created here. See in the example. - /// @param[in] version The from Kodi used version of instance. This can be - /// used to allow compatibility to older versions of - /// them. Further is this given to the parent instance - /// that it can handle differences. - /// @param[out] addonInstance The pointer to instance class created in addon. - /// Needed to be able to identify them on calls. - /// @return \ref ADDON_STATUS_OK if correct, for possible errors - /// see \ref ADDON_STATUS - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Here is a code example how this is used:** - /// - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// ... - /// - /// /* If you use only one instance in your add-on, can be instanceType and - /// * instanceID ignored */ - /// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, - /// const std::string& instanceID, - /// KODI_HANDLE instance, - /// const std::string& version, - /// KODI_HANDLE& addonInstance) - /// { - /// if (instanceType == ADDON_INSTANCE_SCREENSAVER) - /// { - /// kodi::Log(ADDON_LOG_NOTICE, "Creating my Screensaver"); - /// addonInstance = new CMyScreensaver(instance); - /// return ADDON_STATUS_OK; - /// } - /// else if (instanceType == ADDON_INSTANCE_VISUALIZATION) - /// { - /// kodi::Log(ADDON_LOG_NOTICE, "Creating my Visualization"); - /// addonInstance = new CMyVisualization(instance); - /// return ADDON_STATUS_OK; - /// } - /// else if (...) - /// { - /// ... - /// } - /// return ADDON_STATUS_UNKNOWN; - /// } - /// - /// ... - /// - /// ~~~~~~~~~~~~~ - /// - virtual ADDON_STATUS CreateInstance(int instanceType, - const std::string& instanceID, - KODI_HANDLE instance, - const std::string& version, - KODI_HANDLE& addonInstance) - { - return ADDON_STATUS_NOT_IMPLEMENTED; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_addon_addonbase - /// @brief Instance destroy - /// - /// This function is optional and intended to notify addon that the instance - /// is terminating. - /// - /// @param[in] instanceType The requested type of required instance, see \ref ADDON_TYPE. - /// @param[in] instanceID An individual identification key string given by Kodi. - /// @param[in] addonInstance The pointer to instance class created in addon. - /// - /// @warning This call is only used to inform that the associated instance - /// is terminated. The deletion is carried out in the background. - /// - virtual void DestroyInstance(int instanceType, - const std::string& instanceID, - KODI_HANDLE addonInstance) - { - } - //-------------------------------------------------------------------------- - - /* Background helper for GUI render systems, e.g. Screensaver or Visualization */ - std::shared_ptr m_renderHelper; - - /* Global variables of class */ - static AddonGlobalInterface* - m_interface; // Interface function table to hold addresses on add-on and from kodi - - /*private:*/ /* Needed public as long the old call functions becomes used! */ - static inline void ADDONBASE_Destroy() - { - delete static_cast(m_interface->addonBase); - m_interface->addonBase = nullptr; - } - - static inline ADDON_STATUS ADDONBASE_GetStatus() - { - return static_cast(m_interface->addonBase)->GetStatus(); - } - - static inline ADDON_STATUS ADDONBASE_SetSetting(const char* settingName, const void* settingValue) - { - return static_cast(m_interface->addonBase) - ->SetSetting(settingName, CSettingValue(settingValue)); - } - -private: - static inline ADDON_STATUS ADDONBASE_CreateInstance(int instanceType, - const char* instanceID, - KODI_HANDLE instance, - const char* version, - KODI_HANDLE* addonInstance, - KODI_HANDLE parent) - { - CAddonBase* base = static_cast(m_interface->addonBase); - - ADDON_STATUS status = ADDON_STATUS_NOT_IMPLEMENTED; - - /* Check about single instance usage: - * 1. The kodi side instance pointer must be equal to first one - * 2. The addon side instance pointer must be set - * 3. And the requested type must be equal with used add-on class - */ - if (m_interface->firstKodiInstance == instance && m_interface->globalSingleInstance && - static_cast(m_interface->globalSingleInstance)->m_type == instanceType) - { - /* The handling here is intended for the case of the add-on only one - * instance and this is integrated in the add-on base class. - */ - *addonInstance = m_interface->globalSingleInstance; - status = ADDON_STATUS_OK; - } - else - { - /* Here it should use the CreateInstance instance function to allow - * creation of several on one addon. - */ - - /* Check first a parent is defined about (e.g. Codec within inputstream) */ - if (parent != nullptr) - status = static_cast(parent)->CreateInstance( - instanceType, instanceID, instance, version, *addonInstance); - - /* if no parent call the main instance creation function to get it */ - if (status == ADDON_STATUS_NOT_IMPLEMENTED) - { - status = base->CreateInstance(instanceType, instanceID, instance, version, *addonInstance); - } - } - - if (*addonInstance == nullptr) - { - if (status == ADDON_STATUS_OK) - { - m_interface->toKodi->addon_log_msg(m_interface->toKodi->kodiBase, ADDON_LOG_FATAL, - "kodi::addon::CAddonBase CreateInstance returned an " - "empty instance pointer, but reported OK!"); - return ADDON_STATUS_PERMANENT_FAILURE; - } - else - { - return status; - } - } - - if (static_cast(*addonInstance)->m_type != instanceType) - { - m_interface->toKodi->addon_log_msg( - m_interface->toKodi->kodiBase, ADDON_LOG_FATAL, - "kodi::addon::CAddonBase CreateInstance difference between given and returned"); - delete static_cast(*addonInstance); - *addonInstance = nullptr; - return ADDON_STATUS_PERMANENT_FAILURE; - } - - // Store the used ID inside instance, to have on destroy calls by addon to identify - static_cast(*addonInstance)->m_id = instanceID; - - return status; - } - - static inline void ADDONBASE_DestroyInstance(int instanceType, KODI_HANDLE instance) - { - CAddonBase* base = static_cast(m_interface->addonBase); - - if (m_interface->globalSingleInstance == nullptr && instance != base) - { - base->DestroyInstance(instanceType, static_cast(instance)->m_id, instance); - delete static_cast(instance); - } - } -}; - -} /* namespace addon */ - -//============================================================================== -/// @ingroup cpp_kodi_addon -/// @brief To get used version inside Kodi itself about asked type. -/// -/// This thought to allow a addon a handling of newer addon versions within -/// older Kodi until the type min version not changed. -/// -/// @param[in] type The wanted type of @ref ADDON_TYPE to ask -/// @return The version string about type in MAJOR.MINOR.PATCH style. -/// -inline std::string ATTRIBUTE_HIDDEN GetKodiTypeVersion(int type) -{ - using namespace kodi::addon; - - char* str = CAddonBase::m_interface->toKodi->get_type_version( - CAddonBase::m_interface->toKodi->kodiBase, type); - std::string ret = str; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, str); - return ret; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// -inline std::string ATTRIBUTE_HIDDEN GetAddonPath(const std::string& append = "") -{ - using namespace kodi::addon; - - char* str = - CAddonBase::m_interface->toKodi->get_addon_path(CAddonBase::m_interface->toKodi->kodiBase); - std::string ret = str; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, str); - if (!append.empty()) - { - if (append.at(0) != '\\' && append.at(0) != '/') -#ifdef TARGET_WINDOWS - ret.append("\\"); -#else - ret.append("/"); -#endif - ret.append(append); - } - return ret; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// -inline std::string ATTRIBUTE_HIDDEN GetBaseUserPath(const std::string& append = "") -{ - using namespace kodi::addon; - - char* str = CAddonBase::m_interface->toKodi->get_base_user_path( - CAddonBase::m_interface->toKodi->kodiBase); - std::string ret = str; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, str); - if (!append.empty()) - { - if (append.at(0) != '\\' && append.at(0) != '/') -#ifdef TARGET_WINDOWS - ret.append("\\"); -#else - ret.append("/"); -#endif - ret.append(append); - } - return ret; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// -inline std::string ATTRIBUTE_HIDDEN GetLibPath() -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->libBasePath; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi -/// @brief Add a message to Kodi's log. -/// -/// @param[in] loglevel The log level of the message. -/// @param[in] format The format of the message to pass to Kodi. -/// @param[in] ... Additional text to insert in format text -/// -/// -/// @note This method uses limited buffer (16k) for the formatted output. -/// So data, which will not fit into it, will be silently discarded. -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// kodi::Log(ADDON_LOG_ERROR, "%s: There is an error occurred!", __func__); -/// -/// ~~~~~~~~~~~~~ -/// -inline void ATTRIBUTE_HIDDEN Log(const AddonLog loglevel, const char* format, ...) -{ - using namespace kodi::addon; - - char buffer[16384]; - va_list args; - va_start(args, format); - vsnprintf(buffer, sizeof(buffer), format, args); - va_end(args); - CAddonBase::m_interface->toKodi->addon_log_msg(CAddonBase::m_interface->toKodi->kodiBase, - loglevel, buffer); -} -//------------------------------------------------------------------------------ - -//############################################################################## -/// @ingroup cpp_kodi -/// @defgroup cpp_kodi_settings 1. Setting control -/// @brief **Functions to handle settings access**\n -/// This can be used to get and set the addon related values inside his -/// settings.xml. -/// -/// The settings style is given with installed part on e.g. -/// `$HOME/.kodi/addons/myspecial.addon/resources/settings.xml`. The -/// related edit becomes then stored inside -/// `$HOME/.kodi/userdata/addon_data/myspecial.addon/settings.xml`. -/// -/*!@{*/ - -//============================================================================== -/// @brief Check the given setting name is set to default value. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of asked setting -/// @return true if setting is the default -/// -inline bool ATTRIBUTE_HIDDEN IsSettingUsingDefault(const std::string& settingName) -{ - using namespace kodi::addon; - return CAddonBase::m_interface->toKodi->is_setting_using_default( - CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str()); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Check and get a string setting value. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of asked setting -/// @param[out] settingValue The given setting value -/// @return true if setting was successfully found and "settingValue" is set -/// -/// @note If returns false, the "settingValue" is not changed. -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// std::string value; -/// if (!kodi::CheckSettingString("my_string_value", value)) -/// value = "my_default_if_setting_not_work"; -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN CheckSettingString(const std::string& settingName, - std::string& settingValue) -{ - using namespace kodi::addon; - - char* buffer = nullptr; - bool ret = CAddonBase::m_interface->toKodi->get_setting_string( - CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), &buffer); - if (buffer) - { - if (ret) - settingValue = buffer; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, buffer); - } - return ret; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Get string setting value. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of asked setting -/// @param[in] defaultValue [opt] Default value if not found -/// @return The value of setting, empty if not found; -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// std::string value = kodi::GetSettingString("my_string_value"); -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN GetSettingString(const std::string& settingName, - const std::string& defaultValue = "") -{ - std::string settingValue = defaultValue; - CheckSettingString(settingName, settingValue); - return settingValue; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Set string setting of addon. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of setting -/// @param[in] settingValue The setting value to write -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// std::string value = "my_new_name for"; -/// kodi::SetSettingString("my_string_value", value); -/// ~~~~~~~~~~~~~ -/// -inline void ATTRIBUTE_HIDDEN SetSettingString(const std::string& settingName, - const std::string& settingValue) -{ - using namespace kodi::addon; - - CAddonBase::m_interface->toKodi->set_setting_string(CAddonBase::m_interface->toKodi->kodiBase, - settingName.c_str(), settingValue.c_str()); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Check and get a integer setting value. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of asked setting -/// @param[out] settingValue The given setting value -/// @return true if setting was successfully found and "settingValue" is set -/// -/// @note If returns false, the "settingValue" is not changed. -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// int value = 0; -/// if (!kodi::CheckSettingInt("my_integer_value", value)) -/// value = 123; // My default of them -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN CheckSettingInt(const std::string& settingName, int& settingValue) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->get_setting_int(CAddonBase::m_interface->toKodi->kodiBase, - settingName.c_str(), &settingValue); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Get integer setting value. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of asked setting -/// @param[in] defaultValue [opt] Default value if not found -/// @return The value of setting, `0` or defaultValue if not found -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// int value = kodi::GetSettingInt("my_integer_value"); -/// ~~~~~~~~~~~~~ -/// -inline int ATTRIBUTE_HIDDEN GetSettingInt(const std::string& settingName, int defaultValue = 0) -{ - int settingValue = defaultValue; - CheckSettingInt(settingName, settingValue); - return settingValue; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Set integer setting of addon. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of setting -/// @param[in] settingValue The setting value to write -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// int value = 123; -/// kodi::SetSettingInt("my_integer_value", value); -/// ~~~~~~~~~~~~~ -/// -inline void ATTRIBUTE_HIDDEN SetSettingInt(const std::string& settingName, int settingValue) -{ - using namespace kodi::addon; - - CAddonBase::m_interface->toKodi->set_setting_int(CAddonBase::m_interface->toKodi->kodiBase, - settingName.c_str(), settingValue); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Check and get a boolean setting value. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of asked setting -/// @param[out] settingValue The given setting value -/// @return true if setting was successfully found and "settingValue" is set -/// -/// @note If returns false, the "settingValue" is not changed. -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// bool value = false; -/// if (!kodi::CheckSettingBoolean("my_boolean_value", value)) -/// value = true; // My default of them -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN CheckSettingBoolean(const std::string& settingName, bool& settingValue) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->get_setting_bool( - CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), &settingValue); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Get boolean setting value. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of asked setting -/// @param[in] defaultValue [opt] Default value if not found -/// @return The value of setting, `false` or defaultValue if not found -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// bool value = kodi::GetSettingBoolean("my_boolean_value"); -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN GetSettingBoolean(const std::string& settingName, - bool defaultValue = false) -{ - bool settingValue = defaultValue; - CheckSettingBoolean(settingName, settingValue); - return settingValue; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Set boolean setting of addon. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of setting -/// @param[in] settingValue The setting value to write -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// bool value = true; -/// kodi::SetSettingBoolean("my_boolean_value", value); -/// ~~~~~~~~~~~~~ -/// -inline void ATTRIBUTE_HIDDEN SetSettingBoolean(const std::string& settingName, bool settingValue) -{ - using namespace kodi::addon; - - CAddonBase::m_interface->toKodi->set_setting_bool(CAddonBase::m_interface->toKodi->kodiBase, - settingName.c_str(), settingValue); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Check and get a floating point setting value. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of asked setting -/// @param[out] settingValue The given setting value -/// @return true if setting was successfully found and "settingValue" is set -/// -/// @note If returns false, the "settingValue" is not changed. -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// float value = 0.0f; -/// if (!kodi::CheckSettingBoolean("my_float_value", value)) -/// value = 1.0f; // My default of them -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN CheckSettingFloat(const std::string& settingName, float& settingValue) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->get_setting_float( - CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), &settingValue); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Get floating point setting value. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of asked setting -/// @param[in] defaultValue [opt] Default value if not found -/// @return The value of setting, `0.0` or defaultValue if not found -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// float value = kodi::GetSettingFloat("my_float_value"); -/// ~~~~~~~~~~~~~ -/// -inline float ATTRIBUTE_HIDDEN GetSettingFloat(const std::string& settingName, - float defaultValue = 0.0f) -{ - float settingValue = defaultValue; - CheckSettingFloat(settingName, settingValue); - return settingValue; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Set floating point setting of addon. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of setting -/// @param[in] settingValue The setting value to write -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// float value = 1.0f; -/// kodi::SetSettingFloat("my_float_value", value); -/// ~~~~~~~~~~~~~ -/// -inline void ATTRIBUTE_HIDDEN SetSettingFloat(const std::string& settingName, float settingValue) -{ - using namespace kodi::addon; - - CAddonBase::m_interface->toKodi->set_setting_float(CAddonBase::m_interface->toKodi->kodiBase, - settingName.c_str(), settingValue); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Check and get a enum setting value. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of asked setting -/// @param[out] settingValue The given setting value -/// @return true if setting was successfully found and "settingValue" is set -/// -/// @remark The enums are used as integer inside settings.xml. -/// @note If returns false, the "settingValue" is not changed. -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// enum myEnumValue -/// { -/// valueA, -/// valueB, -/// valueC -/// }; -/// -/// myEnumValue value; -/// if (!kodi::CheckSettingEnum("my_enum_value", value)) -/// value = valueA; // My default of them -/// ~~~~~~~~~~~~~ -/// -template -inline bool ATTRIBUTE_HIDDEN CheckSettingEnum(const std::string& settingName, - enumType& settingValue) -{ - using namespace kodi::addon; - - int settingValueInt = static_cast(settingValue); - bool ret = CAddonBase::m_interface->toKodi->get_setting_int( - CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), &settingValueInt); - if (ret) - settingValue = static_cast(settingValueInt); - return ret; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Get enum setting value. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of asked setting -/// @param[in] defaultValue [opt] Default value if not found -/// @return The value of setting, forced to `0` or defaultValue if not found -/// -/// @remark The enums are used as integer inside settings.xml. -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// enum myEnumValue -/// { -/// valueA, -/// valueB, -/// valueC -/// }; -/// -/// myEnumValue value = kodi::GetSettingEnum("my_enum_value"); -/// ~~~~~~~~~~~~~ -/// -template -inline enumType ATTRIBUTE_HIDDEN GetSettingEnum(const std::string& settingName, - enumType defaultValue = static_cast(0)) -{ - enumType settingValue = defaultValue; - CheckSettingEnum(settingName, settingValue); - return settingValue; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Set enum setting of addon. -/// -/// The setting name relate to names used in his settings.xml file. -/// -/// @param[in] settingName The name of setting -/// @param[in] settingValue The setting value to write -/// -/// @remark The enums are used as integer inside settings.xml. -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// enum myEnumValue -/// { -/// valueA, -/// valueB, -/// valueC -/// }; -/// -/// myEnumValue value = valueA; -/// kodi::SetSettingEnum("my_enum_value", value); -/// ~~~~~~~~~~~~~ -/// -template -inline void ATTRIBUTE_HIDDEN SetSettingEnum(const std::string& settingName, enumType settingValue) -{ - using namespace kodi::addon; - - CAddonBase::m_interface->toKodi->set_setting_int(CAddonBase::m_interface->toKodi->kodiBase, - settingName.c_str(), - static_cast(settingValue)); -} -//------------------------------------------------------------------------------ - -/*!@}*/ - -//============================================================================ -/// -inline std::string ATTRIBUTE_HIDDEN TranslateAddonStatus(ADDON_STATUS status) -{ - switch (status) - { - case ADDON_STATUS_OK: - return "OK"; - case ADDON_STATUS_LOST_CONNECTION: - return "Lost Connection"; - case ADDON_STATUS_NEED_RESTART: - return "Need Restart"; - case ADDON_STATUS_NEED_SETTINGS: - return "Need Settings"; - case ADDON_STATUS_UNKNOWN: - return "Unknown error"; - case ADDON_STATUS_PERMANENT_FAILURE: - return "Permanent failure"; - case ADDON_STATUS_NOT_IMPLEMENTED: - return "Not implemented"; - default: - break; - } - return "Unknown"; -} -//---------------------------------------------------------------------------- - -//============================================================================== -/// @ingroup cpp_kodi -/// @brief Returns a function table to a named interface -/// -/// @return pointer to struct containing interface functions -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// #include -/// ... -/// FuncTable_foo *table = kodi::GetPlatformInfo(foo_name, foo_version); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline void* GetInterface(const std::string& name, const std::string& version) -{ - using namespace kodi::addon; - - AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; - - return toKodi->get_interface(toKodi->kodiBase, name.c_str(), version.c_str()); -} -//---------------------------------------------------------------------------- - -} /* namespace kodi */ - -/*! addon creation macro - * @todo cleanup this stupid big macro - * This macro includes now all for add-on's needed functions. This becomes a bigger - * rework after everything is done on Kodi itself, currently is this way needed - * to have compatibility with not reworked interfaces. - * - * Becomes really cleaned up soon :D - */ -#define ADDONCREATOR(AddonClass) \ - extern "C" __declspec(dllexport) ADDON_STATUS ADDON_Create( \ - KODI_HANDLE addonInterface, const char* /*globalApiVersion*/, void* /*unused*/) \ - { \ - kodi::addon::CAddonBase::m_interface = static_cast(addonInterface); \ - kodi::addon::CAddonBase::m_interface->addonBase = new AddonClass; \ - return static_cast(kodi::addon::CAddonBase::m_interface->addonBase) \ - ->Create(); \ - } \ - extern "C" __declspec(dllexport) void ADDON_Destroy() \ - { \ - kodi::addon::CAddonBase::ADDONBASE_Destroy(); \ - } \ - extern "C" __declspec(dllexport) ADDON_STATUS ADDON_GetStatus() \ - { \ - return kodi::addon::CAddonBase::ADDONBASE_GetStatus(); \ - } \ - extern "C" __declspec(dllexport) ADDON_STATUS ADDON_SetSetting(const char* settingName, \ - const void* settingValue) \ - { \ - return kodi::addon::CAddonBase::ADDONBASE_SetSetting(settingName, settingValue); \ - } \ - extern "C" __declspec(dllexport) const char* ADDON_GetTypeVersion(int type) \ - { \ - return kodi::addon::GetTypeVersion(type); \ - } \ - extern "C" __declspec(dllexport) const char* ADDON_GetTypeMinVersion(int type) \ - { \ - return kodi::addon::GetTypeMinVersion(type); \ - } \ - AddonGlobalInterface* kodi::addon::CAddonBase::m_interface = nullptr; diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/AudioEngine.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/AudioEngine.h deleted file mode 100644 index 0cfefac..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/AudioEngine.h +++ /dev/null @@ -1,618 +0,0 @@ -/* - * Copyright (C) 2005-2019 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "AddonBase.h" -#include "c-api/audio_engine.h" - -#ifdef __cplusplus - -namespace kodi -{ -namespace audioengine -{ - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// Main page text for audio engine group by Doxygen. -//{{{ - -//============================================================================== -/// -/// @defgroup cpp_kodi_audioengine Interface - kodi::audioengine -/// @ingroup cpp -/// @brief **Audio engine functions**\n -/// This interface contains auxiliary functions and classes which allow an addon -/// to play their own individual audio stream in Kodi. -/// -/// Using @ref cpp_kodi_audioengine_CAEStream "kodi::audioengine::CAEStream", -/// a class can be created in this regard, about which the necessary stream data and -/// information are given to Kodi. -/// -/// Via @ref kodi::audioengine::GetCurrentSinkFormat(), the audio formats currently -/// processed in Kodi can be called up beforehand in order to adapt your own stream -/// to them. -/// -/// However, the created stream can also differ from this because Kodi changes -/// it to suit it. -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// -/// #include -/// -/// ... -/// -/// kodi::audioengine::AudioEngineFormat format; -/// if (!kodi::audioengine::GetCurrentSinkFormat(format)) -/// return false; -/// -/// format.SetDataFormat(AUDIOENGINE_FMT_FLOATP); -/// format.SetChannelLayout(std::vector(AUDIOENGINE_CH_FL, AUDIOENGINE_CH_FR)); -/// -/// unsigned int myUsedSampleRate = format.GetSampleRate(); -/// -/// ... -/// -/// kodi::audioengine::CAEStream* stream = new kodi::audioengine::CAEStream(format, AUDIO_STREAM_AUTOSTART); -/// -/// ~~~~~~~~~~~~~ -/// -/// ------------------------------------------------------------------------ -/// -/// It has the header \ref AudioEngine.h "#include " be included -/// to enjoy it. -/// -//------------------------------------------------------------------------------ - -//============================================================================== -/// -/// @defgroup cpp_kodi_audioengine_Defs Definitions, structures and enumerators -/// @ingroup cpp_kodi_audioengine -/// @brief **Library definition values**\n -/// All audio engine functions associated data structures. -/// -//------------------------------------------------------------------------------ - -//}}} - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" related audio engine definitions -//{{{ - -//============================================================================== -/// @defgroup cpp_kodi_audioengine_Defs_AudioEngineFormat class AudioEngineFormat -/// @ingroup cpp_kodi_audioengine_Defs -/// @brief **Audio format structure**\n -/// The audio format structure that fully defines a stream's audio -/// information. -/// -/// With the help of this format information, Kodi adjusts its processing -/// accordingly. -/// -//@{ -class ATTRIBUTE_HIDDEN AudioEngineFormat - : public addon::CStructHdl -{ -public: - /*! \cond PRIVATE */ - AudioEngineFormat() - { - m_cStructure->m_dataFormat = AUDIOENGINE_FMT_INVALID; - m_cStructure->m_sampleRate = 0; - m_cStructure->m_encodedRate = 0; - m_cStructure->m_frames = 0; - m_cStructure->m_frameSize = 0; - m_cStructure->m_channelCount = 0; - - for (size_t ch = 0; ch < AUDIOENGINE_CH_MAX; ++ch) - m_cStructure->m_channels[ch] = AUDIOENGINE_CH_NULL; - } - AudioEngineFormat(const AudioEngineFormat& channel) : CStructHdl(channel) {} - AudioEngineFormat(const AUDIO_ENGINE_FORMAT* channel) : CStructHdl(channel) {} - AudioEngineFormat(AUDIO_ENGINE_FORMAT* channel) : CStructHdl(channel) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_audioengine_Defs_AudioEngineFormat_Help *Value Help* - /// @ingroup cpp_kodi_audioengine_Defs_AudioEngineFormat - /// - /// The following table contains values that can be set with @ref cpp_kodi_audioengine_Defs_AudioEngineFormat : - /// | Name | Type | Set call | Get call - /// |------|------|----------|---------- - /// | **Data format**, see @ref AudioEngineDataFormat for available types | enum | @ref AudioEngineFormat::SetDataFormat "SetDataFormat" | @ref AudioEngineFormat::GetDataFormat "GetDataFormat" - /// | **Sample rate** | unsigned int | @ref AudioEngineFormat::SetSampleRate "SetSampleRate" | @ref AudioEngineFormat::GetSampleRate "GetSampleRate" - /// | **Encoded rate** | unsigned int | @ref AudioEngineFormat::SetEncodedRate "SetEncodedRate" | @ref AudioEngineFormat::GetEncodedRate "GetEncodedRate" - /// | **Channel layout**, see @ref AudioEngineChannel for available types | std::vector | @ref AudioEngineFormat::SetChannelLayout "SetChannelLayout" | @ref AudioEngineFormat::GetChannelLayout "GetChannelLayout" - /// | **Frames amount** | unsigned int | @ref AudioEngineFormat::SetFramesAmount "SetFramesAmount" | @ref AudioEngineFormat::GetFramesAmount "GetFramesAmount" - /// | **Frame size** | unsigned int | @ref AudioEngineFormat::SetFrameSize "SetFrameSize" | @ref AudioEngineFormat::GetFrameSize "GetFrameSize" - /// - /// Further is @ref AudioEngineFormat::CompareFormat "CompareFormat" included to compare this class with another. - /// - - /// @addtogroup cpp_kodi_audioengine_Defs_AudioEngineFormat - /// @copydetails cpp_kodi_audioengine_Defs_AudioEngineFormat_Help - //@{ - - /// @brief The stream's data format (eg, AUDIOENGINE_FMT_S16LE) - void SetDataFormat(enum AudioEngineDataFormat format) { m_cStructure->m_dataFormat = format; } - - /// @brief To get with @ref SetDataFormat changed values. - enum AudioEngineDataFormat GetDataFormat() const { return m_cStructure->m_dataFormat; } - - /// @brief The stream's sample rate (eg, 48000) - void SetSampleRate(unsigned int rate) { m_cStructure->m_sampleRate = rate; } - - /// @brief To get with @ref SetSampleRate changed values. - unsigned int GetSampleRate() const { return m_cStructure->m_sampleRate; } - - /// @brief The encoded streams sample rate if a bitstream, otherwise undefined - void SetEncodedRate(unsigned int rate) { m_cStructure->m_encodedRate = rate; } - - /// @brief To get with @ref SetEncodedRate changed values. - unsigned int GetEncodedRate() const { return m_cStructure->m_encodedRate; } - - /// @brief The stream's channel layout - void SetChannelLayout(const std::vector& layout) - { - // Reset first all to empty values to AUDIOENGINE_CH_NULL, in case given list is empty - m_cStructure->m_channelCount = 0; - for (size_t ch = 0; ch < AUDIOENGINE_CH_MAX; ++ch) - m_cStructure->m_channels[ch] = AUDIOENGINE_CH_NULL; - - for (size_t ch = 0; ch < layout.size() && ch < AUDIOENGINE_CH_MAX; ++ch) - { - m_cStructure->m_channels[ch] = layout[ch]; - m_cStructure->m_channelCount++; - } - } - - /// @brief To get with @ref SetChannelLayout changed values. - std::vector GetChannelLayout() const - { - std::vector channels; - for (size_t ch = 0; ch < AUDIOENGINE_CH_MAX; ++ch) - { - if (m_cStructure->m_channels[ch] == AUDIOENGINE_CH_NULL) - break; - - channels.push_back(m_cStructure->m_channels[ch]); - } - return channels; - } - - /// @brief The number of frames per period - void SetFramesAmount(unsigned int frames) { m_cStructure->m_frames = frames; } - - /// @brief To get with @ref SetFramesAmount changed values. - unsigned int GetFramesAmount() const { return m_cStructure->m_frames; } - - /// @brief The size of one frame in bytes - void SetFrameSize(unsigned int frameSize) { m_cStructure->m_frameSize = frameSize; } - - /// @brief To get with @ref SetFrameSize changed values. - unsigned int GetFrameSize() const { return m_cStructure->m_frameSize; } - - /// @brief Function to compare the format structure with another - bool CompareFormat(const AudioEngineFormat* fmt) - { - if (!fmt) - { - return false; - } - - if (m_cStructure->m_dataFormat != fmt->m_cStructure->m_dataFormat || - m_cStructure->m_sampleRate != fmt->m_cStructure->m_sampleRate || - m_cStructure->m_encodedRate != fmt->m_cStructure->m_encodedRate || - m_cStructure->m_frames != fmt->m_cStructure->m_frames || - m_cStructure->m_frameSize != fmt->m_cStructure->m_frameSize || - m_cStructure->m_channelCount != fmt->m_cStructure->m_channelCount) - { - return false; - } - - for (unsigned int ch = 0; ch < AUDIOENGINE_CH_MAX; ++ch) - { - if (fmt->m_cStructure->m_channels[ch] != m_cStructure->m_channels[ch]) - { - return false; - } - } - - return true; - } -}; -//@} -//---------------------------------------------------------------------------- - -//}}} - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" AudioEngine addon interface -//{{{ - -//============================================================================ -/// -/// @defgroup cpp_kodi_audioengine_CAEStream class CAEStream -/// @ingroup cpp_kodi_audioengine -/// @brief **Audio Engine Stream Class**\n -/// Class that can be created by the addon in order to be able to transfer -/// audiostream data processed on the addon to Kodi and output it audibly. -/// -/// This can create individually several times and performed in different -/// processes simultaneously. -/// -/// It has the header @ref AudioEngine.h "#include " be -/// included to enjoy it. -/// -//---------------------------------------------------------------------------- -class ATTRIBUTE_HIDDEN CAEStream -{ -public: - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Contructs new class to an Kodi IAEStream in the format specified. - /// - /// @param[in] format The data format the incoming audio will be in - /// (e.g. \ref AUDIOENGINE_FMT_S16LE) - /// @param[in] options [opt] A bit field of stream options (see: enum \ref AudioEngineStreamOptions) - /// - /// - /// ------------------------------------------------------------------------ - /// - /// @copydetails cpp_kodi_audioengine_Defs_AudioEngineFormat_Help - /// - /// ------------------------------------------------------------------------ - /// - /// **Bit options to pass (on Kodi by IAE::MakeStream)** - /// - /// | enum AEStreamOptions | Value: | Description: - /// |----------------------------:|:------:|:----------------------------------- - /// | AUDIO_STREAM_FORCE_RESAMPLE | 1 << 0 | Force resample even if rates match - /// | AUDIO_STREAM_PAUSED | 1 << 1 | Create the stream paused - /// | AUDIO_STREAM_AUTOSTART | 1 << 2 | Autostart the stream when enough data is buffered - /// - /// - /// ------------------------------------------------------------------------ - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// - /// #include - /// - /// ... - /// - /// kodi::audioengine::AudioEngineFormat format; - /// - /// format.SetDataFormat(AUDIOENGINE_FMT_FLOATP); /* The stream's data format (eg, AUDIOENGINE_FMT_S16LE) */ - /// format.SetChannelLayout(std::vector(AUDIOENGINE_CH_FL, AUDIOENGINE_CH_FR)); /* The stream's channel layout */ - /// format.SetSampleRate(48000); /* The stream's sample rate (eg, 48000) */ - /// format.SetFrameSize(sizeof(float)*2); /* The size of one frame in bytes */ - /// format.SetFramesAmount(882); /* The number of samples in one frame */ - /// - /// kodi::audioengine::CAEStream* stream = new kodi::audioengine::CAEStream(format, AUDIO_STREAM_AUTOSTART); - /// - /// ~~~~~~~~~~~~~ - /// - CAEStream(AudioEngineFormat& format, unsigned int options = 0) - : m_kodiBase(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase), - m_cb(::kodi::addon::CAddonBase::m_interface->toKodi->kodi_audioengine) - { - m_StreamHandle = m_cb->make_stream(m_kodiBase, format, options); - if (m_StreamHandle == nullptr) - { - kodi::Log(ADDON_LOG_FATAL, "CAEStream: make_stream failed!"); - } - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Class destructor. - /// - ~CAEStream() - { - if (m_StreamHandle) - { - m_cb->free_stream(m_kodiBase, m_StreamHandle); - m_StreamHandle = nullptr; - } - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Returns the amount of space available in the stream. - /// - /// @return The number of bytes AddData will consume - /// - unsigned int GetSpace() { return m_cb->aestream_get_space(m_kodiBase, m_StreamHandle); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Add planar or interleaved PCM data to the stream. - /// - /// @param[in] data array of pointers to the planes - /// @param[in] offset to frame in frames - /// @param[in] frames number of frames - /// @param[in] pts [opt] presentation timestamp, default is 0 - /// @param[in] hasDownmix [opt] set true if downmix is present, default is false - /// @param[in] centerMixLevel [opt] level to mix left and right to center default is 1.0 - /// @return The number of frames consumed - /// - unsigned int AddData(uint8_t* const* data, - unsigned int offset, - unsigned int frames, - double pts = 0, - bool hasDownmix = false, - double centerMixLevel = 1.0) - { - return m_cb->aestream_add_data(m_kodiBase, m_StreamHandle, data, offset, frames, pts, - hasDownmix, centerMixLevel); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Returns the time in seconds that it will take for the next added - /// packet to be heard from the speakers. - /// - /// @return seconds - /// - double GetDelay() { return m_cb->aestream_get_delay(m_kodiBase, m_StreamHandle); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Returns if the stream is buffering. - /// - /// @return True if the stream is buffering - /// - bool IsBuffering() { return m_cb->aestream_is_buffering(m_kodiBase, m_StreamHandle); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Returns the time in seconds of the stream's cached audio samples. - /// Engine buffers excluded. - /// - /// @return seconds - /// - double GetCacheTime() { return m_cb->aestream_get_cache_time(m_kodiBase, m_StreamHandle); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Returns the total time in seconds of the cache. - /// - /// @return seconds - /// - double GetCacheTotal() { return m_cb->aestream_get_cache_total(m_kodiBase, m_StreamHandle); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Pauses the stream playback. - /// - void Pause() { return m_cb->aestream_pause(m_kodiBase, m_StreamHandle); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Resumes the stream after pausing - /// - void Resume() { return m_cb->aestream_resume(m_kodiBase, m_StreamHandle); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Start draining the stream. - /// - /// @param[in] wait [opt] Wait until drain is finished if set to true, - /// otherwise it returns direct - /// - /// @note Once called AddData will not consume more data. - /// - void Drain(bool wait = true) { return m_cb->aestream_drain(m_kodiBase, m_StreamHandle, wait); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Returns true if the is stream draining. - /// - bool IsDraining() { return m_cb->aestream_is_draining(m_kodiBase, m_StreamHandle); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Returns true if the is stream has finished draining. - /// - bool IsDrained() { return m_cb->aestream_is_drained(m_kodiBase, m_StreamHandle); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Flush all buffers dropping the audio data. - /// - void Flush() { return m_cb->aestream_flush(m_kodiBase, m_StreamHandle); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Return the stream's current volume level. - /// - /// @return The volume level between 0.0 and 1.0 - /// - float GetVolume() { return m_cb->aestream_get_volume(m_kodiBase, m_StreamHandle); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Set the stream's volume level. - /// - /// @param[in] volume The new volume level between 0.0 and 1.0 - /// - void SetVolume(float volume) - { - return m_cb->aestream_set_volume(m_kodiBase, m_StreamHandle, volume); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Gets the stream's volume amplification in linear units. - /// - /// @return The volume amplification factor between 1.0 and 1000.0 - /// - float GetAmplification() { return m_cb->aestream_get_amplification(m_kodiBase, m_StreamHandle); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Sets the stream's volume amplification in linear units. - /// - /// @param[in] amplify The volume amplification factor between 1.0 and 1000.0 - /// - void SetAmplification(float amplify) - { - return m_cb->aestream_set_amplification(m_kodiBase, m_StreamHandle, amplify); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Returns the size of one audio frame in bytes (channelCount * resolution). - /// - /// @return The size in bytes of one frame - /// - unsigned int GetFrameSize() const - { - return m_cb->aestream_get_frame_size(m_kodiBase, m_StreamHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Returns the number of channels the stream is configured to accept. - /// - /// @return The channel count - /// - unsigned int GetChannelCount() const - { - return m_cb->aestream_get_channel_count(m_kodiBase, m_StreamHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Returns the stream's sample rate, if the stream is using a dynamic - /// sample rate, this value will NOT reflect any changes made by calls to - /// SetResampleRatio(). - /// - /// @return The stream's sample rate (eg, 48000) - /// - unsigned int GetSampleRate() const - { - return m_cb->aestream_get_sample_rate(m_kodiBase, m_StreamHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Return the data format the stream has been configured with. - /// - /// @return The stream's data format (eg, AUDIOENGINE_FMT_S16LE) - /// - AudioEngineDataFormat GetDataFormat() const - { - return m_cb->aestream_get_data_format(m_kodiBase, m_StreamHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Return the resample ratio. - /// - /// @note This will return an undefined value if the stream is not resampling. - /// - /// @return the current resample ratio or undefined if the stream is not resampling - /// - double GetResampleRatio() - { - return m_cb->aestream_get_resample_ratio(m_kodiBase, m_StreamHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_audioengine_CAEStream - /// @brief Sets the resample ratio. - /// - /// @note This function may return false if the stream is not resampling, if - /// you wish to use this be sure to set the AESTREAM_FORCE_RESAMPLE option. - /// - /// @param[in] ratio the new sample rate ratio, calculated by - /// ((double)desiredRate / (double)GetSampleRate()) - /// - void SetResampleRatio(double ratio) - { - m_cb->aestream_set_resample_ratio(m_kodiBase, m_StreamHandle, ratio); - } - //-------------------------------------------------------------------------- - -private: - void* m_kodiBase; - AddonToKodiFuncTable_kodi_audioengine* m_cb; - AEStreamHandle* m_StreamHandle; -}; -//---------------------------------------------------------------------------- - -//============================================================================ -/// @ingroup cpp_kodi_audioengine -/// @brief Get the current sink data format. -/// -/// @param[in] format Current sink data format. For more details see AudioEngineFormat. -/// @return Returns true on success, else false. -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// -/// #include -/// -/// ... -/// -/// kodi::audioengine::AudioEngineFormat format; -/// if (!kodi::audioengine::GetCurrentSinkFormat(format)) -/// return false; -/// -/// std::vector layout = format.GetChannelLayout(); -/// -/// ... -/// return true; -/// -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN GetCurrentSinkFormat(AudioEngineFormat& format) -{ - using namespace kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_audioengine->get_current_sink_format( - CAddonBase::m_interface->toKodi->kodiBase, format); -} -//---------------------------------------------------------------------------- - -//}}} - -} // namespace audioengine -} // namespace kodi - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/CMakeLists.txt deleted file mode 100644 index de7cb3e..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set(HEADERS AddonBase.h - AudioEngine.h - Filesystem.h - General.h - Network.h - StreamCodec.h - StreamCrypto.h - versions.h) - -if(CORE_SYSTEM_NAME STREQUAL android) - list(APPEND SOURCES platform/android/System.h) -endif() - -if(NOT ENABLE_STATIC_LIBS) - core_add_library(addons_kodi-addon-dev-kit_include_kodi) -endif() diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/Filesystem.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/Filesystem.h deleted file mode 100644 index 2054ce6..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/Filesystem.h +++ /dev/null @@ -1,2321 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "AddonBase.h" -#include "c-api/filesystem.h" - -#ifdef __cplusplus - -#include -#include -#include - -namespace kodi -{ -namespace vfs -{ - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// Main page text for filesystem group by Doxygen. -//{{{ - -//============================================================================== -/// -/// @defgroup cpp_kodi_vfs Interface - kodi::vfs -/// @ingroup cpp -/// @brief **Virtual filesystem functions**\n -/// Offers classes and functions for access to the Virtual File Server (VFS) -/// which you can use to manipulate files and folders. -/// -/// This system allow the use of ["Special Protocol"](https://kodi.wiki/view/Special_protocol) -/// where is Kodi's solution to platform dependent directories. Common directory -/// names are assigned a `special://[name]` path which is passed around -/// inside Kodi and then translated to the platform specific path before the -/// operating system sees it. This helps keep most of the platform mess -/// centralized in the code.\n -/// To become a correct path back can be @ref TranslateSpecialProtocol() used. -/// -/// It has the header @ref Filesystem.h "#include " be -/// included to enjoy it. -/// -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_vfs_Defs Definitions, structures and enumerators -/// @ingroup cpp_kodi_vfs -/// @brief **Virtual file Server definition values**\n -/// All to VFS system functions associated data structures. -/// -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_vfs_Directory 1. Directory functions -/// @ingroup cpp_kodi_vfs -/// @brief **Globally available directories related functions**\n -/// Used to perform typical operations with it. -/// -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_vfs_File 2. File functions -/// @ingroup cpp_kodi_vfs -/// @brief **Globally available file related functions**\n -/// Used to perform typical operations with it. -/// -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_vfs_General 3. General functions -/// @ingroup cpp_kodi_vfs -/// @brief **Other globally available functions**\n -/// Used to perform typical operations with it. -/// -//------------------------------------------------------------------------------ - -//}}} - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" related filesystem definitions -//{{{ - -//============================================================================== -/// @defgroup cpp_kodi_vfs_Defs_FileStatus class FileStatus -/// @ingroup cpp_kodi_vfs_Defs -/// @brief **File information status**\n -/// Used on kodi::vfs::StatFile() to get detailed information about a file. -/// -//@{ -class ATTRIBUTE_HIDDEN FileStatus : public kodi::addon::CStructHdl -{ -public: - /*! \cond PRIVATE */ - FileStatus() { memset(m_cStructure, 0, sizeof(STAT_STRUCTURE)); } - FileStatus(const FileStatus& channel) : CStructHdl(channel) {} - FileStatus(const STAT_STRUCTURE* channel) : CStructHdl(channel) {} - FileStatus(STAT_STRUCTURE* channel) : CStructHdl(channel) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_vfs_Defs_FileStatus_Help *Value Help* - /// @ingroup cpp_kodi_vfs_Defs_FileStatus - /// ---------------------------------------------------------------------------- - /// - /// The following table contains values that can be set with @ref cpp_kodi_vfs_Defs_FileStatus : - /// | Name | Type | Set call | Get call - /// |------|------|----------|---------- - /// | **ID of device containing file** | `uint32_t` | @ref FileStatus::SetDeviceId "SetDeviceId" | @ref FileStatus::GetDeviceId "GetDeviceId" - /// | **Total size, in bytes** | `uint64_t` | @ref FileStatus::SetSize "SetSize" | @ref FileStatus::GetSize "GetSize" - /// | **Time of last access** | `time_t` | @ref FileStatus::SetAccessTime "SetAccessTime" | @ref FileStatus::GetAccessTime "GetAccessTime" - /// | **Time of last modification** | `time_t` | @ref FileStatus::SetModificationTime "SetModificationTime" | @ref FileStatus::GetModificationTime "GetModificationTime" - /// | **Time of last status change** | `time_t` | @ref FileStatus::SetStatusTime "SetStatusTime" | @ref FileStatus::GetStatusTime "GetStatusTime" - /// | **Stat url is a directory** | `bool` | @ref FileStatus::SetIsDirectory "SetIsDirectory" | @ref FileStatus::GetIsDirectory "GetIsDirectory" - /// | **Stat url as a symbolic link** | `bool` | @ref FileStatus::SetIsSymLink "SetIsSymLink" | @ref FileStatus::GetIsSymLink "GetIsSymLink" - /// - - /// @addtogroup cpp_kodi_vfs_Defs_FileStatus - /// @copydetails cpp_kodi_vfs_Defs_FileStatus_Help - //@{ - - /// @brief Set ID of device containing file. - void SetDeviceId(uint32_t deviceId) { m_cStructure->deviceId = deviceId; } - - /// @brief Get ID of device containing file. - uint32_t GetDeviceId() const { return m_cStructure->deviceId; } - - /// @brief Set total size, in bytes. - void SetSize(uint64_t size) { m_cStructure->size = size; } - - /// @brief Get total size, in bytes. - uint64_t GetSize() const { return m_cStructure->size; } - - /// @brief Set time of last access. - void SetAccessTime(time_t accessTime) { m_cStructure->accessTime = accessTime; } - - /// @brief Get time of last access. - time_t GetAccessTime() const { return m_cStructure->accessTime; } - - /// @brief Set time of last modification. - void SetModificationTime(time_t modificationTime) - { - m_cStructure->modificationTime = modificationTime; - } - - /// @brief Get time of last modification. - time_t GetModificationTime() const { return m_cStructure->modificationTime; } - - /// @brief Set time of last status change. - void SetStatusTime(time_t statusTime) { m_cStructure->statusTime = statusTime; } - - /// @brief Get time of last status change. - time_t GetStatusTime() const { return m_cStructure->statusTime; } - - /// @brief Set the stat url is a directory. - void SetIsDirectory(bool isDirectory) { m_cStructure->isDirectory = isDirectory; } - - /// @brief The stat url is a directory if returns true. - bool GetIsDirectory() const { return m_cStructure->isDirectory; } - - /// @brief Set stat url as a symbolic link. - void SetIsSymLink(bool isSymLink) { m_cStructure->isSymLink = isSymLink; } - - /// @brief Get stat url is a symbolic link. - bool GetIsSymLink() const { return m_cStructure->isSymLink; } - - //@} -}; -//@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_vfs_Defs_CacheStatus class CacheStatus -/// @ingroup cpp_kodi_vfs_Defs -/// @brief **Cache information status**\n -/// Used on kodi::vfs::CFile::IoControlGetCacheStatus() to get running cache -/// status of proccessed stream. -/// -//@{ -class ATTRIBUTE_HIDDEN CacheStatus - : public kodi::addon::CStructHdl -{ -public: - /*! \cond PRIVATE */ - CacheStatus() { memset(m_cStructure, 0, sizeof(VFS_CACHE_STATUS_DATA)); } - CacheStatus(const CacheStatus& channel) : CStructHdl(channel) {} - CacheStatus(const VFS_CACHE_STATUS_DATA* channel) : CStructHdl(channel) {} - CacheStatus(VFS_CACHE_STATUS_DATA* channel) : CStructHdl(channel) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_vfs_Defs_CacheStatus_Help *Value Help* - /// @ingroup cpp_kodi_vfs_Defs_CacheStatus - /// ---------------------------------------------------------------------------- - /// - /// The following table contains values that can be set with @ref cpp_kodi_vfs_Defs_CacheStatus : - /// | Name | Type | Set call | Get call - /// |------|------|----------|---------- - /// | **Number of bytes cached** | `uint64_t` | @ref CacheStatus::SetForward "SetForward" | @ref CacheStatus::GetForward "GetForward" - /// | **Maximum number of bytes per second** | `unsigned int` | @ref CacheStatus::SetMaxRate "SetMaxRate" | @ref CacheStatus::GetMaxRate "GetMaxRate" - /// | **Average read rate from source file** | `unsigned int` | @ref CacheStatus::SetCurrentRate "SetCurrentRate" | @ref CacheStatus::GetCurrentRate "GetCurrentRate" - /// | **Cache low speed condition detected** | `bool` | @ref CacheStatus::SetLowspeed "SetLowspeed" | @ref CacheStatus::GetLowspeed "GetLowspeed" - /// - - /// @addtogroup cpp_kodi_vfs_Defs_CacheStatus - /// @copydetails cpp_kodi_vfs_Defs_CacheStatus_Help - //@{ - - /// @brief Set number of bytes cached forward of current position. - void SetForward(uint64_t forward) { m_cStructure->forward = forward; } - - /// @brief Get number of bytes cached forward of current position. - uint64_t GetForward() { return m_cStructure->forward; } - - /// @brief Set maximum number of bytes per second cache is allowed to fill. - void SetMaxRate(unsigned int maxrate) { m_cStructure->maxrate = maxrate; } - - /// @brief Set maximum number of bytes per second cache is allowed to fill. - unsigned int GetMaxRate() { return m_cStructure->maxrate; } - - /// @brief Set average read rate from source file since last position change. - void SetCurrentRate(unsigned int currate) { m_cStructure->currate = currate; } - - /// @brief Get average read rate from source file since last position change. - unsigned int GetCurrentRate() { return m_cStructure->currate; } - - /// @brief Set cache low speed condition detected. - void SetLowspeed(bool lowspeed) { m_cStructure->lowspeed = lowspeed; } - - /// @brief Get cache low speed condition detected. - bool GetLowspeed() { return m_cStructure->lowspeed; } - - //@} -}; -//@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_vfs_Defs_HttpHeader class HttpHeader -/// @ingroup cpp_kodi_vfs_Defs -/// @brief **HTTP header information**\n -/// The class used to access HTTP header information and get his information. -/// -/// Used on @ref kodi::vfs::GetHttpHeader(). -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_vfs_Defs_HttpHeader_Help -/// -///@{ -class ATTRIBUTE_HIDDEN HttpHeader -{ -public: - //========================================================================== - /// @brief Http header parser class constructor. - /// - HttpHeader() - { - using namespace ::kodi::addon; - - CAddonBase::m_interface->toKodi->kodi_filesystem->http_header_create( - CAddonBase::m_interface->toKodi->kodiBase, &m_handle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @brief Class destructor. - /// - ~HttpHeader() - { - using namespace ::kodi::addon; - - CAddonBase::m_interface->toKodi->kodi_filesystem->http_header_free( - CAddonBase::m_interface->toKodi->kodiBase, &m_handle); - } - //-------------------------------------------------------------------------- - - /// @defgroup cpp_kodi_vfs_Defs_HttpHeader_Help *Value Help* - /// @ingroup cpp_kodi_vfs_Defs_HttpHeader - /// - /// The following table contains values that can be get with @ref cpp_kodi_vfs_Defs_HttpHeader : - /// | Description | Type | Get call - /// |-------------|------|------------ - /// | **Get the value associated with this parameter of these HTTP headers** | `std::string` | @ref HttpHeader::GetValue "GetValue" - /// | **Get the values as list associated with this parameter of these HTTP headers** | `std::vector` | @ref HttpHeader::GetValues "GetValues" - /// | **Get the full header string associated with these HTTP headers** | `std::string` | @ref HttpHeader::GetHeader "GetHeader" - /// | **Get the mime type associated with these HTTP headers** | `std::string` | @ref HttpHeader::GetMimeType "GetMimeType" - /// | **Get the charset associated with these HTTP headers** | `std::string` | @ref HttpHeader::GetCharset "GetCharset" - /// | **The protocol line associated with these HTTP headers** | `std::string` | @ref HttpHeader::GetProtoLine "GetProtoLine" - /// - - /// @addtogroup cpp_kodi_vfs_Defs_HttpHeader - ///@{ - - //========================================================================== - /// @brief Get the value associated with this parameter of these HTTP - /// headers. - /// - /// @param[in] param The name of the parameter a value is required for - /// @return The value found - /// - std::string GetValue(const std::string& param) const - { - using namespace ::kodi::addon; - - if (!m_handle.handle) - return ""; - - std::string protoLine; - char* string = m_handle.get_value(CAddonBase::m_interface->toKodi->kodiBase, m_handle.handle, - param.c_str()); - if (string != nullptr) - { - protoLine = string; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - string); - } - return protoLine; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @brief Get the values as list associated with this parameter of these - /// HTTP headers. - /// - /// @param[in] param The name of the parameter values are required for - /// @return The values found - /// - std::vector GetValues(const std::string& param) const - { - using namespace kodi::addon; - - if (!m_handle.handle) - return std::vector(); - - int numValues = 0; - char** res(m_handle.get_values(CAddonBase::m_interface->toKodi->kodiBase, m_handle.handle, - param.c_str(), &numValues)); - if (res) - { - std::vector vecReturn; - for (int i = 0; i < numValues; ++i) - { - vecReturn.emplace_back(res[i]); - } - CAddonBase::m_interface->toKodi->free_string_array(CAddonBase::m_interface->toKodi->kodiBase, - res, numValues); - return vecReturn; - } - return std::vector(); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @brief Get the full header string associated with these HTTP headers. - /// - /// @return The header as a string - /// - std::string GetHeader() const - { - using namespace ::kodi::addon; - - if (!m_handle.handle) - return ""; - - std::string header; - char* string = m_handle.get_header(CAddonBase::m_interface->toKodi->kodiBase, m_handle.handle); - if (string != nullptr) - { - header = string; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - string); - } - return header; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @brief Get the mime type associated with these HTTP headers. - /// - /// @return The mime type - /// - std::string GetMimeType() const - { - using namespace ::kodi::addon; - - if (!m_handle.handle) - return ""; - - std::string protoLine; - char* string = - m_handle.get_mime_type(CAddonBase::m_interface->toKodi->kodiBase, m_handle.handle); - if (string != nullptr) - { - protoLine = string; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - string); - } - return protoLine; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @brief Get the charset associated with these HTTP headers. - /// - /// @return The charset - /// - std::string GetCharset() const - { - using namespace ::kodi::addon; - - if (!m_handle.handle) - return ""; - - std::string protoLine; - char* string = m_handle.get_charset(CAddonBase::m_interface->toKodi->kodiBase, m_handle.handle); - if (string != nullptr) - { - protoLine = string; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - string); - } - return protoLine; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @brief The protocol line associated with these HTTP headers. - /// - /// @return The protocol line - /// - std::string GetProtoLine() const - { - using namespace ::kodi::addon; - - if (!m_handle.handle) - return ""; - - std::string protoLine; - char* string = - m_handle.get_proto_line(CAddonBase::m_interface->toKodi->kodiBase, m_handle.handle); - if (string != nullptr) - { - protoLine = string; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - string); - } - return protoLine; - } - //-------------------------------------------------------------------------- - - ///@} - - KODI_HTTP_HEADER m_handle; -}; -///@} -//---------------------------------------------------------------------------- - -//============================================================================== -/// @defgroup cpp_kodi_vfs_CDirEntry class CDirEntry -/// @ingroup cpp_kodi_vfs_Defs -/// -/// @brief **Virtual file server directory entry**\n -/// This class is used as an entry for files and folders in -/// kodi::vfs::GetDirectory(). -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// ... -/// -/// std::vector items; -/// kodi::vfs::GetDirectory("special://temp", "", items); -/// -/// fprintf(stderr, "Directory have %lu entries\n", items.size()); -/// for (unsigned long i = 0; i < items.size(); i++) -/// { -/// char buff[20]; -/// time_t now = items[i].DateTime(); -/// strftime(buff, 20, "%Y-%m-%d %H:%M:%S", gmtime(&now)); -/// fprintf(stderr, " - %04lu -- Folder: %s -- Name: %s -- Path: %s -- Time: %s\n", -/// i+1, -/// items[i].IsFolder() ? "yes" : "no ", -/// items[i].Label().c_str(), -/// items[i].Path().c_str(), -/// buff); -/// } -/// ~~~~~~~~~~~~~ -/// -/// It has the header @ref Filesystem.h "#include " be included -/// to enjoy it. -/// -//@{ -class ATTRIBUTE_HIDDEN CDirEntry -{ -public: - //============================================================================ - /// @ingroup cpp_kodi_vfs_CDirEntry - /// @brief Constructor for VFS directory entry - /// - /// @param[in] label [opt] Name to use for entry - /// @param[in] path [opt] Used path of the entry - /// @param[in] folder [opt] If set entry used as folder - /// @param[in] size [opt] If used as file, his size defined there - /// @param[in] dateTime [opt] Date time of the entry - /// - CDirEntry(const std::string& label = "", - const std::string& path = "", - bool folder = false, - int64_t size = -1, - time_t dateTime = 0) - : m_label(label), m_path(path), m_folder(folder), m_size(size), m_dateTime(dateTime) - { - } - //---------------------------------------------------------------------------- - - //============================================================================ - // @note Not for addon development itself needed, thats why below is - // disabled for doxygen! - // - // @ingroup cpp_kodi_vfs_CDirEntry - // @brief Constructor to create own copy - // - // @param[in] dirEntry pointer to own class type - // - explicit CDirEntry(const VFSDirEntry& dirEntry) - : m_label(dirEntry.label ? dirEntry.label : ""), - m_path(dirEntry.path ? dirEntry.path : ""), - m_folder(dirEntry.folder), - m_size(dirEntry.size), - m_dateTime(dirEntry.date_time) - { - } - //---------------------------------------------------------------------------- - - /// @defgroup cpp_kodi_vfs_CDirEntry_Help *Value Help* - /// @ingroup cpp_kodi_vfs_CDirEntry - /// -------------------------------------------------------------------------- - /// - /// The following table contains values that can be set with @ref cpp_kodi_vfs_CDirEntry : - /// | Name | Type | Set call | Get call | Clear call | - /// |------|------|----------|----------|------------| - /// | **Directory entry name** | `std::string` | @ref CDirEntry::SetLabel "SetLabel" | @ref CDirEntry::Label "Label" | | - /// | **Title of entry** | `std::string` | @ref CDirEntry::SetTitle "SetTitle" | @ref CDirEntry::Title "Title" | | - /// | **Path of the entry** | `std::string` | @ref CDirEntry::SetPath "SetPath" | @ref CDirEntry::Path "Path" | | - /// | **Entry is folder** | `bool` | @ref CDirEntry::SetFolder "SetFolder" | @ref CDirEntry::IsFolder "IsFolder" | | - /// | **The size of the file** | `int64_t` | @ref CDirEntry::SetSize "SetSize" | @ref CDirEntry::Size "Size" | | - /// | **File time and date** | `time_t` | @ref CDirEntry::SetDateTime "SetDateTime" | @ref CDirEntry::DateTime "DateTime" | | - /// | **Property entries** | `std::string, std::string` | @ref CDirEntry::AddProperty "AddProperty" | @ref CDirEntry::GetProperties "GetProperties" | @ref CDirEntry::ClearProperties "ClearProperties" - /// - - /// @addtogroup cpp_kodi_vfs_CDirEntry - /// @copydetails cpp_kodi_vfs_CDirEntry_Help - //@{ - - //============================================================================ - /// @brief Get the directory entry name. - /// - /// @return Name of the entry - /// - const std::string& Label(void) const { return m_label; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get the optional title of entry. - /// - /// @return Title of the entry, if exists - /// - const std::string& Title(void) const { return m_title; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get the path of the entry. - /// - /// @return File system path of the entry - /// - const std::string& Path(void) const { return m_path; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Used to check entry is folder. - /// - /// @return true if entry is a folder - /// - bool IsFolder(void) const { return m_folder; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief If file, the size of the file. - /// - /// @return Defined file size - /// - int64_t Size(void) const { return m_size; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get file time and date for a new entry. - /// - /// @return The with time_t defined date and time of file - /// - time_t DateTime() { return m_dateTime; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Set the label name. - /// - /// @param[in] label name of entry - /// - void SetLabel(const std::string& label) { m_label = label; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Set the title name. - /// - /// @param[in] title title name of entry - /// - void SetTitle(const std::string& title) { m_title = title; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Set the path of the entry. - /// - /// @param[in] path path of entry - /// - void SetPath(const std::string& path) { m_path = path; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Set the entry defined as folder. - /// - /// @param[in] folder If true becomes entry defined as folder - /// - void SetFolder(bool folder) { m_folder = folder; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Set a file size for a new entry. - /// - /// @param[in] size Size to set for dir entry - /// - void SetSize(int64_t size) { m_size = size; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Set file time and date for a new entry. - /// - /// @param[in] dateTime The with time_t defined date and time of file - /// - void SetDateTime(time_t dateTime) { m_dateTime = dateTime; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Add a by string defined property entry to directory entry. - /// - /// @note A property can be used to add some special information about a file - /// or directory entry, this can be used on other places to do the right work - /// of them. - /// - /// @param[in] id Identification name of property - /// @param[in] value The property value to add by given id - /// - void AddProperty(const std::string& id, const std::string& value) { m_properties[id] = value; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Clear all present properties. - /// - void ClearProperties() { m_properties.clear(); } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get the present properties list on directory entry. - /// - /// @return map with all present properties - /// - const std::map& GetProperties() const { return m_properties; } - //---------------------------------------------------------------------------- - - //@} - -private: - std::string m_label; - std::string m_title; - std::string m_path; - std::map m_properties; - bool m_folder; - int64_t m_size; - time_t m_dateTime; -}; -//@} -//------------------------------------------------------------------------------ - -//}}} - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" Directory related functions -//{{{ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_Directory -/// @brief Make a directory. -/// -/// The kodi::vfs::CreateDirectory() function shall create a -/// new directory with name path. -/// -/// The newly created directory shall be an empty directory. -/// -/// @param[in] path Path to the directory. -/// @return Upon successful completion, CreateDirectory() shall return true. -/// Otherwise false shall be returned, no directory shall be created. -/// -/// -/// ------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string directory = "C:\\my_dir"; -/// bool ret = kodi::vfs::CreateDirectory(directory); -/// fprintf(stderr, "Directory '%s' successfull created: %s\n", directory.c_str(), ret ? "yes" : "no"); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN CreateDirectory(const std::string& path) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->create_directory( - CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_Directory -/// @brief Verifying the Existence of a Directory. -/// -/// The kodi::vfs::DirectoryExists() method determines whether -/// a specified folder exists. -/// -/// @param[in] path Path to the directory. -/// @return True when it exists, false otherwise. -/// -/// -/// ------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string directory = "C:\\my_dir"; -/// bool ret = kodi::vfs::DirectoryExists(directory); -/// fprintf(stderr, "Directory '%s' present: %s\n", directory.c_str(), ret ? "yes" : "no"); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN DirectoryExists(const std::string& path) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->directory_exists( - CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_Directory -/// @brief Removes a directory. -/// -/// The kodi::vfs::RemoveDirectory() function shall remove a -/// directory whose name is given by path. -/// -/// @param[in] path Path to the directory. -/// @return Upon successful completion, the function RemoveDirectory() shall -/// return true. Otherwise, false shall be returned, and errno set -/// to indicate the error. If false is returned, the named directory -/// shall not be changed. -/// -/// -/// ------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// bool ret = kodi::vfs::RemoveDirectory("C:\\my_dir"); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN RemoveDirectory(const std::string& path) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->remove_directory( - CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_Directory -/// @brief Lists a directory. -/// -/// Return the list of files and directories which have been found in the -/// specified directory and which respect the given constraint. -/// -/// It can handle the normal OS dependent paths and also the special virtual -/// filesystem from Kodi what starts with \b special://. -/// -/// @param[in] path The path in which the files and directories are located. -/// @param[in] mask Mask to filter out requested files, e.g. "*.avi|*.mpg" to -/// files with this ending. -/// @param[out] items The returned list directory entries. -/// @return True if listing was successful, false otherwise. -/// -/// -/// ------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// std::vector items; -/// kodi::vfs::GetDirectory("special://temp", "", items); -/// -/// fprintf(stderr, "Directory have %lu entries\n", items.size()); -/// for (unsigned long i = 0; i < items.size(); i++) -/// { -/// fprintf(stderr, " - %04lu -- Folder: %s -- Name: %s -- Path: %s\n", -/// i+1, -/// items[i].IsFolder() ? "yes" : "no ", -/// items[i].Label().c_str(), -/// items[i].Path().c_str()); -/// } -/// ~~~~~~~~~~~~~ -inline bool ATTRIBUTE_HIDDEN GetDirectory(const std::string& path, - const std::string& mask, - std::vector& items) -{ - using namespace kodi::addon; - - VFSDirEntry* dir_list = nullptr; - unsigned int num_items = 0; - if (CAddonBase::m_interface->toKodi->kodi_filesystem->get_directory( - CAddonBase::m_interface->toKodi->kodiBase, path.c_str(), mask.c_str(), &dir_list, - &num_items)) - { - if (dir_list) - { - for (unsigned int i = 0; i < num_items; ++i) - items.emplace_back(dir_list[i]); - - CAddonBase::m_interface->toKodi->kodi_filesystem->free_directory( - CAddonBase::m_interface->toKodi->kodiBase, dir_list, num_items); - } - - return true; - } - return false; -} -//------------------------------------------------------------------------------ - -//}}} - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" File related functions -//{{{ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_File -/// @brief Check if a file exists. -/// -/// @param[in] filename The filename to check. -/// @param[in] usecache Check in file cache. -/// @return true if the file exists false otherwise. -/// -/// -/// ------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// bool exists = kodi::vfs::FileExists("special://temp/kodi.log"); -/// fprintf(stderr, "Log file should be always present, is it present? %s\n", exists ? "yes" : "no"); -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN FileExists(const std::string& filename, bool usecache = false) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->file_exists( - CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), usecache); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_File -/// @brief Get file status. -/// -/// These function return information about a file. Execute (search) -/// permission is required on all of the directories in path that -/// lead to the file. -/// -/// The call return a stat structure, which contains the on -/// @ref cpp_kodi_vfs_Defs_FileStatus defined values. -/// -/// @warning Not all of the OS file systems implement all of the time fields. -/// -/// @param[in] filename The filename to read the status from. -/// @param[out] buffer The file status is written into this buffer. -/// @return On success, trur is returned. On error, false is returned -/// -/// -/// @copydetails cpp_kodi_vfs_Defs_FileStatus_Help -/// -/// ------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// kodi::vfs::FileStatus statFile; -/// int ret = kodi::vfs::StatFile("special://temp/kodi.log", statFile); -/// fprintf(stderr, "deviceId (ID of device containing file) = %u\n" -/// "size (total size, in bytes) = %lu\n" -/// "accessTime (time of last access) = %lu\n" -/// "modificationTime (time of last modification) = %lu\n" -/// "statusTime (time of last status change) = %lu\n" -/// "isDirectory (The stat url is a directory) = %s\n" -/// "isSymLink (The stat url is a symbolic link) = %s\n" -/// "Return value = %i\n", -/// statFile.GetDeviceId(), -/// statFile.GetSize(), -/// statFile.GetAccessTime(), -/// statFile.GetModificationTime(), -/// statFile.GetStatusTime(), -/// statFile.GetIsDirectory() ? "true" : "false", -/// statFile.GetIsSymLink() ? "true" : "false", -/// ret); -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN StatFile(const std::string& filename, kodi::vfs::FileStatus& buffer) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->stat_file( - CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), buffer); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_File -/// @brief Deletes a file. -/// -/// @param[in] filename The filename to delete. -/// @return The file was successfully deleted. -/// -/// -/// ------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// #include -/// #include -/// ... -/// std::string filename; -/// if (kodi::gui::DialogFileBrowser::ShowAndGetFile("local", "", -/// "Test File selection and delete of them!", -/// filename)) -/// { -/// bool successed = kodi::vfs::DeleteFile(filename); -/// if (!successed) -/// kodi::gui::DialogOK::ShowAndGetInput("Error", "Delete of File", filename, "failed!"); -/// else -/// kodi::gui::DialogOK::ShowAndGetInput("Information", "Delete of File", filename, "successfull done."); -/// } -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN DeleteFile(const std::string& filename) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->delete_file( - CAddonBase::m_interface->toKodi->kodiBase, filename.c_str()); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_File -/// @brief Rename a file name. -/// -/// @param[in] filename The filename to copy. -/// @param[in] newFileName The new filename -/// @return true if successfully renamed -/// -/// -inline bool ATTRIBUTE_HIDDEN RenameFile(const std::string& filename, const std::string& newFileName) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->rename_file( - CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), newFileName.c_str()); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_File -/// @brief Copy a file from source to destination. -/// -/// @param[in] filename The filename to copy. -/// @param[in] destination The destination to copy file to -/// @return true if successfully copied -/// -/// -inline bool ATTRIBUTE_HIDDEN CopyFile(const std::string& filename, const std::string& destination) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->copy_file( - CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), destination.c_str()); -} -//------------------------------------------------------------------------------ - -//}}} - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" General filesystem functions -//{{{ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Retrieve MD5sum of a file. -/// -/// @param[in] path Path to the file to MD5sum -/// @return MD5 sum of the file -/// -/// -/// ------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// #include -/// ... -/// std::string md5; -/// std::string filename; -/// if (kodi::gui::DialogFileBrowser::ShowAndGetFile("local", "*.avi|*.mpg|*.mp4", -/// "Test File selection to get MD5", -/// filename)) -/// { -/// md5 = kodi::vfs::GetFileMD5(filename); -/// fprintf(stderr, "MD5 of file '%s' is %s\n", md5.c_str(), filename.c_str()); -/// } -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN GetFileMD5(const std::string& path) -{ - using namespace kodi::addon; - - std::string strReturn; - char* strMd5 = CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_md5( - CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); - if (strMd5 != nullptr) - { - if (std::strlen(strMd5)) - strReturn = strMd5; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, strMd5); - } - return strReturn; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Returns a thumb cache filename. -/// -/// @param[in] filename Path to file -/// @return Cache filename -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// #include -/// ... -/// std::string thumb; -/// std::string filename; -/// if (kodi::gui::DialogFileBrowser::ShowAndGetFile("local", "*.avi|*.mpg|*.mp4", -/// "Test File selection to get Thumnail", -/// filename)) -/// { -/// thumb = kodi::vfs::GetCacheThumbName(filename); -/// fprintf(stderr, "Thumb name of file '%s' is %s\n", thumb.c_str(), filename.c_str()); -/// } -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN GetCacheThumbName(const std::string& filename) -{ - using namespace kodi::addon; - - std::string strReturn; - char* strThumbName = CAddonBase::m_interface->toKodi->kodi_filesystem->get_cache_thumb_name( - CAddonBase::m_interface->toKodi->kodiBase, filename.c_str()); - if (strThumbName != nullptr) - { - if (std::strlen(strThumbName)) - strReturn = strThumbName; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - strThumbName); - } - return strReturn; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Make filename valid. -/// -/// Function to replace not valid characters with '_'. It can be also -/// compared with original before in a own loop until it is equal -/// (no invalid characters). -/// -/// @param[in] filename Filename to check and fix -/// @return The legal filename -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string fileName = "///\\jk???lj????.mpg"; -/// std::string legalName = kodi::vfs::MakeLegalFileName(fileName); -/// fprintf(stderr, "Legal name of '%s' is '%s'\n", fileName.c_str(), legalName.c_str()); -/// -/// /* Returns as legal: 'jk___lj____.mpg' */ -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN MakeLegalFileName(const std::string& filename) -{ - using namespace kodi::addon; - - std::string strReturn; - char* strLegalFileName = CAddonBase::m_interface->toKodi->kodi_filesystem->make_legal_filename( - CAddonBase::m_interface->toKodi->kodiBase, filename.c_str()); - if (strLegalFileName != nullptr) - { - if (std::strlen(strLegalFileName)) - strReturn = strLegalFileName; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - strLegalFileName); - } - return strReturn; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Make directory name valid. -/// -/// Function to replace not valid characters with '_'. It can be also -/// compared with original before in a own loop until it is equal -/// (no invalid characters). -/// -/// @param[in] path Directory name to check and fix -/// @return The legal directory name -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string path = "///\\jk???lj????\\hgjkg"; -/// std::string legalPath = kodi::vfs::MakeLegalPath(path); -/// fprintf(stderr, "Legal name of '%s' is '%s'\n", path.c_str(), legalPath.c_str()); -/// -/// /* Returns as legal: '/jk___lj____/hgjkg' */ -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN MakeLegalPath(const std::string& path) -{ - using namespace kodi::addon; - - std::string strReturn; - char* strLegalPath = CAddonBase::m_interface->toKodi->kodi_filesystem->make_legal_path( - CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); - if (strLegalPath != nullptr) - { - if (std::strlen(strLegalPath)) - strReturn = strLegalPath; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - strLegalPath); - } - return strReturn; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Returns the translated path. -/// -/// @param[in] source String or unicode - Path to format -/// @return A human-readable string suitable for logging -/// -/// @note Only useful if you are coding for both Linux and Windows. e.g. -/// Converts 'special://masterprofile/script_data' -> -/// '/home/user/.kodi/UserData/script_data' on Linux. -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string path = kodi::vfs::TranslateSpecialProtocol("special://masterprofile/script_data"); -/// fprintf(stderr, "Translated path is: %s\n", path.c_str()); -/// ... -/// ~~~~~~~~~~~~~ -/// or -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// fprintf(stderr, "Directory 'special://temp' is '%s'\n", kodi::vfs::TranslateSpecialProtocol("special://temp").c_str()); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN TranslateSpecialProtocol(const std::string& source) -{ - using namespace kodi::addon; - - std::string strReturn; - char* protocol = CAddonBase::m_interface->toKodi->kodi_filesystem->translate_special_protocol( - CAddonBase::m_interface->toKodi->kodiBase, source.c_str()); - if (protocol != nullptr) - { - if (std::strlen(protocol)) - strReturn = protocol; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - protocol); - } - return strReturn; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Retrieves information about the amount of space that is available on -/// a disk volume. -/// -/// Path can be also with Kodi's special protocol. -/// -/// @param[in] path Path for where to check -/// @param[out] capacity The total number of bytes in the file system -/// @param[out] free The total number of free bytes in the file system -/// @param[out] available The total number of free bytes available to a -/// non-privileged process -/// @return true if successfully done and set -/// -/// @warning This only works with paths belonging to OS. If "special://" -/// is used, it must point to a place on your own OS. -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include // for ULLONG_MAX -/// #include -/// ... -/// std::string path = "special://temp"; -/// uint64_t capacity = ULLONG_MAX; -/// uint64_t free = ULLONG_MAX; -/// uint64_t available = ULLONG_MAX; -/// kodi::vfs::GetDiskSpace(path, capacity, free, available); -/// fprintf(stderr, "Path '%s' sizes:\n", path.c_str()); -/// fprintf(stderr, " - capacity: %lu MByte\n", capacity / 1024 / 1024); -/// fprintf(stderr, " - free: %lu MByte\n", free / 1024 / 1024); -/// fprintf(stderr, " - available: %lu MByte\n", available / 1024 / 1024); -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN GetDiskSpace(const std::string& path, - uint64_t& capacity, - uint64_t& free, - uint64_t& available) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->get_disk_space( - CAddonBase::m_interface->toKodi->kodiBase, path.c_str(), &capacity, &free, &available); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Return the file name from given complate path string. -/// -/// @param[in] path The complete path include file and directory -/// @return Filename from path -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string fileName = kodi::vfs::GetFileName("special://temp/kodi.log"); -/// fprintf(stderr, "File name is '%s'\n", fileName.c_str()); -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN GetFileName(const std::string& path) -{ - /* find the last slash */ - const size_t slash = path.find_last_of("/\\"); - return path.substr(slash + 1); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Return the directory name from given complate path string. -/// -/// @param[in] path The complete path include file and directory -/// @return Directory name from path -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string dirName = kodi::vfs::GetDirectoryName("special://temp/kodi.log"); -/// fprintf(stderr, "Directory name is '%s'\n", dirName.c_str()); -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN GetDirectoryName(const std::string& path) -{ - // Will from a full filename return the directory the file resides in. - // Keeps the final slash at end and possible |option=foo options. - - size_t iPosSlash = path.find_last_of("/\\"); - if (iPosSlash == std::string::npos) - return ""; // No slash, so no path (ignore any options) - - size_t iPosBar = path.rfind('|'); - if (iPosBar == std::string::npos) - return path.substr(0, iPosSlash + 1); // Only path - - return path.substr(0, iPosSlash + 1) + path.substr(iPosBar); // Path + options -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Remove the slash on given path name. -/// -/// @param[in,out] path The complete path -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string dirName = "special://temp/"; -/// kodi::vfs::RemoveSlashAtEnd(dirName); -/// fprintf(stderr, "Directory name is '%s'\n", dirName.c_str()); -/// ~~~~~~~~~~~~~ -/// -inline void ATTRIBUTE_HIDDEN RemoveSlashAtEnd(std::string& path) -{ - if (!path.empty()) - { - char last = path[path.size() - 1]; - if (last == '/' || last == '\\') - path.erase(path.size() - 1); - } -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Return a size aligned to the chunk size at least as large as the -/// chunk size. -/// -/// @param[in] chunk The chunk size -/// @param[in] minimum The minimum size (or maybe the minimum number of chunks?) -/// @return The aligned size -/// -inline unsigned int ATTRIBUTE_HIDDEN GetChunkSize(unsigned int chunk, unsigned int minimum) -{ - if (chunk) - return chunk * ((minimum + chunk - 1) / chunk); - else - return minimum; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Checks the given path contains a known internet protocol. -/// -/// About following protocols are the path checked: -/// | Protocol | Return true condition | Protocol | Return true condition -/// |----------|-----------------------|----------|----------------------- -/// | **dav** | strictCheck = true | **rtmps** | always -/// | **davs** | strictCheck = true | **rtmpt** | always -/// | **ftp** | strictCheck = true | **rtmpte** | always -/// | **ftps** | strictCheck = true | **rtp** | always -/// | **http** | always | **rtsp** | always -/// | **https**| always | **sdp** | always -/// | **mms** | always | **sftp** | strictCheck = true -/// | **mmsh** | always | **stack** | always -/// | **mmst** | always | **tcp** | always -/// | **rtmp** | always | **udp** | always -/// | **rtmpe**| always | | | -/// -/// @param[in] path To checked path/URL -/// @param[in] strictCheck [opt] If True the set of protocols used will be -/// extended to include ftp, ftps, dav, davs and sftp. -/// @return True if path is to a internet stream, false otherwise -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// // Check should return false -/// fprintf(stderr, "File name 1 is internet stream '%s' (should no)\n", -/// kodi::vfs::IsInternetStream("D:/my-file.mkv") ? "yes" : "no"); -/// -/// // Check should return true -/// fprintf(stderr, "File name 2 is internet stream '%s' (should yes)\n", -/// kodi::vfs::IsInternetStream("http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4") ? "yes" : "no"); -/// -/// // Check should return false -/// fprintf(stderr, "File name 1 is internet stream '%s' (should no)\n", -/// kodi::vfs::IsInternetStream("ftp://do-somewhere.com/the-file.mkv") ? "yes" : "no", false); -/// -/// // Check should return true -/// fprintf(stderr, "File name 1 is internet stream '%s' (should yes)\n", -/// kodi::vfs::IsInternetStream("ftp://do-somewhere.com/the-file.mkv") ? "yes" : "no", true); -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN IsInternetStream(const std::string& path, bool strictCheck = false) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->is_internet_stream( - CAddonBase::m_interface->toKodi->kodiBase, path.c_str(), strictCheck); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Checks whether the specified path refers to a local network. -/// -/// In difference to @ref IsHostOnLAN() include this more deeper checks where -/// also handle Kodi's special protocol and stacks. -/// -/// @param[in] path To checked path -/// @return True if path is on LAN, false otherwise -/// -/// @note Check includes @ref IsHostOnLAN() too. -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// // Check should return true -/// bool lan = kodi::vfs::IsOnLAN("smb://path/to/file"); -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN IsOnLAN(const std::string& path) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->is_on_lan( - CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Checks specified path for external network. -/// -/// @param[in] path To checked path -/// @return True if path is remote, false otherwise -/// -/// @note This does not apply to the local network. -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// // Check should return true -/// bool remote = kodi::vfs::IsRemote("http://path/to/file"); -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN IsRemote(const std::string& path) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->is_remote( - CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Checks whether the given path refers to the own system. -/// -/// @param[in] path To checked path -/// @return True if path is local, false otherwise -/// -inline bool ATTRIBUTE_HIDDEN IsLocal(const std::string& path) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->is_local( - CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @ingroup cpp_kodi_vfs_General -/// @brief Checks specified path is a regular URL, e.g. "someprotocol://path/to/file" -/// -/// @return True if file item is URL, false otherwise -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// -/// bool isURL; -/// // Check should return true -/// isURL = kodi::vfs::IsURL("someprotocol://path/to/file"); -/// -/// // Check should return false -/// isURL = kodi::vfs::IsURL("/path/to/file"); -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN IsURL(const std::string& path) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->is_url( - CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); -} -//-------------------------------------------------------------------------- - -//============================================================================ -/// @ingroup cpp_kodi_vfs_General -/// @brief To get HTTP header information. -/// -/// @param[in] url URL source of the data -/// @param[out] header The @ref cpp_kodi_vfs_Defs_HttpHeader -/// @return true if successfully done, otherwise false -/// -/// -/// ------------------------------------------------------------------------ -/// -/// @copydetails cpp_kodi_vfs_Defs_HttpHeader_Help -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// kodi::vfs::HttpHeader header; -/// bool ret = kodi::vfs::GetHttpHeader(url, header); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN GetHttpHeader(const std::string& url, HttpHeader& header) -{ - using namespace ::kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_filesystem->get_http_header( - CAddonBase::m_interface->toKodi->kodiBase, url.c_str(), &header.m_handle); -} -//---------------------------------------------------------------------------- - -//============================================================================ -/// @ingroup cpp_kodi_vfs_General -/// @brief Get file mime type. -/// -/// @param[in] url URL source of the data -/// @param[out] mimeType the mime type of the URL -/// @param[in] useragent to be used when retrieving the MimeType [opt] -/// @return true if successfully done, otherwise false -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string mimeType;. -/// if (kodi::vfs::GetMimeType(url, mimeType)) -/// fprintf(stderr, "The mime type is '%s'\n", mimeType.c_str()); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN GetMimeType(const std::string& url, - std::string& mimeType, - const std::string& useragent = "") -{ - using namespace ::kodi::addon; - - char* cMimeType = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_filesystem->get_mime_type( - CAddonBase::m_interface->toKodi->kodiBase, url.c_str(), &cMimeType, useragent.c_str()); - if (cMimeType != nullptr) - { - mimeType = cMimeType; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - cMimeType); - } - return ret; -} -//---------------------------------------------------------------------------- - -//============================================================================ -/// @ingroup cpp_kodi_vfs_General -/// @brief Get file content-type. -/// -/// @param[in] url URL source of the data -/// @param[out] content The returned type -/// @param[in] useragent to be used when retrieving the MimeType [opt] -/// @return true if successfully done, otherwise false -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string content;. -/// if (kodi::vfs::GetContentType(url, content)) -/// fprintf(stderr, "The content type is '%s'\n", content.c_str()); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN GetContentType(const std::string& url, - std::string& content, - const std::string& useragent = "") -{ - using namespace ::kodi::addon; - - char* cContent = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_filesystem->get_content_type( - CAddonBase::m_interface->toKodi->kodiBase, url.c_str(), &cContent, useragent.c_str()); - if (cContent != nullptr) - { - content = cContent; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - cContent); - } - return ret; -} -//---------------------------------------------------------------------------- - -//============================================================================ -/// @ingroup cpp_kodi_vfs_General -/// @brief Get cookies stored by CURL in RFC 2109 format. -/// -/// @param[in] url URL source of the data -/// @param[out] cookies The text list of available cookies -/// @return true if successfully done, otherwise false -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string url = ""; -/// std::string cookies; -/// bool ret = kodi::vfs::GetCookies(url, cookies); -/// fprintf(stderr, "Cookies from URL '%s' are '%s' (return was %s)\n", -/// url.c_str(), cookies.c_str(), ret ? "true" : "false"); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN GetCookies(const std::string& url, std::string& cookies) -{ - using namespace ::kodi::addon; - - char* cCookies = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_filesystem->get_cookies( - CAddonBase::m_interface->toKodi->kodiBase, url.c_str(), &cCookies); - if (cCookies != nullptr) - { - cookies = cCookies; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - cCookies); - } - return ret; -} -//---------------------------------------------------------------------------- - -//}}} - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" CFile class -//{{{ - -//============================================================================== -/// @defgroup cpp_kodi_vfs_CFile 4. class CFile -/// @ingroup cpp_kodi_vfs -/// -/// @brief **Creatable class for virtual file server control**\n -/// To perform file read/write with Kodi's filesystem parts. -/// -/// CFile is the class used for handling Files in Kodi. This class can be used -/// for creating, reading, writing and modifying files. It directly provides unbuffered, binary disk input/output services -/// -/// It has the header @ref Filesystem.h "#include " be included -/// to enjoy it. -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// ... -/// -/// /* Create the needed file handle class */ -/// kodi::vfs::CFile myFile(); -/// -/// /* In this example we use the user path for the add-on */ -/// std::string file = kodi::GetUserPath() + "/myFile.txt"; -/// -/// /* Now create and open the file or overwrite if present */ -/// myFile.OpenFileForWrite(file, true); -/// -/// const char* str = "I love Kodi!"; -/// -/// /* write string */ -/// myFile.Write(str, sizeof(str)); -/// -/// /* On this way the Close() is not needed to call, becomes done from destructor */ -/// -/// ~~~~~~~~~~~~~ -/// -//@{ -class ATTRIBUTE_HIDDEN CFile -{ -public: - //============================================================================ - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Construct a new, unopened file. - /// - CFile() = default; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_vfs_CFile - /// @brief `Close()` is called from the destructor, so explicitly - /// closing the file isn't required. - /// - virtual ~CFile() { Close(); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Open the file with filename via Kodi's @ref cpp_kodi_vfs_CFile - /// "CFile". Needs to be closed by calling Close() when done. - /// - /// @param[in] filename The filename to open. - /// @param[in] flags [opt] The flags to pass, see @ref OpenFileFlags - /// @return True on success or false on failure - /// - bool OpenFile(const std::string& filename, unsigned int flags = 0) - { - using namespace kodi::addon; - - Close(); - m_file = CAddonBase::m_interface->toKodi->kodi_filesystem->open_file( - CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), flags); - return m_file != nullptr; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Open the file with filename via Kodi's @ref cpp_kodi_vfs_CFile - /// "CFile" in write mode. Needs to be closed by calling Close() when - /// done. - /// - /// @note Related folders becomes created if not present. - /// - /// @param[in] filename The filename to open. - /// @param[in] overwrite True to overwrite, false otherwise. - /// @return True on success or false on failure - /// - bool OpenFileForWrite(const std::string& filename, bool overwrite = false) - { - using namespace kodi::addon; - - Close(); - - // Try to open the file. If it fails, check if we need to create the directory first - // This way we avoid checking if the directory exists every time - m_file = CAddonBase::m_interface->toKodi->kodi_filesystem->open_file_for_write( - CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), overwrite); - if (!m_file) - { - std::string cacheDirectory = kodi::vfs::GetDirectoryName(filename); - if (CAddonBase::m_interface->toKodi->kodi_filesystem->directory_exists( - CAddonBase::m_interface->toKodi->kodiBase, cacheDirectory.c_str()) || - CAddonBase::m_interface->toKodi->kodi_filesystem->create_directory( - CAddonBase::m_interface->toKodi->kodiBase, cacheDirectory.c_str())) - m_file = CAddonBase::m_interface->toKodi->kodi_filesystem->open_file_for_write( - CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), overwrite); - } - return m_file != nullptr; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Check file is opened. - /// - /// @return True on open or false on closed or failure - /// - bool IsOpen() const { return m_file != nullptr; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Close an open file. - /// - void Close() - { - using namespace kodi::addon; - - if (!m_file) - return; - CAddonBase::m_interface->toKodi->kodi_filesystem->close_file( - CAddonBase::m_interface->toKodi->kodiBase, m_file); - m_file = nullptr; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Create a Curl representation - /// - /// @param[in] url The URL of the Type. - /// @return True on success or false on failure - /// - bool CURLCreate(const std::string& url) - { - using namespace kodi::addon; - - m_file = CAddonBase::m_interface->toKodi->kodi_filesystem->curl_create( - CAddonBase::m_interface->toKodi->kodiBase, url.c_str()); - return m_file != nullptr; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Add options to the curl file created with CURLCreate. - /// - /// @param[in] type Option type to set, see @ref CURLOptiontype - /// @param[in] name Name of the option - /// @param[in] value Value of the option - /// @return True on success or false on failure - /// - bool CURLAddOption(CURLOptiontype type, const std::string& name, const std::string& value) - { - using namespace kodi::addon; - - if (!m_file) - { - kodi::Log(ADDON_LOG_ERROR, "kodi::vfs::CURLCreate(...) needed to call before!"); - return false; - } - return CAddonBase::m_interface->toKodi->kodi_filesystem->curl_add_option( - CAddonBase::m_interface->toKodi->kodiBase, m_file, type, name.c_str(), value.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Open the curl file created with CURLCreate. - /// - /// @param[in] flags [opt] The flags to pass, see @ref OpenFileFlags - /// @return True on success or false on failure - /// - bool CURLOpen(unsigned int flags = 0) - { - using namespace kodi::addon; - - if (!m_file) - { - kodi::Log(ADDON_LOG_ERROR, "kodi::vfs::CURLCreate(...) needed to call before!"); - return false; - } - return CAddonBase::m_interface->toKodi->kodi_filesystem->curl_open( - CAddonBase::m_interface->toKodi->kodiBase, m_file, flags); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Read from an open file. - /// - /// @param[in] ptr The buffer to store the data in. - /// @param[in] size The size of the buffer. - /// @return number of successfully read bytes if any bytes were read and - /// stored in buffer, zero if no bytes are available to read (end of - /// file was reached) or undetectable error occur, -1 in case of any - /// explicit error - /// - ssize_t Read(void* ptr, size_t size) - { - using namespace kodi::addon; - - if (!m_file) - return -1; - return CAddonBase::m_interface->toKodi->kodi_filesystem->read_file( - CAddonBase::m_interface->toKodi->kodiBase, m_file, ptr, size); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Read a string from an open file. - /// - /// @param[out] line The buffer to store the data in. - /// @return True when a line was read, false otherwise. - /// - bool ReadLine(std::string& line) - { - using namespace kodi::addon; - - line.clear(); - if (!m_file) - return false; - // TODO: Read 1024 chars into buffer. If file position advanced that many - // chars, we didn't hit a newline. Otherwise, if file position is 1 or 2 - // past the number of bytes read, we read (and skipped) a newline sequence. - char buffer[1025]; - if (CAddonBase::m_interface->toKodi->kodi_filesystem->read_file_string( - CAddonBase::m_interface->toKodi->kodiBase, m_file, buffer, sizeof(buffer))) - { - line = buffer; - return !line.empty(); - } - return false; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Write to a file opened in write mode. - /// - /// @param[in] ptr Pointer to the data to write, converted to a `const void*`. - /// @param[in] size Size of the data to write. - /// @return number of successfully written bytes if any bytes were written, - /// zero if no bytes were written and no detectable error occur,-1 - /// in case of any explicit error - /// - ssize_t Write(const void* ptr, size_t size) - { - using namespace kodi::addon; - - if (!m_file) - return -1; - return CAddonBase::m_interface->toKodi->kodi_filesystem->write_file( - CAddonBase::m_interface->toKodi->kodiBase, m_file, ptr, size); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Flush buffered data. - /// - /// If the given stream was open for writing (or if it was open for updating - /// and the last i/o operation was an output operation) any unwritten data - /// in its output buffer is written to the file. - /// - /// The stream remains open after this call. - /// - /// When a file is closed, either because of a call to close or because the - /// class is destructed, all the buffers associated with it are - /// automatically flushed. - /// - void Flush() - { - using namespace kodi::addon; - - if (!m_file) - return; - CAddonBase::m_interface->toKodi->kodi_filesystem->flush_file( - CAddonBase::m_interface->toKodi->kodiBase, m_file); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Set the file's current position. - /// - /// The whence argument is optional and defaults to SEEK_SET (0) - /// - /// @param[in] position the position that you want to seek to - /// @param[in] whence [optional] offset relative to You can set the value of - /// whence to one of three things: - /// | Value | int | Description | - /// |:--------:|:---:|:----------------------------------------------------| - /// | SEEK_SET | 0 | position is relative to the beginning of the file. This is probably what you had in mind anyway, and is the most commonly used value for whence. - /// | SEEK_CUR | 1 | position is relative to the current file pointer position. So, in effect, you can say, "Move to my current position plus 30 bytes," or, "move to my current position minus 20 bytes." - /// | SEEK_END | 2 | position is relative to the end of the file. Just like SEEK_SET except from the other end of the file. Be sure to use negative values for offset if you want to back up from the end of the file, instead of going past the end into oblivion. - /// - /// @return Returns the resulting offset location as measured in bytes from - /// the beginning of the file. On error, the value -1 is returned. - /// - int64_t Seek(int64_t position, int whence = SEEK_SET) - { - using namespace kodi::addon; - - if (!m_file) - return -1; - return CAddonBase::m_interface->toKodi->kodi_filesystem->seek_file( - CAddonBase::m_interface->toKodi->kodiBase, m_file, position, whence); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Truncate a file to the requested size. - /// - /// @param[in] size The new max size. - /// @return New size? On error, the value -1 is returned. - /// - int Truncate(int64_t size) - { - using namespace kodi::addon; - - if (!m_file) - return -1; - return CAddonBase::m_interface->toKodi->kodi_filesystem->truncate_file( - CAddonBase::m_interface->toKodi->kodiBase, m_file, size); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief The current offset in an open file. - /// - /// @return The requested offset. On error, the value -1 is returned. - /// - int64_t GetPosition() const - { - using namespace kodi::addon; - - if (!m_file) - return -1; - return CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_position( - CAddonBase::m_interface->toKodi->kodiBase, m_file); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Get the file size of an open file. - /// - /// @return The requested size. On error, the value -1 is returned. - /// - int64_t GetLength() const - { - using namespace kodi::addon; - - if (!m_file) - return -1; - return CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_length( - CAddonBase::m_interface->toKodi->kodiBase, m_file); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Checks the file access is on end position. - /// - /// @return If you've reached the end of the file, AtEnd() returns true. - /// - bool AtEnd() const - { - using namespace kodi::addon; - - if (!m_file) - return true; - int64_t length = CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_length( - CAddonBase::m_interface->toKodi->kodiBase, m_file); - int64_t position = CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_position( - CAddonBase::m_interface->toKodi->kodiBase, m_file); - return position >= length; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Get the chunk size for an open file. - /// - /// @return The requested size. On error, the value -1 is returned. - /// - int GetChunkSize() const - { - using namespace kodi::addon; - - if (!m_file) - return -1; - return CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_chunk_size( - CAddonBase::m_interface->toKodi->kodiBase, m_file); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief To check seek possible on current stream by file. - /// - /// @return true if seek possible, false if not - /// - bool IoControlGetSeekPossible() const - { - using namespace kodi::addon; - - if (!m_file) - return false; - return CAddonBase::m_interface->toKodi->kodi_filesystem->io_control_get_seek_possible( - CAddonBase::m_interface->toKodi->kodiBase, m_file); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief To check a running stream on file for state of his cache. - /// - /// @param[in] status Information about current cache status - /// @return true if successfull done, false otherwise - /// - /// - /// @copydetails cpp_kodi_vfs_Defs_CacheStatus_Help - /// - bool IoControlGetCacheStatus(CacheStatus& status) const - { - using namespace kodi::addon; - - if (!m_file) - return false; - return CAddonBase::m_interface->toKodi->kodi_filesystem->io_control_get_cache_status( - CAddonBase::m_interface->toKodi->kodiBase, m_file, status); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Unsigned int with speed limit for caching in bytes per second. - /// - /// @param[in] rate Cache rate size to use - /// @return true if successfull done, false otherwise - /// - bool IoControlSetCacheRate(unsigned int rate) - { - using namespace kodi::addon; - - if (!m_file) - return false; - return CAddonBase::m_interface->toKodi->kodi_filesystem->io_control_set_cache_rate( - CAddonBase::m_interface->toKodi->kodiBase, m_file, rate); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Enable/disable retry within the protocol handler (if supported). - /// - /// @param[in] retry To set the retry, true for use, false for not - /// @return true if successfull done, false otherwise - /// - bool IoControlSetRetry(bool retry) - { - using namespace kodi::addon; - - if (!m_file) - return false; - return CAddonBase::m_interface->toKodi->kodi_filesystem->io_control_set_retry( - CAddonBase::m_interface->toKodi->kodiBase, m_file, retry); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Retrieve a file property. - /// - /// @param[in] type The type of the file property to retrieve the value for - /// @param[in] name The name of a named property value (e.g. Header) - /// @return value of requested property, empty on failure / non-existance - /// - const std::string GetPropertyValue(FilePropertyTypes type, const std::string& name) const - { - using namespace kodi::addon; - - if (!m_file) - { - kodi::Log(ADDON_LOG_ERROR, - "kodi::vfs::CURLCreate(...) needed to call before GetPropertyValue!"); - return ""; - } - std::vector values = GetPropertyValues(type, name); - if (values.empty()) - { - return ""; - } - return values[0]; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Retrieve file property values. - /// - /// @param[in] type The type of the file property values to retrieve the value for - /// @param[in] name The name of the named property (e.g. Header) - /// @return values of requested property, empty vector on failure / non-existance - /// - const std::vector GetPropertyValues(FilePropertyTypes type, - const std::string& name) const - { - using namespace kodi::addon; - - if (!m_file) - { - kodi::Log(ADDON_LOG_ERROR, - "kodi::vfs::CURLCreate(...) needed to call before GetPropertyValues!"); - return std::vector(); - } - int numValues = 0; - char** res(CAddonBase::m_interface->toKodi->kodi_filesystem->get_property_values( - CAddonBase::m_interface->toKodi->kodiBase, m_file, type, name.c_str(), &numValues)); - if (res) - { - std::vector vecReturn; - for (int i = 0; i < numValues; ++i) - { - vecReturn.emplace_back(res[i]); - } - CAddonBase::m_interface->toKodi->free_string_array(CAddonBase::m_interface->toKodi->kodiBase, - res, numValues); - return vecReturn; - } - return std::vector(); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_vfs_CFile - /// @brief Get the current download speed of file if loaded from web. - /// - /// @return The current download speed. - /// - double GetFileDownloadSpeed() const - { - using namespace kodi::addon; - - if (!m_file) - return 0.0; - return CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_download_speed( - CAddonBase::m_interface->toKodi->kodiBase, m_file); - } - //-------------------------------------------------------------------------- - -private: - void* m_file = nullptr; -}; -//@} -//------------------------------------------------------------------------------ - -//}}} - -} /* namespace vfs */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/General.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/General.h deleted file mode 100644 index 878eaa4..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/General.h +++ /dev/null @@ -1,834 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "AddonBase.h" -#include "c-api/general.h" - -#ifdef __cplusplus - -//============================================================================== -/// \ingroup cpp_kodi_Defs -/// @brief For kodi::Version used structure -/// -typedef struct kodi_version_t -{ - /// Application name, normally 'Kodi' - std::string compile_name; - /// Major code version of Kodi - int major; - /// Minor code version of Kodi - int minor; - /// The Revision contains a id and the build date, e.g. 20170706-c6b22fe217-dirty - std::string revision; - /// The version canditate e.g. alpha, beta or release - std::string tag; - /// The revision of tag before - std::string tag_revision; -} kodi_version_t; -//------------------------------------------------------------------------------ - -namespace kodi -{ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief Returns the value of an addon property as a string -/// -/// @param[in] id id of the property that the module needs to access -/// | | Choices are | | -/// |:------------:|:------------:|:------------:| -/// | author | icon | stars | -/// | changelog | id | summary | -/// | description | name | type | -/// | disclaimer | path | version | -/// | fanart | profile | | -/// -/// @return AddOn property as a string -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string addonName = kodi::GetAddonInfo("name"); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN GetAddonInfo(const std::string& id) -{ - using namespace kodi::addon; - - AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; - - std::string strReturn; - char* strMsg = toKodi->kodi->get_addon_info(toKodi->kodiBase, id.c_str()); - if (strMsg != nullptr) - { - if (std::strlen(strMsg)) - strReturn = strMsg; - toKodi->free_string(toKodi->kodiBase, strMsg); - } - return strReturn; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief Opens this Add-Ons settings dialog. -/// -/// @return true if settings were changed and the dialog confirmed, false otherwise. -/// -/// -/// -------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// .. -/// kodi::OpenSettings(); -/// .. -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN OpenSettings() -{ - using namespace kodi::addon; - return CAddonBase::m_interface->toKodi->kodi->open_settings_dialog( - CAddonBase::m_interface->toKodi->kodiBase); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief Returns an addon's localized 'unicode string'. -/// -/// @param[in] labelId string you want to localize -/// @param[in] defaultStr [opt] The default message, also helps to identify -/// the code that is used (default is -/// empty) -/// @return The localized message, or default if the add-on -/// helper fails to return a message -/// -/// @note Label id's \b 30000 to \b 30999 and \b 32000 to \b 32999 are related -/// to the add-on's own included strings from -/// ./resources/language/resource.language.??_??/strings.po -/// All other strings are from Kodi core language files. -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string str = kodi::GetLocalizedString(30005, "Use me as default"); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN GetLocalizedString(uint32_t labelId, - const std::string& defaultStr = "") -{ - using namespace kodi::addon; - - std::string retString = defaultStr; - char* strMsg = CAddonBase::m_interface->toKodi->kodi->get_localized_string( - CAddonBase::m_interface->toKodi->kodiBase, labelId); - if (strMsg != nullptr) - { - if (std::strlen(strMsg)) - retString = strMsg; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, strMsg); - } - return retString; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief Translate a string with an unknown encoding to UTF8. -/// -/// @param[in] stringSrc The string to translate. -/// @param[out] utf8StringDst The translated string. -/// @param[in] failOnBadChar [opt] returns failed if bad character is inside (default is false) -/// @return true if OK -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string ret; -/// if (!kodi::UnknownToUTF8("test string", ret, true)) -/// fprintf(stderr, "Translation to UTF8 failed!\n"); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN UnknownToUTF8(const std::string& stringSrc, - std::string& utf8StringDst, - bool failOnBadChar = false) -{ - using namespace kodi::addon; - - bool ret = false; - char* retString = CAddonBase::m_interface->toKodi->kodi->unknown_to_utf8( - CAddonBase::m_interface->toKodi->kodiBase, stringSrc.c_str(), &ret, failOnBadChar); - if (retString != nullptr) - { - if (ret) - utf8StringDst = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - retString); - } - return ret; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief Returns the active language as a string. -/// -/// @param[in] format Used format of the returned language string -/// | enum code: | Description: | -/// |----------------------:|------------------------------------------------------------| -/// | LANG_FMT_ENGLISH_NAME | full language name in English (Default) | -/// | LANG_FMT_ISO_639_1 | two letter code as defined in ISO 639-1 | -/// | LANG_FMT_ISO_639_2 | three letter code as defined in ISO 639-2/T or ISO 639-2/B | -/// @param[in] region [opt] append the region delimited by "-" of the language (setting) to the returned language string (default is false) -/// @return active language -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string language = kodi::GetLanguage(LANG_FMT_ISO_639_1, false); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN GetLanguage(LangFormats format = LANG_FMT_ENGLISH_NAME, - bool region = false) -{ - using namespace kodi::addon; - - std::string language; - char* retString = CAddonBase::m_interface->toKodi->kodi->get_language( - CAddonBase::m_interface->toKodi->kodiBase, format, region); - if (retString != nullptr) - { - if (std::strlen(retString)) - language = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - retString); - } - return language; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief Writes the C string pointed by format in the GUI. If format includes -/// format specifiers (subsequences beginning with %), the additional arguments -/// following format are formatted and inserted in the resulting string replacing -/// their respective specifiers. -/// -/// After the format parameter, the function expects at least as many additional -/// arguments as specified by format. -/// -/// @param[in] type The message type. -/// | enum code: | Description: | -/// |---------------:|-----------------------------------| -/// | QUEUE_INFO | Show info notification message | -/// | QUEUE_WARNING | Show warning notification message | -/// | QUEUE_ERROR | Show error notification message | -/// @param[in] format The format of the message to pass to display in Kodi. -/// C string that contains the text to be written to the stream. -/// It can optionally contain embedded format specifiers that are -/// replaced by the values specified in subsequent additional -/// arguments and formatted as requested. -/// | specifier | Output | Example -/// |------------|----------------------------------------------------|------------ -/// | d or i | Signed decimal integer | 392 -/// | u | Unsigned decimal integer | 7235 -/// | o | Unsigned octal | 610 -/// | x | Unsigned hexadecimal integer | 7fa -/// | X | Unsigned hexadecimal integer (uppercase) | 7FA -/// | f | Decimal floating point, lowercase | 392.65 -/// | F | Decimal floating point, uppercase | 392.65 -/// | e | Scientific notation (mantissa/exponent), lowercase | 3.9265e+2 -/// | E | Scientific notation (mantissa/exponent), uppercase | 3.9265E+2 -/// | g | Use the shortest representation: %e or %f | 392.65 -/// | G | Use the shortest representation: %E or %F | 392.65 -/// | a | Hexadecimal floating point, lowercase | -0xc.90fep-2 -/// | A | Hexadecimal floating point, uppercase | -0XC.90FEP-2 -/// | c | Character | a -/// | s | String of characters | sample -/// | p | Pointer address | b8000000 -/// | % | A % followed by another % character will write a single % to the stream. | % -/// -/// The length sub-specifier modifies the length of the data type. This is a chart -/// showing the types used to interpret the corresponding arguments with and without -/// length specifier (if a different type is used, the proper type promotion or -/// conversion is performed, if allowed): -/// | length| d i | u o x X | f F e E g G a A | c | s | p | n | -/// |-------|---------------|-----------------------|-----------------|-------|---------|---------|-----------------| -/// | (none)| int | unsigned int | double | int | char* | void* | int* | -/// | hh | signed char | unsigned char | | | | | signed char* | -/// | h | short int | unsigned short int | | | | | short int* | -/// | l | long int | unsigned long int | | wint_t| wchar_t*| | long int* | -/// | ll | long long int | unsigned long long int| | | | | long long int* | -/// | j | intmax_t | uintmax_t | | | | | intmax_t* | -/// | z | size_t | size_t | | | | | size_t* | -/// | t | ptrdiff_t | ptrdiff_t | | | | | ptrdiff_t* | -/// | L | | | long double | | | | | -/// Note: that the c specifier takes an int (or wint_t) as argument, but performs the proper conversion to a char value -/// (or a wchar_t) before formatting it for output. -/// @param[in] ... (additional arguments) Depending on the format string, the function -/// may expect a sequence of additional arguments, each containing a value -/// to be used to replace a format specifier in the format string (or a pointer -/// to a storage location, for n). -/// There should be at least as many of these arguments as the number of values specified -/// in the format specifiers. Additional arguments are ignored by the function. -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// kodi::QueueFormattedNotification(QUEUE_WARNING, "I'm want to inform you, here with a test call to show '%s'", "this"); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline void ATTRIBUTE_HIDDEN QueueFormattedNotification(QueueMsg type, const char* format, ...) -{ - using namespace kodi::addon; - - va_list args; - char buffer[16384]; - va_start(args, format); - vsprintf(buffer, format, args); - va_end(args); - CAddonBase::m_interface->toKodi->kodi->queue_notification( - CAddonBase::m_interface->toKodi->kodiBase, type, "", buffer, "", 5000, false, 1000); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief Queue a notification in the GUI. -/// -/// @param[in] type The message type. -/// | enum code: | Description: -/// |----------------------:|----------------------------------- -/// | QUEUE_INFO | Show info notification message -/// | QUEUE_WARNING | Show warning notification message -/// | QUEUE_ERROR | Show error notification message -/// | QUEUE_OWN_STYLE | If used can be with imageFile the wanted image set or if leaved empty shown as info, also are the other optional values available then -/// @param[in] header Header Name (if leaved empty becomes addon name used) -/// @param[in] message Message to display on Kodi -/// @param[in] imageFile [opt] The image file to show on message (to use must be type set to QUEUE_OWN_STYLE) -/// @param[in] displayTime [opt] The time how long message is displayed (default 5 sec) (to use must be type set to QUEUE_OWN_STYLE) -/// @param[in] withSound [opt] if true also warning sound becomes played (default with sound) (to use must be type set to QUEUE_OWN_STYLE) -/// @param[in] messageTime [opt] how many milli seconds start show of notification (default 1 sec) (to use must be type set to QUEUE_OWN_STYLE) -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// kodi::QueueNotification(QUEUE_OWN_STYLE, "I'm want to inform you", "Here with a test call", "", 3000, false, 1000); -/// ... -/// ~~~~~~~~~~~~~ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// kodi::QueueNotification(QUEUE_WARNING, "I'm want to inform you", "Here with a test call"); -/// ... -/// ~~~~~~~~~~~~~ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// kodi::QueueNotification(QUEUE_OWN_STYLE, "", "Here with a test call", "./myImage.png"); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline void ATTRIBUTE_HIDDEN QueueNotification(QueueMsg type, - const std::string& header, - const std::string& message, - const std::string& imageFile = "", - unsigned int displayTime = 5000, - bool withSound = true, - unsigned int messageTime = 1000) -{ - using namespace kodi::addon; - - CAddonBase::m_interface->toKodi->kodi->queue_notification( - CAddonBase::m_interface->toKodi->kodiBase, type, header.c_str(), message.c_str(), - imageFile.c_str(), displayTime, withSound, messageTime); -} -//------------------------------------------------------------------------------ - -//============================================================================ -/// \ingroup cpp_kodi -/// @brief Get the MD5 digest of the given text -/// -/// @param[in] text text to compute the MD5 for -/// @return Returned MD5 digest -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string md5 = kodi::GetMD5("Make me as md5"); -/// fprintf(stderr, "My md5 digest is: '%s'\n", md5.c_str()); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN GetMD5(const std::string& text) -{ - using namespace kodi::addon; - - char* md5ret = static_cast(malloc(40 * sizeof(char))); // md5 size normally 32 bytes - CAddonBase::m_interface->toKodi->kodi->get_md5(CAddonBase::m_interface->toKodi->kodiBase, - text.c_str(), md5ret); - std::string md5 = md5ret; - free(md5ret); - return md5; -} -//---------------------------------------------------------------------------- - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief To get a temporary path for the addon -/// -/// This gives a temporary path which the addon can use individually for its things. -/// -/// The content of this folder will be deleted when Kodi is finished! -/// -/// @param[in] append A string to append to returned temporary path -/// @return Individual path for the addon -/// -inline std::string ATTRIBUTE_HIDDEN GetTempAddonPath(const std::string& append = "") -{ - using namespace kodi::addon; - - char* str = CAddonBase::m_interface->toKodi->kodi->get_temp_path( - CAddonBase::m_interface->toKodi->kodiBase); - std::string ret = str; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, str); - if (!append.empty()) - { - if (append.at(0) != '\\' && append.at(0) != '/') -#ifdef TARGET_WINDOWS - ret.append("\\"); -#else - ret.append("/"); -#endif - ret.append(append); - } - return ret; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief Returns your regions setting as a string for the specified id -/// -/// @param[in] id id of setting to return -/// | | Choices are | | -/// |:------------:|:------------:|:------------:| -/// | dateshort | time | tempunit | -/// | datelong | meridiem | speedunit | -/// -/// @return settings string -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string timeFormat = kodi::GetRegion("time"); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN GetRegion(const std::string& id) -{ - using namespace kodi::addon; - - AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; - - std::string strReturn; - char* strMsg = toKodi->kodi->get_region(toKodi->kodiBase, id.c_str()); - if (strMsg != nullptr) - { - if (std::strlen(strMsg)) - strReturn = strMsg; - toKodi->free_string(toKodi->kodiBase, strMsg); - } - return strReturn; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief Returns the amount of free memory in MByte (or as bytes) as an long -/// integer -/// -/// @param[out] free free memory -/// @param[out] total total memory -/// @param[in] asBytes [opt] if set to true becomes returned as bytes, otherwise -/// as mega bytes -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// long freeMem; -/// long totalMem; -/// kodi::GetFreeMem(freeMem, totalMem); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline void ATTRIBUTE_HIDDEN GetFreeMem(long& free, long& total, bool asBytes = false) -{ - using namespace kodi::addon; - - free = -1; - total = -1; - AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; - toKodi->kodi->get_free_mem(toKodi->kodiBase, &free, &total, asBytes); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief Returns the elapsed idle time in seconds as an integer -/// -/// @return idle time -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// int time = kodi::GetGlobalIdleTime(); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline int ATTRIBUTE_HIDDEN GetGlobalIdleTime() -{ - using namespace kodi::addon; - - AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; - return toKodi->kodi->get_global_idle_time(toKodi->kodiBase); -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief Get the currently used skin identification name from Kodi -/// -/// @return The active skin id name as a string -/// -/// -/// @note This is not the full path like 'special://home/addons/MediaCenter', -/// but only 'MediaCenter'. -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// .. -/// std::string skinid = kodi::GetCurrentSkinId(); -/// .. -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN GetCurrentSkinId() -{ - using namespace kodi::addon; - - AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; - - std::string strReturn; - char* strMsg = toKodi->kodi->get_current_skin_id(toKodi->kodiBase); - if (strMsg != nullptr) - { - if (std::strlen(strMsg)) - strReturn = strMsg; - toKodi->free_string(toKodi->kodiBase, strMsg); - } - return strReturn; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief To check another addon is available and usable inside Kodi. -/// -/// @param[in] id The wanted addon identification string to check -/// @param[out] version Version string of addon if **installed** inside Kodi -/// @param[out] enabled Set to true `true* if addon is enabled -/// @return Returns `true* if addon is installed -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// bool enabled = false; -/// std::string version; -/// bool ret = kodi::IsAddonAvailable("inputstream.adaptive", version, enabled); -/// fprintf(stderr, "Available inputstream.adaptive version '%s' and enabled '%s'\n", -/// ret ? version.c_str() : "not installed", enabled ? "yes" : "no"); -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN IsAddonAvailable(const std::string& id, - std::string& version, - bool& enabled) -{ - using namespace kodi::addon; - - AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; - - char* cVersion = nullptr; - bool ret = toKodi->kodi->is_addon_avilable(toKodi->kodiBase, id.c_str(), &cVersion, &enabled); - if (cVersion) - { - version = cVersion; - toKodi->free_string(toKodi->kodiBase, cVersion); - } - return ret; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief Get current Kodi informations and versions, returned data from the following -/// kodi_version_t version; kodi::KodiVersion(version); -/// is e.g.: -/// ~~~~~~~~~~~~~{.cpp} -/// version.compile_name = Kodi -/// version.major = 18 -/// version.minor = 0 -/// version.revision = 20170706-c6b22fe217-di -/// version.tag = alpha -/// version.tag_revision = 1 -/// ~~~~~~~~~~~~~ -/// -/// @param[out] version structure to store data from kodi -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// kodi_version_t version; -/// kodi::KodiVersion(version); -/// fprintf(stderr, -/// "kodi_version_t version;\n" -/// "kodi::KodiVersion(version);\n" -/// " - version.compile_name = %s\n" -/// " - version.major = %i\n" -/// " - version.minor = %i\n" -/// " - version.revision = %s\n" -/// " - version.tag = %s\n" -/// " - version.tag_revision = %s\n", -/// version.compile_name.c_str(), version.major, version.minor, -/// version.revision.c_str(), version.tag.c_str(), version.tag_revision.c_str()); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline void ATTRIBUTE_HIDDEN KodiVersion(kodi_version_t& version) -{ - using namespace kodi::addon; - - char* compile_name = nullptr; - char* revision = nullptr; - char* tag = nullptr; - char* tag_revision = nullptr; - - AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; - toKodi->kodi->kodi_version(toKodi->kodiBase, &compile_name, &version.major, &version.minor, - &revision, &tag, &tag_revision); - if (compile_name != nullptr) - { - version.compile_name = compile_name; - toKodi->free_string(toKodi->kodiBase, compile_name); - } - if (revision != nullptr) - { - version.revision = revision; - toKodi->free_string(toKodi->kodiBase, revision); - } - if (tag != nullptr) - { - version.tag = tag; - toKodi->free_string(toKodi->kodiBase, tag); - } - if (tag_revision != nullptr) - { - version.tag_revision = tag_revision; - toKodi->free_string(toKodi->kodiBase, tag_revision); - } -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief To get keyboard layout characters -/// -/// This is used to get the keyboard layout currently used from Kodi by the -/// there set language. -/// -/// @param[in] modifierKey the key to define the needed layout (uppercase, symbols...) -/// @param[out] layout_name name of used layout -/// @param[out] layout list of selected keyboard layout -/// @return true if request successed -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string layout_name; -/// std::vector> layout; -/// kodi::GetKeyboardLayout(STD_KB_MODIFIER_KEY_SHIFT | STD_KB_MODIFIER_KEY_SYMBOL, layout_name, layout); -/// fprintf(stderr, "Layout: '%s'\n", layout_name.c_str()); -/// for (unsigned int row = 0; row < STD_KB_BUTTONS_MAX_ROWS; row++) -/// { -/// for (unsigned int column = 0; column < STD_KB_BUTTONS_PER_ROW; column++) -/// { -/// fprintf(stderr, " - Row: '%02i'; Column: '%02i'; Text: '%s'\n", row, column, layout[row][column].c_str()); -/// } -/// } -/// ... -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN GetKeyboardLayout(int modifierKey, - std::string& layout_name, - std::vector>& layout) -{ - using namespace kodi::addon; - - AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; - AddonKeyboardKeyTable c_layout; - char* c_layout_name = nullptr; - bool ret = - toKodi->kodi->get_keyboard_layout(toKodi->kodiBase, &c_layout_name, modifierKey, &c_layout); - if (ret) - { - if (c_layout_name) - { - layout_name = c_layout_name; - toKodi->free_string(toKodi->kodiBase, c_layout_name); - } - - layout.resize(STD_KB_BUTTONS_MAX_ROWS); - for (unsigned int row = 0; row < STD_KB_BUTTONS_MAX_ROWS; row++) - { - layout[row].resize(STD_KB_BUTTONS_PER_ROW); - for (unsigned int column = 0; column < STD_KB_BUTTONS_PER_ROW; column++) - { - char* button = c_layout.keys[row][column]; - if (button) - { - layout[row][column] = button; - toKodi->free_string(toKodi->kodiBase, button); - } - } - } - } - return ret; -} -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi -/// @brief To change keyboard layout characters -/// -/// This is used to change the keyboard layout currently used from Kodi -/// -/// @param[out] layout_name new name of used layout (input string not used!) -/// @return true if request successed -/// -/// @note \ref GetKeyboardLayout must be called afterwards. -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string layout_name; -/// kodi::ChangeKeyboardLayout(layout_name); -/// -/// std::vector> layout; -/// kodi::GetKeyboardLayout(STD_KB_MODIFIER_KEY_SHIFT | STD_KB_MODIFIER_KEY_SYMBOL, layout_name, layout); -/// fprintf(stderr, "Layout: '%s'\n", layout_name.c_str()); -/// for (unsigned int row = 0; row < STD_KB_BUTTONS_MAX_ROWS; row++) -/// { -/// for (unsigned int column = 0; column < STD_KB_BUTTONS_PER_ROW; column++) -/// { -/// fprintf(stderr, " - Row: '%02i'; Column: '%02i'; Text: '%s'\n", row, column, layout[row][column].c_str()); -/// } -/// } -/// ... -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN ChangeKeyboardLayout(std::string& layout_name) -{ - using namespace kodi::addon; - - AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; - char* c_layout_name = nullptr; - bool ret = toKodi->kodi->change_keyboard_layout(toKodi->kodiBase, &c_layout_name); - if (c_layout_name) - { - layout_name = c_layout_name; - toKodi->free_string(toKodi->kodiBase, c_layout_name); - } - - return ret; -} -//------------------------------------------------------------------------------ - -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/Network.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/Network.h deleted file mode 100644 index 910385f..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/Network.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "AddonBase.h" -#include "c-api/network.h" - -#ifdef __cplusplus - -//============================================================================== -/// @defgroup cpp_kodi_network Interface - kodi::network -/// @ingroup cpp -/// @brief **Network functions**\n -/// The network module offers functions that allow you to control it. -/// -/// It has the header @ref Network.h "#include " be included -/// to enjoy it. -/// -//------------------------------------------------------------------------------ - -namespace kodi -{ -namespace network -{ - -//============================================================================ -/// @ingroup cpp_kodi_network -/// @brief Send WakeOnLan magic packet. -/// -/// @param[in] mac Network address of the host to wake. -/// @return True if the magic packet was successfully sent, false otherwise. -/// -inline bool ATTRIBUTE_HIDDEN WakeOnLan(const std::string& mac) -{ - using namespace ::kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_network->wake_on_lan( - CAddonBase::m_interface->toKodi->kodiBase, mac.c_str()); -} -//---------------------------------------------------------------------------- - -//============================================================================ -/// @ingroup cpp_kodi_network -/// @brief To the current own ip address as a string. -/// -/// @return Own system ip. -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string ipAddress = kodi::network::GetIPAddress(); -/// fprintf(stderr, "My IP is '%s'\n", ipAddress.c_str()); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN GetIPAddress() -{ - using namespace ::kodi::addon; - - std::string ip; - char* string = CAddonBase::m_interface->toKodi->kodi_network->get_ip_address( - CAddonBase::m_interface->toKodi->kodiBase); - if (string != nullptr) - { - ip = string; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, string); - } - return ip; -} -//---------------------------------------------------------------------------- - -//============================================================================ -/// @ingroup cpp_kodi_network -/// @brief Return our hostname. -/// -/// @return String about hostname, empty in case of error -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string hostname = kodi::network::GetHostname(); -/// fprintf(stderr, "My hostname is '%s'\n", hostname.c_str()); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline std::string ATTRIBUTE_HIDDEN GetHostname() -{ - using namespace ::kodi::addon; - - std::string ip; - char* string = CAddonBase::m_interface->toKodi->kodi_network->get_hostname( - CAddonBase::m_interface->toKodi->kodiBase); - if (string != nullptr) - { - ip = string; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, string); - } - return ip; -} -//---------------------------------------------------------------------------- - -//============================================================================ -/// @ingroup cpp_kodi_network -/// @brief Returns Kodi's HTTP UserAgent string. -/// -/// @return HTTP user agent -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.py} -/// .. -/// std::string agent = kodi::network::GetUserAgent() -/// .. -/// ~~~~~~~~~~~~~ -/// -/// example output: -/// Kodi/19.0-ALPHA1 (X11; Linux x86_64) Ubuntu/20.04 App_Bitness/64 Version/19.0-ALPHA1-Git:20200522-0076d136d3-dirty -/// -inline std::string ATTRIBUTE_HIDDEN GetUserAgent() -{ - using namespace ::kodi::addon; - - std::string agent; - char* string = CAddonBase::m_interface->toKodi->kodi_network->get_user_agent( - CAddonBase::m_interface->toKodi->kodiBase); - if (string != nullptr) - { - agent = string; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, string); - } - return agent; -} -//---------------------------------------------------------------------------- - -//============================================================================ -/// @ingroup cpp_kodi_network -/// @brief Check given name or ip address corresponds to localhost. -/// -/// @param[in] hostname Hostname to check -/// @return Return true if given name or ip address corresponds to localhost -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// if (kodi::network::IsLocalHost("127.0.0.1")) -/// fprintf(stderr, "Is localhost\n"); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN IsLocalHost(const std::string& hostname) -{ - using namespace ::kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_network->is_local_host( - CAddonBase::m_interface->toKodi->kodiBase, hostname.c_str()); -} -//---------------------------------------------------------------------------- - -//============================================================================== -/// @ingroup cpp_kodi_network -/// @brief Checks whether the specified path refers to a local network. -/// -/// @param[in] hostname Hostname to check -/// @param[in] offLineCheck Check if in private range, see https://en.wikipedia.org/wiki/Private_network -/// @return True if host is on a LAN, false otherwise -/// -inline bool ATTRIBUTE_HIDDEN IsHostOnLAN(const std::string& hostname, bool offLineCheck = false) -{ - using namespace kodi::addon; - - return CAddonBase::m_interface->toKodi->kodi_network->is_host_on_lan( - CAddonBase::m_interface->toKodi->kodiBase, hostname.c_str(), offLineCheck); -} -//------------------------------------------------------------------------------ - -//============================================================================ -/// @ingroup cpp_kodi_network -/// @brief URL encodes the given string -/// -/// This function converts the given input string to a URL encoded string and -/// returns that as a new allocated string. All input characters that are -/// not a-z, A-Z, 0-9, '-', '.', '_' or '~' are converted to their "URL escaped" -/// version (%NN where NN is a two-digit hexadecimal number). -/// -/// @param[in] url The code of the message to get. -/// @return Encoded URL string -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string encodedUrl = kodi::network::URLEncode("François"); -/// fprintf(stderr, "Encoded URL is '%s'\n", encodedUrl.c_str()); -/// ... -/// ~~~~~~~~~~~~~ -/// For example, the string: François ,would be encoded as: Fran%C3%A7ois -/// -inline std::string ATTRIBUTE_HIDDEN URLEncode(const std::string& url) -{ - using namespace ::kodi::addon; - - std::string retString; - char* string = CAddonBase::m_interface->toKodi->kodi_network->url_encode( - CAddonBase::m_interface->toKodi->kodiBase, url.c_str()); - if (string != nullptr) - { - retString = string; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, string); - } - return retString; -} -//---------------------------------------------------------------------------- - -//============================================================================ -/// @ingroup cpp_kodi_network -/// @brief Lookup URL in DNS cache -/// -/// This test will get DNS record for a domain. The DNS lookup is done directly -/// against the domain's authoritative name server, so changes to DNS Records -/// should show up instantly. By default, the DNS lookup tool will return an -/// IP address if you give it a name (e.g. www.example.com) -/// -/// @param[in] hostName The code of the message to get. -/// @param[out] ipAddress Returned address -/// @return true if successfull -/// -/// -/// ------------------------------------------------------------------------ -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// ... -/// std::string ipAddress; -/// bool ret = kodi::network::DNSLookup("www.google.com", ipAddress); -/// fprintf(stderr, "DNSLookup returned for www.google.com the IP '%s', call was %s\n", ipAddress.c_str(), ret ? "ok" : "failed"); -/// ... -/// ~~~~~~~~~~~~~ -/// -inline bool ATTRIBUTE_HIDDEN DNSLookup(const std::string& hostName, std::string& ipAddress) -{ - using namespace ::kodi::addon; - - bool ret = false; - char* string = CAddonBase::m_interface->toKodi->kodi_network->dns_lookup( - CAddonBase::m_interface->toKodi->kodiBase, hostName.c_str(), &ret); - if (string != nullptr) - { - ipAddress = string; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, string); - } - return ret; -} -//---------------------------------------------------------------------------- - -} /* namespace network */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCodec.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCodec.h deleted file mode 100644 index e030371..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCodec.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2017-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //============================================================================== - /// @ingroup cpp_kodi_addon_videocodec_Defs_VIDEOCODEC_INITDATA - /// @brief The standard defines several sets of capabilities, which are referred - /// to as profiles, targeting specific classes of applications. - //@{ - enum STREAMCODEC_PROFILE - { - /// @brief Unknown codec profile - CodecProfileUnknown = 0, - - /// @brief If a codec profile is not required - CodecProfileNotNeeded, - - /// @brief **H264** Baseline Profile (BP, 66) - /// - /// Primarily for low-cost applications that require additional data loss - /// robustness, this profile is used in some videoconferencing and mobile - /// applications. This profile includes all features that are supported - /// in the Constrained Baseline Profile, plus three additional features - /// that can be used for loss robustness (or for other purposes such as - /// low-delay multi-point video stream compositing). The importance of - /// this profile has faded somewhat since the definition of the Constrained - /// Baseline Profile in 2009. All Constrained Baseline Profile bitstreams - /// are also considered to be Baseline Profile bitstreams, as these two - /// profiles share the same profile identifier code value. - H264CodecProfileBaseline, - - /// @brief **H264** Main Profile (MP, 77) - /// - /// This profile is used for standard-definition digital TV broadcasts that - /// use the MPEG-4 format as defined in the - /// [DVB standard](http://www.etsi.org/deliver/etsi_ts/101100_101199/101154/01.09.01_60/ts_101154v010901p.pdf). - /// It is not, however, used for high-definition television broadcasts, as the - /// importance of this profile faded when the High Profile was developed - /// in 2004 for that application. - H264CodecProfileMain, - - /// @brief **H264** Extended Profile (XP, 88) - /// - /// Intended as the streaming video profile, this profile has relatively high - /// compression capability and some extra tricks for robustness to data losses - /// and server stream switching. - H264CodecProfileExtended, - - /// @brief **H264** High Profile (HiP, 100) - /// - /// The primary profile for broadcast and disc storage applications, - /// particularly for high-definition television applications (for example, - /// this is the profile adopted by the [Blu-ray Disc](https://en.wikipedia.org/wiki/Blu-ray_Disc) - /// storage format and the [DVB](https://en.wikipedia.org/wiki/Digital_Video_Broadcasting) - /// HDTV broadcast service). - H264CodecProfileHigh, - - /// @brief **H264** High 10 Profile (Hi10P, 110) - /// - /// Going beyond typical mainstream consumer product capabilities, this - /// profile builds on top of the High Profile, adding support for up to 10 - /// bits per sample of decoded picture precision. - H264CodecProfileHigh10, - - /// @brief **H264** High 4:2:2 Profile (Hi422P, 122) - /// - /// Primarily targeting professional applications that use interlaced video, - /// this profile builds on top of the High 10 Profile, adding support for the - /// 4:2:2 chroma sampling format while using up to 10 bits per sample of - /// decoded picture precision. - H264CodecProfileHigh422, - - /// @brief **H264** High 4:4:4 Predictive Profile (Hi444PP, 244) - /// - /// This profile builds on top of the High 4:2:2 Profile, supporting up to - /// 4:4:4 chroma sampling, up to 14 bits per sample, and additionally - /// supporting efficient lossless region coding and the coding of each - /// picture as three separate color planes. - H264CodecProfileHigh444Predictive, - - /// @brief **VP9** profile 0 - /// - /// There are several variants of the VP9 format (known as "coding profiles"), - /// which successively allow more features; profile 0 is the basic variant, - /// requiring the least from a hardware implementation. - /// - /// [Color depth](https://en.wikipedia.org/wiki/Color_depth): 8 bit/sample, - /// [chroma subsampling](https://en.wikipedia.org/wiki/Chroma_subsampling): 4:2:0 - VP9CodecProfile0 = 20, - - /// @brief **VP9** profile 1 - /// - /// [Color depth](https://en.wikipedia.org/wiki/Color_depth): 8 bit, - /// [chroma subsampling](https://en.wikipedia.org/wiki/Chroma_subsampling): 4:2:0, 4:2:2, 4:4:4 - VP9CodecProfile1, - - /// @brief **VP9** profile 2 - /// - /// [Color depth](https://en.wikipedia.org/wiki/Color_depth): 10–12 bit, - /// [chroma subsampling](https://en.wikipedia.org/wiki/Chroma_subsampling): 4:2:0 - VP9CodecProfile2, - - /// @brief **VP9** profile 3 - /// - /// [Color depth](https://en.wikipedia.org/wiki/Color_depth): 10–12 bit, - /// [chroma subsampling](https://en.wikipedia.org/wiki/Chroma_subsampling): 4:2:0, 4:2:2, 4:4:4, - /// see [VP9 Bitstream & Decoding Process Specification](https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf) - VP9CodecProfile3, - }; - //@} - //------------------------------------------------------------------------------ - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCrypto.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCrypto.h deleted file mode 100644 index 8008aa1..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/StreamCrypto.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2017-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include -#include - -#define STREAMCRYPTO_VERSION_LEVEL 1 - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - typedef struct CRYPTO_INFO - { - enum CRYPTO_KEY_SYSTEM : uint8_t - { - CRYPTO_KEY_SYSTEM_NONE = 0, - CRYPTO_KEY_SYSTEM_WIDEVINE, - CRYPTO_KEY_SYSTEM_PLAYREADY, - CRYPTO_KEY_SYSTEM_WISEPLAY, - CRYPTO_KEY_SYSTEM_COUNT - } m_CryptoKeySystem; /*!< @brief keysystem for encrypted media, KEY_SYSTEM_NONE for unencrypted media */ - - static const uint8_t FLAG_SECURE_DECODER = - 1; /*!< @brief is set in flags if decoding has to be done in TEE environment */ - - uint8_t flags; - uint16_t m_CryptoSessionIdSize; /*!< @brief The size of the crypto session key id */ - const char* m_CryptoSessionId; /*!< @brief The crypto session key id */ - } CRYPTO_INFO; - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/AudioDecoder.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/AudioDecoder.h deleted file mode 100644 index 25e39e2..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/AudioDecoder.h +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../AddonBase.h" -#ifdef BUILD_KODI_ADDON -#include "../AEChannelData.h" -#else -#include "cores/AudioEngine/Utils/AEChannelData.h" -#endif -#include - -namespace kodi -{ -namespace addon -{ - class CInstanceAudioDecoder; -} /* namespace addon */ -} /* namespace kodi */ - -extern "C" -{ - -typedef struct AddonProps_AudioDecoder -{ - int dummy; -} AddonProps_AudioDecoder; - -typedef struct AddonToKodiFuncTable_AudioDecoder -{ - void* kodiInstance; -} AddonToKodiFuncTable_AudioDecoder; - -struct AddonInstance_AudioDecoder; -typedef struct KodiToAddonFuncTable_AudioDecoder -{ - kodi::addon::CInstanceAudioDecoder* addonInstance; - bool (__cdecl* init)(const AddonInstance_AudioDecoder* instance, - const char* file, unsigned int filecache, - int* channels, int* samplerate, - int* bitspersample, int64_t* totaltime, - int* bitrate, AEDataFormat* format, - const AEChannel** info); - int (__cdecl* read_pcm)(const AddonInstance_AudioDecoder* instance, uint8_t* buffer, int size, int* actualsize); - int64_t (__cdecl* seek)(const AddonInstance_AudioDecoder* instance, int64_t time); - bool (__cdecl* read_tag)(const AddonInstance_AudioDecoder* instance, - const char* file, char* title, - char* artist, int* length); - int (__cdecl* track_count)(const AddonInstance_AudioDecoder* instance, const char* file); -} KodiToAddonFuncTable_AudioDecoder; - -typedef struct AddonInstance_AudioDecoder -{ - AddonProps_AudioDecoder props; - AddonToKodiFuncTable_AudioDecoder toKodi; - KodiToAddonFuncTable_AudioDecoder toAddon; -} AddonInstance_AudioDecoder; - -} /* extern "C" */ - -namespace kodi -{ -namespace addon -{ - -//============================================================================== -/// -/// \addtogroup cpp_kodi_addon_audiodecoder -/// @brief \cpp_class{ kodi::addon::CInstanceAudioDecoder } -/// **Audio decoder add-on instance** -/// -/// For audio decoders as binary add-ons. This class implements a way to handle -/// special types of audio files. -/// -/// The add-on handles loading of the source file and outputting the audio stream -/// for consumption by the player. -/// -/// The addon.xml defines the capabilities of this add-on. -/// -/// @note The option to have multiple instances is possible with audio-decoder -/// add-ons. This is useful, since some playback engines are riddled by global -/// variables, making decoding of multiple streams using the same instance -/// impossible. -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Here's an example on addon.xml:** -/// ~~~~~~~~~~~~~{.xml} -/// -/// ~~~~~~~~~~~~~ -/// -/// Description to audio decoder related addon.xml values: -/// | Name | Description -/// |:------------------------------|---------------------------------------- -/// | `point` | Addon type specification
At all addon types and for this kind always "kodi.audiodecoder". -/// | `library_@PLATFORM@` | Sets the used library name, which is automatically set by cmake at addon build. -/// | `name` | The name of the decoder used in Kodi for display. -/// | `extension` | The file extensions / styles supported by this addon. -/// | `tags` | Boolean to point out that addon can bring own information to replayed file, if `false` only the file name is used as info.
If `true`, \ref CInstanceAudioDecoder::ReadTag is used and must be implemented. -/// -/// -------------------------------------------------------------------------- -/// -/// **Here is a code example how this addon is used:** -/// -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// class CMyAudioDecoder : public ::kodi::addon::CInstanceAudioDecoder -/// { -/// public: -/// CMyAudioDecoder(KODI_HANDLE instance); -/// -/// bool Init(const std::string& filename, unsigned int filecache, -/// int& channels, int& samplerate, -/// int& bitspersample, int64_t& totaltime, -/// int& bitrate, AEDataFormat& format, -/// std::vector& channellist) override; -/// int ReadPCM(uint8_t* buffer, int size, int& actualsize) override; -/// }; -/// -/// CMyAudioDecoder::CMyAudioDecoder(KODI_HANDLE instance) -/// : CInstanceAudioDecoder(instance) -/// { -/// ... -/// } -/// -/// bool CMyAudioDecoder::Init(const std::string& filename, unsigned int filecache, -/// int& channels, int& samplerate, -/// int& bitspersample, int64_t& totaltime, -/// int& bitrate, AEDataFormat& format, -/// std::vector& channellist) -/// { -/// ... -/// return true; -/// } -/// -/// int CMyAudioDecoder::ReadPCM(uint8_t* buffer, int size, int& actualsize) -/// { -/// ... -/// return 0; -/// } -/// -/// -/// /*----------------------------------------------------------------------*/ -/// -/// class CMyAddon : public ::kodi::addon::CAddonBase -/// { -/// public: -/// CMyAddon() { } -/// ADDON_STATUS CreateInstance(int instanceType, -/// std::string instanceID, -/// KODI_HANDLE instance, -/// KODI_HANDLE& addonInstance) override; -/// }; -/// -/// /* If you use only one instance in your add-on, can be instanceType and -/// * instanceID ignored */ -/// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, -/// std::string instanceID, -/// KODI_HANDLE instance, -/// KODI_HANDLE& addonInstance) -/// { -/// if (instanceType == ADDON_INSTANCE_AUDIODECODER) -/// { -/// kodi::Log(ADDON_LOG_NOTICE, "Creating my audio decoder"); -/// addonInstance = new CMyAudioDecoder(instance); -/// return ADDON_STATUS_OK; -/// } -/// else if (...) -/// { -/// ... -/// } -/// return ADDON_STATUS_UNKNOWN; -/// } -/// -/// ADDONCREATOR(CMyAddon) -/// ~~~~~~~~~~~~~ -/// -/// The destruction of the example class `CMyAudioDecoder` is called from -/// Kodi's header. Manually deleting the add-on instance is not required. -/// -class ATTRIBUTE_HIDDEN CInstanceAudioDecoder : public IAddonInstance -{ -public: - //========================================================================== - /// @ingroup cpp_kodi_addon_audiodecoder - /// @brief Class constructor - /// - /// @param[in] instance The addon instance class handler given by Kodi - /// at \ref kodi::addon::CAddonBase::CreateInstance(...) - /// @param[in] kodiVersion [opt] Version used in Kodi for this instance, to - /// allow compatibility to older Kodi versions. - /// @note Recommended to set. - /// - explicit CInstanceAudioDecoder(KODI_HANDLE instance, const std::string& kodiVersion = "") - : IAddonInstance(ADDON_INSTANCE_AUDIODECODER, - !kodiVersion.empty() ? kodiVersion - : GetKodiTypeVersion(ADDON_INSTANCE_AUDIODECODER)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstanceAudioDecoder: Creation of multiple together with single instance way is not allowed!"); - - SetAddonStruct(instance); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_addon_audiodecoder - /// @brief Initialize a decoder - /// - /// @param[in] filename The file to read - /// @param[in] filecache The file cache size - /// @param[out] channels Number of channels in output stream - /// @param[out] samplerate Samplerate of output stream - /// @param[out] bitspersample Bits per sample in output stream - /// @param[out] totaltime Total time for stream - /// @param[out] bitrate Average bitrate of input stream - /// @param[out] format Data format for output stream - /// @param[out] channellist Channel mapping for output stream - /// @return true if successfully done, otherwise - /// false - /// - virtual bool Init(const std::string& filename, unsigned int filecache, - int& channels, int& samplerate, - int& bitspersample, int64_t& totaltime, - int& bitrate, AEDataFormat& format, - std::vector& channellist) = 0; - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_addon_audiodecoder - /// @brief Produce some noise - /// - /// @param[in] buffer Output buffer - /// @param[in] size Size of output buffer - /// @param[out] actualsize Actual number of bytes written to output buffer - /// @return Return with following possible values: - /// | Value | Description | - /// |:-----:|:-----------------------------| - /// | 0 | on success - /// | -1 | on end of stream - /// | 1 | on failure - /// - virtual int ReadPCM(uint8_t* buffer, int size, int& actualsize) = 0; - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_addon_audiodecoder - /// @brief Seek in output stream - /// - /// @param[in] time Time position to seek to in milliseconds - /// @return Time position seek ended up on - /// - virtual int64_t Seek(int64_t time) { return time; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_addon_audiodecoder - /// @brief Read tag of a file - /// - /// @param[in] file File to read tag for - /// @param[out] title Title of file - /// @param[out] artist Artist of file - /// @param[out] length Length of file - /// @return True on success, false on failure - /// - virtual bool ReadTag(const std::string& file, std::string& title, std::string& artist, int& length) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// @ingroup cpp_kodi_addon_audiodecoder - /// @brief Get number of tracks in a file - /// - /// @param[in] file File to read tag for - /// @return Number of tracks in file - /// - virtual int TrackCount(const std::string& file) { return 1; } - //-------------------------------------------------------------------------- - -private: - void SetAddonStruct(KODI_HANDLE instance) - { - if (instance == nullptr) - throw std::logic_error("kodi::addon::CInstanceAudioDecoder: Creation with empty addon structure not allowed, table must be given from Kodi!"); - - m_instanceData = static_cast(instance); - - m_instanceData->toAddon.addonInstance = this; - m_instanceData->toAddon.init = ADDON_Init; - m_instanceData->toAddon.read_pcm = ADDON_ReadPCM; - m_instanceData->toAddon.seek = ADDON_Seek; - m_instanceData->toAddon.read_tag = ADDON_ReadTag; - m_instanceData->toAddon.track_count = ADDON_TrackCount; - } - - inline static bool ADDON_Init(const AddonInstance_AudioDecoder* instance, const char* file, unsigned int filecache, - int* channels, int* samplerate, - int* bitspersample, int64_t* totaltime, - int* bitrate, AEDataFormat* format, - const AEChannel** info) - { - instance->toAddon.addonInstance->m_channelList.clear(); - bool ret = instance->toAddon.addonInstance->Init(file, filecache, *channels, - *samplerate, *bitspersample, - *totaltime, *bitrate, *format, - instance->toAddon.addonInstance->m_channelList); - if (!instance->toAddon.addonInstance->m_channelList.empty()) - { - if (instance->toAddon.addonInstance->m_channelList.back() != AE_CH_NULL) - instance->toAddon.addonInstance->m_channelList.push_back(AE_CH_NULL); - *info = instance->toAddon.addonInstance->m_channelList.data(); - } - else - *info = nullptr; - return ret; - } - - inline static int ADDON_ReadPCM(const AddonInstance_AudioDecoder* instance, uint8_t* buffer, int size, int* actualsize) - { - return instance->toAddon.addonInstance->ReadPCM(buffer, size, *actualsize); - } - - inline static int64_t ADDON_Seek(const AddonInstance_AudioDecoder* instance, int64_t time) - { - return instance->toAddon.addonInstance->Seek(time); - } - - inline static bool ADDON_ReadTag(const AddonInstance_AudioDecoder* instance, const char* file, char* title, char* artist, int* length) - { - std::string intTitle; - std::string intArtist; - bool ret = instance->toAddon.addonInstance->ReadTag(file, intTitle, intArtist, *length); - if (ret) - { - strncpy(title, intTitle.c_str(), ADDON_STANDARD_STRING_LENGTH_SMALL-1); - strncpy(artist, intArtist.c_str(), ADDON_STANDARD_STRING_LENGTH_SMALL-1); - } - return ret; - } - - inline static int ADDON_TrackCount(const AddonInstance_AudioDecoder* instance, const char* file) - { - return instance->toAddon.addonInstance->TrackCount(file); - } - - std::vector m_channelList; - AddonInstance_AudioDecoder* m_instanceData; -}; - -} /* namespace addon */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/AudioEncoder.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/AudioEncoder.h deleted file mode 100644 index 36257e1..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/AudioEncoder.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../AddonBase.h" - -namespace kodi { namespace addon { class CInstanceAudioEncoder; }} - -extern "C" -{ - - typedef struct AddonProps_AudioEncoder - { - int dummy; - } AddonProps_AudioEncoder; - - typedef struct AddonToKodiFuncTable_AudioEncoder - { - void* kodiInstance; - int (*write) (void* kodiInstance, const uint8_t* data, int len); - int64_t (*seek)(void* kodiInstance, int64_t pos, int whence); - } AddonToKodiFuncTable_AudioEncoder; - - struct AddonInstance_AudioEncoder; - typedef struct KodiToAddonFuncTable_AudioEncoder - { - kodi::addon::CInstanceAudioEncoder* addonInstance; - bool (__cdecl* start) (const AddonInstance_AudioEncoder* instance, int in_channels, int in_rate, int in_bits, - const char* title, const char* artist, - const char* albumartist, const char* album, - const char* year, const char* track, - const char* genre, const char* comment, - int track_length); - int (__cdecl* encode) (const AddonInstance_AudioEncoder* instance, int num_bytes_read, const uint8_t* pbt_stream); - bool (__cdecl* finish) (const AddonInstance_AudioEncoder* instance); - } KodiToAddonFuncTable_AudioEncoder; - - typedef struct AddonInstance_AudioEncoder - { - AddonProps_AudioEncoder props; - AddonToKodiFuncTable_AudioEncoder toKodi; - KodiToAddonFuncTable_AudioEncoder toAddon; - } AddonInstance_AudioEncoder; - -} /* extern "C" */ - -namespace kodi -{ -namespace addon -{ - - class ATTRIBUTE_HIDDEN CInstanceAudioEncoder : public IAddonInstance - { - public: - //========================================================================== - /// @brief Class constructor - /// - /// @param[in] instance The from Kodi given instance given be - /// add-on CreateInstance call with instance - /// id ADDON_INSTANCE_AUDIOENCODER. - /// @param[in] kodiVersion [opt] Version used in Kodi for this instance, to - /// allow compatibility to older Kodi versions. - /// @note Recommended to set. - /// - explicit CInstanceAudioEncoder(KODI_HANDLE instance, const std::string& kodiVersion = "") - : IAddonInstance(ADDON_INSTANCE_AUDIOENCODER, - !kodiVersion.empty() ? kodiVersion - : GetKodiTypeVersion(ADDON_INSTANCE_AUDIOENCODER)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstanceAudioEncoder: Creation of multiple together with single instance way is not allowed!"); - - SetAddonStruct(instance); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// \brief Start encoder (**required**) - /// - /// \param[in] inChannels Number of channels - /// \param[in] inRate Sample rate of input data - /// \param[in] inBits Bits per sample in input data - /// \param[in] title The title of the song - /// \param[in] artist The artist of the song - /// \param[in] albumartist The albumartist of the song - /// \param[in] year The year of the song - /// \param[in] track The track number of the song - /// \param[in] genre The genre of the song - /// \param[in] comment A comment to attach to the song - /// \param[in] trackLength Total track length in seconds - /// \return True on success, false on failure. - /// - virtual bool Start(int inChannels, - int inRate, - int inBits, - const std::string& title, - const std::string& artist, - const std::string& albumartist, - const std::string& album, - const std::string& year, - const std::string& track, - const std::string& genre, - const std::string& comment, - int trackLength) = 0; - //-------------------------------------------------------------------------- - - //========================================================================== - /// \brief Encode a chunk of audio (**required**) - /// - /// \param[in] numBytesRead Number of bytes in input buffer - /// \param[in] pbtStream the input buffer - /// \return Number of bytes consumed - /// - virtual int Encode(int numBytesRead, const uint8_t* pbtStream) = 0; - //-------------------------------------------------------------------------- - - //========================================================================== - /// \brief Finalize encoding (**optional**) - /// - /// \return True on success, false on failure. - /// - virtual bool Finish() { return true; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// \brief Write block of data - /// - /// \param[in] data Pointer to the array of elements to be - /// written - /// \param[in] length Size in bytes to be written. - /// \return The total number of bytes - /// successfully written is returned. - int Write(const uint8_t* data, int length) - { - return m_instanceData->toKodi.write(m_instanceData->toKodi.kodiInstance, data, length); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// \brief Set the file's current position. - /// - /// The whence argument is optional and defaults to SEEK_SET (0) - /// - /// \param[in] position the position that you want to seek to - /// \param[in] whence [optional] offset relative to - /// You can set the value of whence to one - /// of three things: - /// | Value | int | Description | - /// |:--------:|:---:|:---------------------------------------------------| - /// | SEEK_SET | 0 | position is relative to the beginning of the file. This is probably what you had in mind anyway, and is the most commonly used value for whence. - /// | SEEK_CUR | 1 | position is relative to the current file pointer position. So, in effect, you can say, "Move to my current position plus 30 bytes," or, "move to my current position minus 20 bytes." - /// | SEEK_END | 2 | position is relative to the end of the file. Just like SEEK_SET except from the other end of the file. Be sure to use negative values for offset if you want to back up from the end of the file, instead of going past the end into oblivion. - /// - /// \return Returns the resulting offset location as - /// measured in bytes from the beginning of - /// the file. On error, the value -1 is - /// returned. - int64_t Seek(int64_t position, int whence = SEEK_SET) - { - return m_instanceData->toKodi.seek(m_instanceData->toKodi.kodiInstance, position, whence); - } - //-------------------------------------------------------------------------- - - private: - void SetAddonStruct(KODI_HANDLE instance) - { - if (instance == nullptr) - throw std::logic_error("kodi::addon::CInstanceAudioEncoder: Creation with empty addon structure not allowed, table must be given from Kodi!"); - - m_instanceData = static_cast(instance); - m_instanceData->toAddon.addonInstance = this; - m_instanceData->toAddon.start = ADDON_Start; - m_instanceData->toAddon.encode = ADDON_Encode; - m_instanceData->toAddon.finish = ADDON_Finish; - } - - inline static bool ADDON_Start(const AddonInstance_AudioEncoder* instance, int inChannels, int inRate, int inBits, - const char* title, const char* artist, - const char* albumartist, const char* album, - const char* year, const char* track, - const char* genre, const char* comment, - int trackLength) - { - return instance->toAddon.addonInstance->Start(inChannels, - inRate, - inBits, - title, - artist, - albumartist, - album, - year, - track, - genre, - comment, - trackLength); - } - - inline static int ADDON_Encode(const AddonInstance_AudioEncoder* instance, int numBytesRead, const uint8_t* pbtStream) - { - return instance->toAddon.addonInstance->Encode(numBytesRead, pbtStream); - } - - inline static bool ADDON_Finish(const AddonInstance_AudioEncoder* instance) - { - return instance->toAddon.addonInstance->Finish(); - } - - AddonInstance_AudioEncoder* m_instanceData; - }; - -} /* namespace addon */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/CMakeLists.txt deleted file mode 100644 index 8fa6e05..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set(HEADERS AudioDecoder.h - AudioEncoder.h - Game.h - ImageDecoder.h - Inputstream.h - Peripheral.h - PeripheralUtils.h - PVR.h - Screensaver.h - VFS.h - VideoCodec.h - Visualization.h) - -if(NOT ENABLE_STATIC_LIBS) - core_add_library(addons_kodi-addon-dev-kit_include_kodi_addon-instance) -endif() diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Game.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Game.h deleted file mode 100644 index a53f1e7..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Game.h +++ /dev/null @@ -1,2360 +0,0 @@ -/* - * Copyright (C) 2014-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../AddonBase.h" - -#ifdef BUILD_KODI_ADDON -#include "XBMC_vkeys.h" -#else -#include "input/XBMC_vkeys.h" -#endif - -//============================================================================== -/// @addtogroup cpp_kodi_addon_game -/// -/// To use on Libretro and for stand-alone games or emulators that does not use -/// the Libretro API. -/// -/// Possible examples could be, Nvidia GameStream via Limelight or WINE capture -/// could possible through the Game API. -/// - -namespace kodi -{ -namespace addon -{ -class CInstanceGame; -} -} // namespace kodi - -extern "C" -{ - -//============================================================================== -/// \defgroup cpp_kodi_addon_game_Defs Definitions, structures and enumerators -/// \ingroup cpp_kodi_addon_game -/// @brief **Game add-on instance definition values** -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi_addon_game_Defs -/// @brief **Port ID used when topology is unknown** -#define DEFAULT_PORT_ID "1" -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi_addon_game_Defs -/// @brief **Game add-on error codes** -/// -/// Used as return values on most Game related functions. -/// -typedef enum GAME_ERROR -{ - /// @brief no error occurred - GAME_ERROR_NO_ERROR, - - /// @brief an unknown error occurred - GAME_ERROR_UNKNOWN, - - /// @brief the method that the frontend called is not implemented - GAME_ERROR_NOT_IMPLEMENTED, - - /// @brief the command was rejected by the game client - GAME_ERROR_REJECTED, - - /// @brief the parameters of the method that was called are invalid for this operation - GAME_ERROR_INVALID_PARAMETERS, - - /// @brief the command failed - GAME_ERROR_FAILED, - - /// @brief no game is loaded - GAME_ERROR_NOT_LOADED, - - /// @brief game requires restricted resources - GAME_ERROR_RESTRICTED, -} GAME_ERROR; -//------------------------------------------------------------------------------ - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- -/// \defgroup cpp_kodi_addon_game_Defs_AudioStream 1. Audio stream -/// \ingroup cpp_kodi_addon_game_Defs -/// @brief **The for Audio stream used data system** -/// -/// Used to give Addon currently used audio stream configuration on Kodi and -/// arrays to give related data to Kodi on callbacks. -/// -//@{ - -//============================================================================== -/// @brief **Stream Format** -/// -/// From Kodi requested specified audio sample format. -/// -typedef enum GAME_PCM_FORMAT -{ - GAME_PCM_FORMAT_UNKNOWN, - - /// @brief S16NE sample format - GAME_PCM_FORMAT_S16NE, -} GAME_PCM_FORMAT; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Audio channel** -/// -/// Channel identification flags. -/// -typedef enum GAME_AUDIO_CHANNEL -{ - /// @brief Channel list terminator - GAME_CH_NULL, - - /// @brief Channel front left - GAME_CH_FL, - - /// @brief Channel front right - GAME_CH_FR, - - /// @brief Channel front center - GAME_CH_FC, - - /// @brief Channel Low Frequency Effects / Subwoofer - GAME_CH_LFE, - - /// @brief Channel back left - GAME_CH_BL, - - /// @brief Channel back right - GAME_CH_BR, - - /// @brief Channel front left over center - GAME_CH_FLOC, - - /// @brief Channel front right over center - GAME_CH_FROC, - - /// @brief Channel back center - GAME_CH_BC, - - /// @brief Channel surround/side left - GAME_CH_SL, - - /// @brief Channel surround/side right - GAME_CH_SR, - - /// @brief Channel top front left - GAME_CH_TFL, - - /// @brief Channel top front right - GAME_CH_TFR, - - /// @brief Channel top front center - GAME_CH_TFC, - - /// @brief Channel top center - GAME_CH_TC, - - /// @brief Channel top back left - GAME_CH_TBL, - - /// @brief Channel top back right - GAME_CH_TBR, - - /// @brief Channel top back center - GAME_CH_TBC, - - /// @brief Channel bacl left over center - GAME_CH_BLOC, - - /// @brief Channel back right over center - GAME_CH_BROC, -} GAME_AUDIO_CHANNEL; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Game audio stream properties** -/// -/// Used by Kodi to pass the currently required audio stream settings to the addon -/// -typedef struct game_stream_audio_properties -{ - GAME_PCM_FORMAT format; - const GAME_AUDIO_CHANNEL* channel_map; -} ATTRIBUTE_PACKED game_stream_audio_properties; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Audio stream packet** -/// -/// This packet contains audio stream data passed to Kodi. -/// -typedef struct game_stream_audio_packet -{ - /// @brief Pointer for audio stream data given to Kodi - const uint8_t *data; - - /// @brief Size of data array - size_t size; -} ATTRIBUTE_PACKED game_stream_audio_packet; -//------------------------------------------------------------------------------ - -//@} - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- -/// \defgroup cpp_kodi_addon_game_Defs_VideoStream 2. Video stream -/// \ingroup cpp_kodi_addon_game_Defs -/// @brief **The for Video stream used data system** -/// -/// Used to give Addon currently used video stream configuration on Kodi and -/// arrays to give related data to Kodi on callbacks. -/// -//@{ - -//============================================================================== -/// @brief **Pixel format** -/// -/// From Kodi requested specified video RGB color model format. -/// -typedef enum GAME_PIXEL_FORMAT -{ - GAME_PIXEL_FORMAT_UNKNOWN, - - /// @brief 0RGB8888 Format - GAME_PIXEL_FORMAT_0RGB8888, - - /// @brief RGB565 Format - GAME_PIXEL_FORMAT_RGB565, - - /// @brief 0RGB1555 Format - GAME_PIXEL_FORMAT_0RGB1555, -} GAME_PIXEL_FORMAT; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Video rotation position** -/// -/// To define position how video becomes shown. -/// -typedef enum GAME_VIDEO_ROTATION -{ - /// @brief 0° and Without rotation - GAME_VIDEO_ROTATION_0, - - /// @brief rotate 90° counterclockwise - GAME_VIDEO_ROTATION_90_CCW, - - /// @brief rotate 180° counterclockwise - GAME_VIDEO_ROTATION_180_CCW, - - /// @brief rotate 270° counterclockwise - GAME_VIDEO_ROTATION_270_CCW, -} GAME_VIDEO_ROTATION; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Game video stream properties** -/// -/// Used by Kodi to pass the currently required video stream settings to the addon -/// -typedef struct game_stream_video_properties -{ - /// @brief The to used pixel format - GAME_PIXEL_FORMAT format; - - /// @brief The nominal used width - unsigned int nominal_width; - - /// @brief The nominal used height - unsigned int nominal_height; - - /// @brief The maximal used width - unsigned int max_width; - - /// @brief The maximal used height - unsigned int max_height; - - /// @brief On video stream used aspect ration - /// - /// @note If aspect_ratio is <= 0.0, an aspect ratio of nominal_width / nominal_height is assumed - float aspect_ratio; -} ATTRIBUTE_PACKED game_stream_video_properties; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Video stream packet** -/// -/// This packet contains video stream data passed to Kodi. -/// -typedef struct game_stream_video_packet -{ - /// @brief Video height - unsigned int width; - - /// @brief Video width - unsigned int height; - - /// @brief Width @ref GAME_VIDEO_ROTATION defined rotation angle. - GAME_VIDEO_ROTATION rotation; - - /// @brief Pointer for video stream data given to Kodi - const uint8_t *data; - - /// @brief Size of data array - size_t size; -} ATTRIBUTE_PACKED game_stream_video_packet; -//------------------------------------------------------------------------------ - -//@} - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- -/// \defgroup cpp_kodi_addon_game_Defs_HardwareFramebuffer 3. Hardware framebuffer stream -/// \ingroup cpp_kodi_addon_game_Defs -/// @brief **Hardware framebuffer stream data** -/// -//@{ - -//============================================================================== -/// @brief **Hardware framebuffer type** -/// -typedef enum GAME_HW_CONTEXT_TYPE -{ - /// @brief None context - GAME_HW_CONTEXT_NONE, - - /// @brief OpenGL 2.x. Driver can choose to use latest compatibility context - GAME_HW_CONTEXT_OPENGL, - - /// @brief OpenGL ES 2.0 - GAME_HW_CONTEXT_OPENGLES2, - - /// @brief Modern desktop core GL context. Use major/minor fields to set GL version - GAME_HW_CONTEXT_OPENGL_CORE, - - /// @brief OpenGL ES 3.0 - GAME_HW_CONTEXT_OPENGLES3, - - /// @brief OpenGL ES 3.1+. Set major/minor fields. - GAME_HW_CONTEXT_OPENGLES_VERSION, - - /// @brief Vulkan - GAME_HW_CONTEXT_VULKAN -} GAME_HW_CONTEXT_TYPE; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Hardware framebuffer properties** -/// -typedef struct game_stream_hw_framebuffer_properties -{ - /// @brief The API to use. - /// - GAME_HW_CONTEXT_TYPE context_type; - - /// @brief Set if render buffers should have depth component attached. - /// - /// @todo: Obsolete - /// - bool depth; - - /// @brief Set if stencil buffers should be attached. - /// - /// If depth and stencil are true, a packed 24/8 buffer will be added. - /// Only attaching stencil is invalid and will be ignored. - /// - /// @todo: Obsolete. - /// - bool stencil; - - /// @brief Use conventional bottom-left origin convention. - /// - /// If false, standard top-left origin semantics are used. - /// - /// @todo: Move to GL specific interface - /// - bool bottom_left_origin; - - /// @brief Major version number for core GL context or GLES 3.1+. - unsigned int version_major; - - /// @brief Minor version number for core GL context or GLES 3.1+. - unsigned int version_minor; - - /// @brief If this is true, the frontend will go very far to avoid resetting context - /// in scenarios like toggling fullscreen, etc. - /// - /// @todo: Obsolete? Maybe frontend should just always assume this... - /// - /// The reset callback might still be called in extreme situations such as if - /// the context is lost beyond recovery. - /// - /// For optimal stability, set this to false, and allow context to be reset at - /// any time. - /// - bool cache_context; - - /// @brief Creates a debug context. - bool debug_context; -} ATTRIBUTE_PACKED game_stream_hw_framebuffer_properties; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Hardware framebuffer buffer** -/// -typedef struct game_stream_hw_framebuffer_buffer -{ - /// @brief - uintptr_t framebuffer; -} ATTRIBUTE_PACKED game_stream_hw_framebuffer_buffer; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Hardware framebuffer packet** -/// -typedef struct game_stream_hw_framebuffer_packet -{ - /// @brief - uintptr_t framebuffer; -} ATTRIBUTE_PACKED game_stream_hw_framebuffer_packet; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Hardware framebuffer process function address** -/// -typedef void (*game_proc_address_t)(void); -//------------------------------------------------------------------------------ - -//@} - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- -/// \defgroup cpp_kodi_addon_game_Defs_SoftwareFramebuffer 4. Software framebuffer stream -/// \ingroup cpp_kodi_addon_game_Defs -/// @brief **Software framebuffer stream data** -/// -//@{ - -//============================================================================== -/// @brief **Game video stream properties** -/// -/// Used by Kodi to pass the currently required video stream settings to the addon -/// -typedef game_stream_video_properties game_stream_sw_framebuffer_properties; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Hardware framebuffer type** -/// -typedef struct game_stream_sw_framebuffer_buffer -{ - GAME_PIXEL_FORMAT format; - uint8_t *data; - size_t size; -} ATTRIBUTE_PACKED game_stream_sw_framebuffer_buffer; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Video stream packet** -/// -/// This packet contains video stream data passed to Kodi. -/// -typedef game_stream_video_packet game_stream_sw_framebuffer_packet; -//------------------------------------------------------------------------------ - -//@} - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- -/// \defgroup cpp_kodi_addon_game_Defs_StreamTypes 5. Stream types -/// \ingroup cpp_kodi_addon_game_Defs -/// @brief **Stream types data** -/// -//@{ - -//============================================================================== -/// @brief **Game stream types** -/// -typedef enum GAME_STREAM_TYPE -{ - /// @brief Unknown - GAME_STREAM_UNKNOWN, - - /// @brief Audio stream - GAME_STREAM_AUDIO, - - /// @brief Video stream - GAME_STREAM_VIDEO, - - /// @brief Hardware framebuffer - GAME_STREAM_HW_FRAMEBUFFER, - - /// @brief Software framebuffer - GAME_STREAM_SW_FRAMEBUFFER, -} GAME_STREAM_TYPE; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Immutable stream metadata** -/// -/// This metadata is provided when the stream is opened. If any stream -/// properties change, a new stream must be opened. -/// -typedef struct game_stream_properties -{ - /// @brief - GAME_STREAM_TYPE type; - union - { - /// @brief - game_stream_audio_properties audio; - - /// @brief - game_stream_video_properties video; - - /// @brief - game_stream_hw_framebuffer_properties hw_framebuffer; - - /// @brief - game_stream_sw_framebuffer_properties sw_framebuffer; - }; -} ATTRIBUTE_PACKED game_stream_properties; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Stream buffers for hardware rendering and zero-copy support** -/// -typedef struct game_stream_buffer -{ - /// @brief - GAME_STREAM_TYPE type; - union - { - /// @brief - game_stream_hw_framebuffer_buffer hw_framebuffer; - - /// @brief - game_stream_sw_framebuffer_buffer sw_framebuffer; - }; -} ATTRIBUTE_PACKED game_stream_buffer; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Stream packet and ephemeral metadata** -/// -/// This packet contains stream data and accompanying metadata. The metadata -/// is ephemeral, meaning it only applies to the current packet and can change -/// from packet to packet in the same stream. -/// -typedef struct game_stream_packet -{ - /// @brief - GAME_STREAM_TYPE type; - union - { - /// @brief - game_stream_audio_packet audio; - - /// @brief - game_stream_video_packet video; - - /// @brief - game_stream_hw_framebuffer_packet hw_framebuffer; - - /// @brief - game_stream_sw_framebuffer_packet sw_framebuffer; - }; -} ATTRIBUTE_PACKED game_stream_packet; -//------------------------------------------------------------------------------ - -//@} - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- -/// \defgroup cpp_kodi_addon_game_Defs_GameTypes 6. Game types -/// \ingroup cpp_kodi_addon_game_Defs -/// @brief **Game types data** -/// -//@{ - -//============================================================================== -/// @brief **Game reguin definition** -/// -/// Returned from game_get_region() -typedef enum GAME_REGION -{ - /// @brief Game region unknown - GAME_REGION_UNKNOWN, - - /// @brief Game region NTSC - GAME_REGION_NTSC, - - /// @brief Game region PAL - GAME_REGION_PAL, -} GAME_REGION; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Special game types passed into game_load_game_special().** -/// -/// @remark Only used when multiple ROMs are required. -/// -typedef enum SPECIAL_GAME_TYPE -{ - /// @brief Game Type BSX - SPECIAL_GAME_TYPE_BSX, - - /// @brief Game Type BSX slotted - SPECIAL_GAME_TYPE_BSX_SLOTTED, - - /// @brief Game Type sufami turbo - SPECIAL_GAME_TYPE_SUFAMI_TURBO, - - /// @brief Game Type super game boy - SPECIAL_GAME_TYPE_SUPER_GAME_BOY, -} SPECIAL_GAME_TYPE; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **Game Memory** -/// -typedef enum GAME_MEMORY -{ - /// @brief Passed to game_get_memory_data/size(). If the memory type doesn't apply - /// to the implementation NULL/0 can be returned. - GAME_MEMORY_MASK = 0xff, - - /// @brief Regular save ram. - /// - /// This ram is usually found on a game cartridge, backed - /// up by a battery. If save game data is too complex for a single memory - /// buffer, the SYSTEM_DIRECTORY environment callback can be used. - GAME_MEMORY_SAVE_RAM = 0, - - /// @brief Some games have a built-in clock to keep track of time. - /// - /// This memory is usually just a couple of bytes to keep track of time. - GAME_MEMORY_RTC = 1, - - /// @brief System ram lets a frontend peek into a game systems main RAM - GAME_MEMORY_SYSTEM_RAM = 2, - - /// @brief Video ram lets a frontend peek into a game systems video RAM (VRAM) - GAME_MEMORY_VIDEO_RAM = 3, - - /// @brief Special memory type - GAME_MEMORY_SNES_BSX_RAM = ((1 << 8) | GAME_MEMORY_SAVE_RAM), - - /// @brief Special memory type - GAME_MEMORY_SNES_BSX_PRAM = ((2 << 8) | GAME_MEMORY_SAVE_RAM), - - /// @brief Special memory type - GAME_MEMORY_SNES_SUFAMI_TURBO_A_RAM = ((3 << 8) | GAME_MEMORY_SAVE_RAM), - - /// @brief Special memory type - GAME_MEMORY_SNES_SUFAMI_TURBO_B_RAM = ((4 << 8) | GAME_MEMORY_SAVE_RAM), - - /// @brief Special memory type - GAME_MEMORY_SNES_GAME_BOY_RAM = ((5 << 8) | GAME_MEMORY_SAVE_RAM), - - /// @brief Special memory type - GAME_MEMORY_SNES_GAME_BOY_RTC = ((6 << 8) | GAME_MEMORY_RTC), -} GAME_MEMORY; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief **ID values for SIMD CPU features** -typedef enum GAME_SIMD -{ - /// @brief SIMD CPU SSE - GAME_SIMD_SSE = (1 << 0), - - /// @brief SIMD CPU SSE2 - GAME_SIMD_SSE2 = (1 << 1), - - /// @brief SIMD CPU VMX - GAME_SIMD_VMX = (1 << 2), - - /// @brief SIMD CPU VMX128 - GAME_SIMD_VMX128 = (1 << 3), - - /// @brief SIMD CPU AVX - GAME_SIMD_AVX = (1 << 4), - - /// @brief SIMD CPU NEON - GAME_SIMD_NEON = (1 << 5), - - /// @brief SIMD CPU SSE3 - GAME_SIMD_SSE3 = (1 << 6), - - /// @brief SIMD CPU SSSE3 - GAME_SIMD_SSSE3 = (1 << 7), - - /// @brief SIMD CPU MMX - GAME_SIMD_MMX = (1 << 8), - - /// @brief SIMD CPU MMXEXT - GAME_SIMD_MMXEXT = (1 << 9), - - /// @brief SIMD CPU SSE4 - GAME_SIMD_SSE4 = (1 << 10), - - /// @brief SIMD CPU SSE42 - GAME_SIMD_SSE42 = (1 << 11), - - /// @brief SIMD CPU AVX2 - GAME_SIMD_AVX2 = (1 << 12), - - /// @brief SIMD CPU VFPU - GAME_SIMD_VFPU = (1 << 13), -} GAME_SIMD; -//------------------------------------------------------------------------------ - -//@} - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- -/// \defgroup cpp_kodi_addon_game_Defs_InputTypes 7. Input types -/// \ingroup cpp_kodi_addon_game_Defs -/// @brief **Input types** -/// -//@{ - -//============================================================================== -/// @brief -typedef enum GAME_INPUT_EVENT_SOURCE -{ - /// @brief - GAME_INPUT_EVENT_DIGITAL_BUTTON, - - /// @brief - GAME_INPUT_EVENT_ANALOG_BUTTON, - - /// @brief - GAME_INPUT_EVENT_AXIS, - - /// @brief - GAME_INPUT_EVENT_ANALOG_STICK, - - /// @brief - GAME_INPUT_EVENT_ACCELEROMETER, - - /// @brief - GAME_INPUT_EVENT_KEY, - - /// @brief - GAME_INPUT_EVENT_RELATIVE_POINTER, - - /// @brief - GAME_INPUT_EVENT_ABSOLUTE_POINTER, - - /// @brief - GAME_INPUT_EVENT_MOTOR, -} GAME_INPUT_EVENT_SOURCE; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief -typedef enum GAME_KEY_MOD -{ - /// @brief - GAME_KEY_MOD_NONE = 0x0000, - - /// @brief - GAME_KEY_MOD_SHIFT = 0x0001, - - /// @brief - GAME_KEY_MOD_CTRL = 0x0002, - - /// @brief - GAME_KEY_MOD_ALT = 0x0004, - - /// @brief - GAME_KEY_MOD_META = 0x0008, - - /// @brief - GAME_KEY_MOD_SUPER = 0x0010, - - /// @brief - GAME_KEY_MOD_NUMLOCK = 0x0100, - - /// @brief - GAME_KEY_MOD_CAPSLOCK = 0x0200, - - /// @brief - GAME_KEY_MOD_SCROLLOCK = 0x0400, -} GAME_KEY_MOD; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Type of port on the virtual game console -typedef enum GAME_PORT_TYPE -{ - /// @brief Game port unknown - GAME_PORT_UNKNOWN, - - /// @brief Game port Keyboard - GAME_PORT_KEYBOARD, - - /// @brief Game port mouse - GAME_PORT_MOUSE, - - /// @brief Game port controller - GAME_PORT_CONTROLLER, -} GAME_PORT_TYPE; -//------------------------------------------------------------------------------ - -/*! \cond PRIVATE */ -/*! - * @brief "C" Game add-on controller layout. - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref AddonGameControllerLayout for description of values. - */ -typedef struct game_controller_layout -{ - char* controller_id; - bool provides_input; // False for multitaps - char** digital_buttons; - unsigned int digital_button_count; - char** analog_buttons; - unsigned int analog_button_count; - char** analog_sticks; - unsigned int analog_stick_count; - char** accelerometers; - unsigned int accelerometer_count; - char** keys; - unsigned int key_count; - char** rel_pointers; - unsigned int rel_pointer_count; - char** abs_pointers; - unsigned int abs_pointer_count; - char** motors; - unsigned int motor_count; -} ATTRIBUTE_PACKED game_controller_layout; - /*! \endcond */ - -//============================================================================== -/// @brief -struct AddonGameControllerLayout -{ - /*! \cond PRIVATE */ - explicit AddonGameControllerLayout() = default; - AddonGameControllerLayout(const game_controller_layout& layout) - { - controller_id = layout.controller_id; - provides_input = layout.provides_input; - for (unsigned int i = 0; i < layout.digital_button_count; ++i) - digital_buttons.push_back(layout.digital_buttons[i]); - for (unsigned int i = 0; i < layout.analog_button_count; ++i) - analog_buttons.push_back(layout.analog_buttons[i]); - for (unsigned int i = 0; i < layout.analog_stick_count; ++i) - analog_sticks.push_back(layout.analog_sticks[i]); - for (unsigned int i = 0; i < layout.accelerometer_count; ++i) - accelerometers.push_back(layout.accelerometers[i]); - for (unsigned int i = 0; i < layout.key_count; ++i) - keys.push_back(layout.keys[i]); - for (unsigned int i = 0; i < layout.rel_pointer_count; ++i) - rel_pointers.push_back(layout.rel_pointers[i]); - for (unsigned int i = 0; i < layout.abs_pointer_count; ++i) - abs_pointers.push_back(layout.abs_pointers[i]); - for (unsigned int i = 0; i < layout.motor_count; ++i) - motors.push_back(layout.motors[i]); - } - /*! \endcond */ - - /// @brief - std::string controller_id; - - /// @brief False for multitaps - bool provides_input; - - /// @brief - std::vector digital_buttons; - - /// @brief - std::vector analog_buttons; - - /// @brief - std::vector analog_sticks; - - /// @brief - std::vector accelerometers; - - /// @brief - std::vector keys; - - /// @brief - std::vector rel_pointers; - - /// @brief - std::vector abs_pointers; - - /// @brief - std::vector motors; -}; -//------------------------------------------------------------------------------ - -struct game_input_port; - -//============================================================================== -/// @brief Device that can provide input -typedef struct game_input_device -{ - /// @brief ID used in the Kodi controller API - const char* controller_id; - - /// @brief - const char* port_address; - - /// @brief - game_input_port* available_ports; - - /// @brief - unsigned int port_count; -} ATTRIBUTE_PACKED game_input_device; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief Port that can provide input -/// -/// Ports can accept multiple devices and devices can have multiple ports, so -/// the topology of possible configurations is a tree structure of alternating -/// port and device nodes. -/// -typedef struct game_input_port -{ - /// @brief - GAME_PORT_TYPE type; - - /// @brief Required for GAME_PORT_CONTROLLER type - const char* port_id; - - /// @brief - game_input_device* accepted_devices; - - /// @brief - unsigned int device_count; -} ATTRIBUTE_PACKED game_input_port; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief The input topology is the possible ways to connect input devices -/// -/// This represents the logical topology, which is the possible connections that -/// the game client's logic can handle. It is strictly a subset of the physical -/// topology. Loops are not allowed. -/// -typedef struct game_input_topology -{ - /// @brief The list of ports on the virtual game console - game_input_port *ports; - - /// @brief The number of ports - unsigned int port_count; - - /// @brief A limit on the number of input-providing devices, or -1 for no limit - int player_limit; -} ATTRIBUTE_PACKED game_input_topology; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief -typedef struct game_digital_button_event -{ - /// @brief - bool pressed; -} ATTRIBUTE_PACKED game_digital_button_event; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief -typedef struct game_analog_button_event -{ - /// @brief - float magnitude; -} ATTRIBUTE_PACKED game_analog_button_event; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief -typedef struct game_axis_event -{ - /// @brief - float position; -} ATTRIBUTE_PACKED game_axis_event; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief -typedef struct game_analog_stick_event -{ - /// @brief - float x; - - /// @brief - float y; -} ATTRIBUTE_PACKED game_analog_stick_event; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief -typedef struct game_accelerometer_event -{ - /// @brief - float x; - - /// @brief - float y; - - /// @brief - float z; -} ATTRIBUTE_PACKED game_accelerometer_event; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief -typedef struct game_key_event -{ - /// @brief - bool pressed; - - /// @brief If the keypress generates a printing character - /// - /// The unicode value contains the character generated. If the key is a - /// non-printing character, e.g. a function or arrow key, the unicode value - /// is zero. - uint32_t unicode; - - /// @brief - GAME_KEY_MOD modifiers; -} ATTRIBUTE_PACKED game_key_event; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief -typedef struct game_rel_pointer_event -{ - /// @brief - int x; - - /// @brief - int y; -} ATTRIBUTE_PACKED game_rel_pointer_event; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief -typedef struct game_abs_pointer_event -{ - /// @brief - bool pressed; - - /// @brief - float x; - - /// @brief - float y; -} ATTRIBUTE_PACKED game_abs_pointer_event; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief -typedef struct game_motor_event -{ - /// @brief - float magnitude; -} ATTRIBUTE_PACKED game_motor_event; -//------------------------------------------------------------------------------ - -//============================================================================== -/// @brief -typedef struct game_input_event -{ - /// @brief - GAME_INPUT_EVENT_SOURCE type; - - /// @brief - const char* controller_id; - - /// @brief - GAME_PORT_TYPE port_type; - - /// @brief - const char* port_address; - - /// @brief - const char* feature_name; - union { - /// @brief - struct game_digital_button_event digital_button; - - /// @brief - struct game_analog_button_event analog_button; - - /// @brief - struct game_axis_event axis; - - /// @brief - struct game_analog_stick_event analog_stick; - - /// @brief - struct game_accelerometer_event accelerometer; - - /// @brief - struct game_key_event key; - - /// @brief - struct game_rel_pointer_event rel_pointer; - - /// @brief - struct game_abs_pointer_event abs_pointer; - - /// @brief - struct game_motor_event motor; - }; -} ATTRIBUTE_PACKED game_input_event; -//------------------------------------------------------------------------------ - -//@} - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- -/// \defgroup cpp_kodi_addon_game_Defs_EnvironmentTypes 8. Environment types -/// \ingroup cpp_kodi_addon_game_Defs -/// @brief **Environment types** -/// -//@{ - -//============================================================================== -/// @brief Game system timing -/// -struct game_system_timing -{ - /// @brief FPS of video content. - double fps; - - /// @brief Sampling rate of audio. - double sample_rate; -}; -//------------------------------------------------------------------------------ - -//@} - - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- - -/*! - * @brief Game properties - * - * Not to be used outside this header. - */ -typedef struct AddonProps_Game -{ - /*! - * The path of the game client being loaded. - */ - const char* game_client_dll_path; - - /*! - * Paths to proxy DLLs used to load the game client. - */ - const char** proxy_dll_paths; - - /*! - * Number of proxy DLL paths provided. - */ - unsigned int proxy_dll_count; - - /*! - * The "system" directories of the frontend. These directories can be used to - * store system-specific ROMs such as BIOSes, configuration data, etc. - */ - const char** resource_directories; - - /*! - * Number of resource directories provided - */ - unsigned int resource_directory_count; - - /*! - * The writable directory of the frontend. This directory can be used to store - * SRAM, memory cards, high scores, etc, if the game client cannot use the - * regular memory interface, GetMemoryData(). - */ - const char* profile_directory; - - /*! - * The value of the property from addon.xml - */ - bool supports_vfs; - - /*! - * The extensions in the property from addon.xml - */ - const char** extensions; - - /*! - * Number of extensions provided - */ - unsigned int extension_count; -} AddonProps_Game; - -typedef AddonProps_Game game_client_properties; - -/*! Structure to transfer the methods from kodi_game_dll.h to Kodi */ - -struct AddonInstance_Game; - -/*! - * @brief Game callbacks - * - * Not to be used outside this header. - */ -typedef struct AddonToKodiFuncTable_Game -{ - KODI_HANDLE kodiInstance; - - void (*CloseGame)(void* kodiInstance); - void* (*OpenStream)(void*, const game_stream_properties*); - bool (*GetStreamBuffer)(void*, void*, unsigned int, unsigned int, game_stream_buffer*); - void (*AddStreamData)(void*, void*, const game_stream_packet*); - void (*ReleaseStreamBuffer)(void*, void*, game_stream_buffer*); - void (*CloseStream)(void*, void*); - game_proc_address_t (*HwGetProcAddress)(void* kodiInstance, const char* symbol); - bool (*InputEvent)(void* kodiInstance, const game_input_event* event); -} AddonToKodiFuncTable_Game; - -/*! - * @brief Game function hooks - * - * Not to be used outside this header. - */ -typedef struct KodiToAddonFuncTable_Game -{ - kodi::addon::CInstanceGame* addonInstance; - - GAME_ERROR(__cdecl* LoadGame)(const AddonInstance_Game*, const char*); - GAME_ERROR(__cdecl* LoadGameSpecial) - (const AddonInstance_Game*, SPECIAL_GAME_TYPE, const char**, size_t); - GAME_ERROR(__cdecl* LoadStandalone)(const AddonInstance_Game*); - GAME_ERROR(__cdecl* UnloadGame)(const AddonInstance_Game*); - GAME_ERROR(__cdecl* GetGameTiming)(const AddonInstance_Game*, game_system_timing*); - GAME_REGION(__cdecl* GetRegion)(const AddonInstance_Game*); - bool(__cdecl* RequiresGameLoop)(const AddonInstance_Game*); - GAME_ERROR(__cdecl* RunFrame)(const AddonInstance_Game*); - GAME_ERROR(__cdecl* Reset)(const AddonInstance_Game*); - GAME_ERROR(__cdecl* HwContextReset)(const AddonInstance_Game*); - GAME_ERROR(__cdecl* HwContextDestroy)(const AddonInstance_Game*); - bool(__cdecl* HasFeature)(const AddonInstance_Game*, const char*, const char*); - game_input_topology*(__cdecl* GetTopology)(const AddonInstance_Game*); - void(__cdecl* FreeTopology)(const AddonInstance_Game*, game_input_topology*); - void(__cdecl* SetControllerLayouts)(const AddonInstance_Game*, - const game_controller_layout*, - unsigned int); - bool(__cdecl* EnableKeyboard)(const AddonInstance_Game*, bool, const char*); - bool(__cdecl* EnableMouse)(const AddonInstance_Game*, bool, const char*); - bool(__cdecl* ConnectController)(const AddonInstance_Game*, bool, const char*, const char*); - bool(__cdecl* InputEvent)(const AddonInstance_Game*, const game_input_event*); - size_t(__cdecl* SerializeSize)(const AddonInstance_Game*); - GAME_ERROR(__cdecl* Serialize)(const AddonInstance_Game*, uint8_t*, size_t); - GAME_ERROR(__cdecl* Deserialize)(const AddonInstance_Game*, const uint8_t*, size_t); - GAME_ERROR(__cdecl* CheatReset)(const AddonInstance_Game*); - GAME_ERROR(__cdecl* GetMemory)(const AddonInstance_Game*, GAME_MEMORY, uint8_t**, size_t*); - GAME_ERROR(__cdecl* SetCheat)(const AddonInstance_Game*, unsigned int, bool, const char*); -} KodiToAddonFuncTable_Game; - -/*! - * @brief Game instance - * - * Not to be used outside this header. - */ -typedef struct AddonInstance_Game -{ - AddonProps_Game props; - AddonToKodiFuncTable_Game toKodi; - KodiToAddonFuncTable_Game toAddon; -} AddonInstance_Game; - -} /* extern "C" */ - -namespace kodi -{ -namespace addon -{ - -//============================================================================== -/// -/// \addtogroup cpp_kodi_addon_game -/// @brief \cpp_class{ kodi::addon::CInstanceGame } -/// **Game add-on instance** -/// -/// This class is created at addon by Kodi. -/// -//------------------------------------------------------------------------------ -class ATTRIBUTE_HIDDEN CInstanceGame : public IAddonInstance -{ -public: - //============================================================================ - /// - /// @defgroup cpp_kodi_addon_game_Base 1. Basic functions - /// @ingroup cpp_kodi_addon_game - /// @brief **Functions to manage the addon and get basic information about it** - /// - /// - //@{ - - //============================================================================ - /// - /// @brief Game class constructor - /// - /// Used by an add-on that only supports only Game and only in one instance. - /// - /// This class is created at addon by Kodi. - /// - /// - /// -------------------------------------------------------------------------- - /// - /// - /// **Here's example about the use of this:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// ... - /// - /// class ATTRIBUTE_HIDDEN CGameExample - /// : public kodi::addon::CAddonBase, - /// public kodi::addon::CInstanceGame - /// { - /// public: - /// CGameExample() - /// { - /// } - /// - /// virtual ~CGameExample(); - /// { - /// } - /// - /// ... - /// }; - /// - /// ADDONCREATOR(CGameExample) - /// ~~~~~~~~~~~~~ - /// - CInstanceGame() : IAddonInstance(ADDON_INSTANCE_GAME, GetKodiTypeVersion(ADDON_INSTANCE_GAME)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstanceGame: Creation of more as one in single " - "instance way is not allowed!"); - - SetAddonStruct(CAddonBase::m_interface->firstKodiInstance); - CAddonBase::m_interface->globalSingleInstance = this; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Destructor - /// - ~CInstanceGame() override = default; - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief **Callback to Kodi Function**
The path of the game client being loaded. - /// - /// @return the used game client Dll path - /// - /// @remarks Only called from addon itself - /// - std::string GameClientDllPath() const - { - return m_instanceData->props.game_client_dll_path; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief **Callback to Kodi Function**
Paths to proxy DLLs used to load the game client. - /// - /// @param[out] paths vector list to store available dll paths - /// @return true if success and dll paths present - /// - /// @remarks Only called from addon itself - /// - bool ProxyDllPaths(std::vector& paths) - { - for (unsigned int i = 0; i < m_instanceData->props.proxy_dll_count; ++i) - { - if (m_instanceData->props.proxy_dll_paths[i] != nullptr) - paths.push_back(m_instanceData->props.proxy_dll_paths[i]); - } - return !paths.empty(); - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief **Callback to Kodi Function**
The "system" directories of the frontend - /// - /// These directories can be used to store system-specific ROMs such as - /// BIOSes, configuration data, etc. - /// - /// @return the used resource directory - /// - /// @remarks Only called from addon itself - /// - bool ResourceDirectories(std::vector& dirs) - { - for (unsigned int i = 0; i < m_instanceData->props.resource_directory_count; ++i) - { - if (m_instanceData->props.resource_directories[i] != nullptr) - dirs.push_back(m_instanceData->props.resource_directories[i]); - } - return !dirs.empty(); - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief **Callback to Kodi Function**
The writable directory of the frontend - /// - /// This directory can be used to store SRAM, memory cards, high scores, - /// etc, if the game client cannot use the regular memory interface, - /// GetMemoryData(). - /// - /// @return the used profile directory - /// - /// @remarks Only called from addon itself - /// - std::string ProfileDirectory() const - { - return m_instanceData->props.profile_directory; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief **Callback to Kodi Function**
The value of the property from addon.xml - /// - /// @return true if VFS is supported - /// - /// @remarks Only called from addon itself - /// - bool SupportsVFS() const - { - return m_instanceData->props.supports_vfs; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief **Callback to Kodi Function**
The extensions in the property from addon.xml - /// - /// @param[out] extensions vector list to store available extension - /// @return true if success and extensions present - /// - /// @remarks Only called from addon itself - /// - bool Extensions(std::vector& extensions) - { - for (unsigned int i = 0; i < m_instanceData->props.extension_count; ++i) - { - if (m_instanceData->props.extensions[i] != nullptr) - extensions.push_back(m_instanceData->props.extensions[i]); - } - return !extensions.empty(); - } - //---------------------------------------------------------------------------- - - //@} - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- - - //============================================================================ - /// - /// @defgroup cpp_kodi_addon_game_Operation 2. Game operations - /// @ingroup cpp_kodi_addon_game - /// @brief **Game operations** - /// - /// These are mandatory functions for using this addon to get the available - /// channels. - /// - //@{ - - //============================================================================ - /// - /// @brief Load a game - /// - /// @param[in] url The URL to load - /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was loaded - /// - virtual GAME_ERROR LoadGame(const std::string& url) - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Load a game that requires multiple files - /// - /// @param[in] type The game type - /// @param[in] urls An array of urls - /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was loaded - /// - virtual GAME_ERROR LoadGameSpecial(SPECIAL_GAME_TYPE type, const std::vector& urls) - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Begin playing without a game file - /// - /// If the add-on supports standalone mode, it must add the - /// tag to the extension point in addon.xml: - /// - /// false - /// - /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game add-on was loaded - /// - virtual GAME_ERROR LoadStandalone() - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Unload the current game - /// - /// Unloads a currently loaded game - /// - /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was unloaded - /// - virtual GAME_ERROR UnloadGame() - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Get timing information about the loaded game - /// - /// @param[out] timing_info The info structure to fill - /// - /// @return the error, or @ref GAME_ERROR_NO_ERROR if info was filled - /// - virtual GAME_ERROR GetGameTiming(game_system_timing& timing_info) - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Get region of the loaded game - /// - /// @return the region, or @ref GAME_REGION_UNKNOWN if unknown or no game is loaded - /// - virtual GAME_REGION GetRegion() - { - return GAME_REGION_UNKNOWN; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Return true if the client requires the frontend to provide a game loop - /// - /// The game loop is a thread that calls RunFrame() in a loop at a rate - /// determined by the playback speed and the client's FPS. - /// - /// @return true if the frontend should provide a game loop, false otherwise - /// - virtual bool RequiresGameLoop() - { - return false; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Run a single frame for add-ons that use a game loop - /// - /// @return the error, or @ref GAME_ERROR_NO_ERROR if there was no error - /// - virtual GAME_ERROR RunFrame() - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Reset the current game - /// - /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was reset - /// - virtual GAME_ERROR Reset() - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //========================================================================== - /// - /// @brief **Callback to Kodi Function**
Requests the frontend to stop the current game - /// - /// @remarks Only called from addon itself - /// - void CloseGame(void) { m_instanceData->toKodi.CloseGame(m_instanceData->toKodi.kodiInstance); } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @defgroup cpp_kodi_addon_game_Operation_CStream Class: CStream - /// @ingroup cpp_kodi_addon_game_Operation - /// @brief \cpp_class{ kodi::addon::CInstanceGame::CStream } - /// **Game stream handler** - /// - /// This class will be integrated into the addon, which can then open it if - /// necessary for the processing of an audio or video stream. - /// - /// - /// @note Callback to Kodi class - //@{ - class CStream - { - public: - CStream() = default; - - CStream(const game_stream_properties& properties) - { - Open(properties); - } - - ~CStream() - { - Close(); - } - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_game_Operation_CStream - /// @brief Create a stream for gameplay data - /// - /// @param[in] properties The stream properties - /// @return A stream handle, or `nullptr` on failure - /// - /// @remarks Only called from addon itself - /// - bool Open(const game_stream_properties& properties) - { - if (!CAddonBase::m_interface->globalSingleInstance) - return false; - - if (m_handle) - { - kodi::Log(ADDON_LOG_INFO, "kodi::addon::CInstanceGame::CStream already becomes reopened"); - Close(); - } - - AddonToKodiFuncTable_Game& cb = - static_cast(CAddonBase::m_interface->globalSingleInstance) - ->m_instanceData->toKodi; - m_handle = cb.OpenStream(cb.kodiInstance, &properties); - return m_handle != nullptr; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_game_Operation_CStream - /// @brief Free the specified stream - /// - /// @remarks Only called from addon itself - /// - void Close() - { - if (!m_handle || !CAddonBase::m_interface->globalSingleInstance) - return; - - AddonToKodiFuncTable_Game& cb = - static_cast(CAddonBase::m_interface->globalSingleInstance) - ->m_instanceData->toKodi; - cb.CloseStream(cb.kodiInstance, m_handle); - m_handle = nullptr; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_game_Operation_CStream - /// @brief Get a buffer for zero-copy stream data - /// - /// @param[in] width The framebuffer width, or 0 for no width specified - /// @param[in] height The framebuffer height, or 0 for no height specified - /// @param[out] buffer The buffer, or unmodified if false is returned - /// @return True if buffer was set, false otherwise - /// - /// @note If this returns true, buffer must be freed using \ref ReleaseBuffer(). - /// - /// @remarks Only called from addon itself - /// - bool GetBuffer(unsigned int width, unsigned int height, game_stream_buffer& buffer) - { - if (!m_handle || !CAddonBase::m_interface->globalSingleInstance) - return false; - - AddonToKodiFuncTable_Game& cb = - static_cast(CAddonBase::m_interface->globalSingleInstance) - ->m_instanceData->toKodi; - return cb.GetStreamBuffer(cb.kodiInstance, m_handle, width, height, &buffer); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_game_Operation_CStream - /// @brief Add a data packet to a stream - /// - /// @param[in] packet The data packet - /// - /// @remarks Only called from addon itself - /// - void AddData(const game_stream_packet& packet) - { - if (!m_handle || !CAddonBase::m_interface->globalSingleInstance) - return; - - AddonToKodiFuncTable_Game& cb = - static_cast(CAddonBase::m_interface->globalSingleInstance) - ->m_instanceData->toKodi; - cb.AddStreamData(cb.kodiInstance, m_handle, &packet); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_game_Operation_CStream - /// @brief Free an allocated buffer - /// - /// @param[in] buffer The buffer returned from GetStreamBuffer() - /// - /// @remarks Only called from addon itself - /// - void ReleaseBuffer(game_stream_buffer& buffer) - { - if (!m_handle || !CAddonBase::m_interface->globalSingleInstance) - return; - - AddonToKodiFuncTable_Game& cb = - static_cast(CAddonBase::m_interface->globalSingleInstance) - ->m_instanceData->toKodi; - cb.ReleaseStreamBuffer(cb.kodiInstance, m_handle, &buffer); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_game_Operation_CStream - /// @brief To check stream open was OK, e.g. after use of constructor - /// - /// @return true if stream was successfully opened - /// - /// @remarks Only called from addon itself - /// - bool IsOpen() const { return m_handle != nullptr; } - //-------------------------------------------------------------------------- - - private: - void* m_handle = nullptr; - }; - //@} - - //@} - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- - - //============================================================================ - /// - /// @defgroup cpp_kodi_addon_game_HardwareRendering 3. Hardware rendering operations - /// @ingroup cpp_kodi_addon_game - /// @brief **Hardware rendering operations** - /// - //@{ - - //============================================================================ - /// - /// @brief Invalidates the current HW context and reinitializes GPU resources - /// - /// Any GL state is lost, and must not be deinitialized explicitly. - /// - /// @return the error, or @ref GAME_ERROR_NO_ERROR if the HW context was reset - /// - virtual GAME_ERROR HwContextReset() - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Called before the context is destroyed - /// - /// Resources can be deinitialized at this step. - /// - /// @return the error, or @ref GAME_ERROR_NO_ERROR if the HW context was destroyed - /// - virtual GAME_ERROR HwContextDestroy() - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - - //============================================================================ - /// - /// @brief **Callback to Kodi Function**
Get a symbol from the hardware context - /// - /// @param[in] sym The symbol's name - /// - /// @return A function pointer for the specified symbol - /// - /// @remarks Only called from addon itself - /// - game_proc_address_t HwGetProcAddress(const char* sym) - { - return m_instanceData->toKodi.HwGetProcAddress(m_instanceData->toKodi.kodiInstance, sym); - } - //---------------------------------------------------------------------------- - - //@} - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- - - //============================================================================ - /// - /// @defgroup cpp_kodi_addon_game_InputOperations 4. Input operations - /// @ingroup cpp_kodi_addon_game - /// @brief **Input operations** - /// - //@{ - - //============================================================================ - /// - /// @brief Check if input is accepted for a feature on the controller - /// - /// If only a subset of the controller profile is used, this can return false - /// for unsupported features to not absorb their input. - /// - /// If the entire controller profile is used, this should always return true. - /// - /// @param[in] controller_id The ID of the controller profile - /// @param[in] feature_name The name of a feature in that profile - /// @return true if input is accepted for the feature, false otherwise - /// - virtual bool HasFeature(const std::string& controller_id, const std::string& feature_name) - { - return false; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Get the input topology that specifies which controllers can be connected - /// - /// @return The input topology, or null to use the default - /// - /// If this returns non-null, topology must be freed using FreeTopology(). - /// - /// If this returns null, the topology will default to a single port that can - /// accept all controllers imported by addon.xml. The port ID is set to - /// the @ref DEFAULT_PORT_ID constant. - /// - virtual game_input_topology* GetTopology() - { - return nullptr; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Free the topology's resources - /// - /// @param[in] topology The topology returned by GetTopology() - /// - virtual void FreeTopology(game_input_topology* topology) - { - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Set the layouts for known controllers - /// - /// @param[in] controllers The controller layouts - /// - /// After loading the input topology, the frontend will call this with - /// controller layouts for all controllers discovered in the topology. - /// - virtual void SetControllerLayouts(const std::vector& controllers) - { - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Enable/disable keyboard input using the specified controller - /// - /// @param[in] enable True to enable input, false otherwise - /// @param[in] controller_id The controller ID if enabling, or unused if disabling - /// - /// @return True if keyboard input was enabled, false otherwise - /// - virtual bool EnableKeyboard(bool enable, const std::string& controller_id) - { - return false; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Enable/disable mouse input using the specified controller - /// - /// @param[in] enable True to enable input, false otherwise - /// @param[in] controller_id The controller ID if enabling, or unused if disabling - /// - /// @return True if mouse input was enabled, false otherwise - /// - virtual bool EnableMouse(bool enable, const std::string& controller_id) - { - return false; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @brief Connect/disconnect a controller to a port on the virtual game console - /// - /// @param[in] connect True to connect a controller, false to disconnect - /// @param[in] port_address The address of the port - /// @param[in] controller_id The controller ID if connecting, or unused if disconnecting - /// @return True if the \p controller was (dis-)connected to the port, false otherwise - /// - /// The address is a string that allows traversal of the controller topology. - /// It is formed by alternating port IDs and controller IDs separated by "/". - /// - /// For example, assume that the topology represented in XML for Snes9x is: - /// - /// ~~~~~~~~~~~~~{.xml} - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// ... - /// - /// - /// - /// ~~~~~~~~~~~~~ - /// - /// To connect a multitap to the console's first port, the multitap's controller - /// info is set using the port address: - /// - /// 1 - /// - /// To connect a SNES controller to the second port of the multitap, the - /// controller info is next set using the address: - /// - /// 1/game.controller.multitap/2 - /// - /// Any attempts to connect a controller to a port on a disconnected multitap - /// will return false. - /// - virtual bool ConnectController(bool connect, - const std::string& port_address, - const std::string& controller_id) - { - return false; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Notify the add-on of an input event - /// - /// @param[in] event The input event - /// - /// @return true if the event was handled, false otherwise - /// - virtual bool InputEvent(const game_input_event& event) - { - return false; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief **Callback to Kodi Function**
Notify the port of an input event - /// - /// @param[in] event The input event - /// @return true if the event was handled, false otherwise - /// - /// @note Input events can arrive for the following sources: - /// - \ref GAME_INPUT_EVENT_MOTOR - /// - /// @remarks Only called from addon itself - /// - bool KodiInputEvent(const game_input_event& event) - { - return m_instanceData->toKodi.InputEvent(m_instanceData->toKodi.kodiInstance, &event); - } - //---------------------------------------------------------------------------- - - //@} - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- - - //============================================================================ - /// - /// @defgroup cpp_kodi_addon_game_SerializationOperations 5. Serialization operations - /// @ingroup cpp_kodi_addon_game - /// @brief **Serialization operations** - /// - //@{ - - //============================================================================ - /// - /// @brief Get the number of bytes required to serialize the game - /// - /// @return the number of bytes, or 0 if serialization is not supported - /// - virtual size_t SerializeSize() - { - return 0; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Serialize the state of the game - /// - /// @param[in] data The buffer receiving the serialized game data - /// @param[in] size The size of the buffer - /// - /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was serialized into the buffer - /// - virtual GAME_ERROR Serialize(uint8_t* data, size_t size) - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Deserialize the game from the given state - /// - /// @param[in] data A buffer containing the game's new state - /// @param[in] size The size of the buffer - /// - /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game deserialized - /// - virtual GAME_ERROR Deserialize(const uint8_t* data, size_t size) - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //@} - -//--==----==----==----==----==----==----==----==----==----==----==----==----==-- - - //============================================================================ - /// - /// @defgroup cpp_kodi_addon_game_CheatOperations 6. Cheat operations - /// @ingroup cpp_kodi_addon_game - /// @brief **Cheat operations** - /// - //@{ - - //============================================================================ - /// - /// @brief Reset the cheat system - /// - /// @return the error, or @ref GAME_ERROR_NO_ERROR if the cheat system was reset - /// - virtual GAME_ERROR CheatReset() - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Get a region of memory - /// - /// @param[in] type The type of memory to retrieve - /// @param[in] data Set to the region of memory; must remain valid until UnloadGame() is called - /// @param[in] size Set to the size of the region of memory - /// - /// @return the error, or @ref GAME_ERROR_NO_ERROR if data was set to a valid buffer - /// - virtual GAME_ERROR GetMemory(GAME_MEMORY type, uint8_t*& data, size_t& size) - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Set a cheat code - /// - /// @param[in] index - /// @param[in] enabled - /// @param[in] code - /// - /// @return the error, or @ref GAME_ERROR_NO_ERROR if the cheat was set - /// - virtual GAME_ERROR SetCheat(unsigned int index, bool enabled, const std::string& code) - { - return GAME_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //@} - -private: - void SetAddonStruct(KODI_HANDLE instance) - { - if (instance == nullptr) - throw std::logic_error("kodi::addon::CInstanceGame: Creation with empty addon structure not" - "allowed, table must be given from Kodi!"); - - m_instanceData = static_cast(instance); - m_instanceData->toAddon.addonInstance = this; - - m_instanceData->toAddon.LoadGame = ADDON_LoadGame; - m_instanceData->toAddon.LoadGameSpecial = ADDON_LoadGameSpecial; - m_instanceData->toAddon.LoadStandalone = ADDON_LoadStandalone; - m_instanceData->toAddon.UnloadGame = ADDON_UnloadGame; - m_instanceData->toAddon.GetGameTiming = ADDON_GetGameTiming; - m_instanceData->toAddon.GetRegion = ADDON_GetRegion; - m_instanceData->toAddon.RequiresGameLoop = ADDON_RequiresGameLoop; - m_instanceData->toAddon.RunFrame = ADDON_RunFrame; - m_instanceData->toAddon.Reset = ADDON_Reset; - - m_instanceData->toAddon.HwContextReset = ADDON_HwContextReset; - m_instanceData->toAddon.HwContextDestroy = ADDON_HwContextDestroy; - - m_instanceData->toAddon.HasFeature = ADDON_HasFeature; - m_instanceData->toAddon.GetTopology = ADDON_GetTopology; - m_instanceData->toAddon.FreeTopology = ADDON_FreeTopology; - m_instanceData->toAddon.SetControllerLayouts = ADDON_SetControllerLayouts; - m_instanceData->toAddon.EnableKeyboard = ADDON_EnableKeyboard; - m_instanceData->toAddon.EnableMouse = ADDON_EnableMouse; - m_instanceData->toAddon.ConnectController = ADDON_ConnectController; - m_instanceData->toAddon.InputEvent = ADDON_InputEvent; - - m_instanceData->toAddon.SerializeSize = ADDON_SerializeSize; - m_instanceData->toAddon.Serialize = ADDON_Serialize; - m_instanceData->toAddon.Deserialize = ADDON_Deserialize; - - m_instanceData->toAddon.CheatReset = ADDON_CheatReset; - m_instanceData->toAddon.GetMemory = ADDON_GetMemory; - m_instanceData->toAddon.SetCheat = ADDON_SetCheat; - } - - // --- Game operations --------------------------------------------------------- - - inline static GAME_ERROR ADDON_LoadGame(const AddonInstance_Game* instance, const char* url) - { - return instance->toAddon.addonInstance->LoadGame(url); - } - - inline static GAME_ERROR ADDON_LoadGameSpecial(const AddonInstance_Game* instance, - SPECIAL_GAME_TYPE type, - const char** urls, - size_t urlCount) - { - std::vector urlList; - for (size_t i = 0; i < urlCount; ++i) - { - if (urls[i] != nullptr) - urlList.push_back(urls[i]); - } - - return instance->toAddon.addonInstance->LoadGameSpecial(type, urlList); - } - - inline static GAME_ERROR ADDON_LoadStandalone(const AddonInstance_Game* instance) - { - return instance->toAddon.addonInstance->LoadStandalone(); - } - - inline static GAME_ERROR ADDON_UnloadGame(const AddonInstance_Game* instance) - { - return instance->toAddon.addonInstance->UnloadGame(); - } - - inline static GAME_ERROR ADDON_GetGameTiming(const AddonInstance_Game* instance, - game_system_timing* timing_info) - { - return instance->toAddon.addonInstance->GetGameTiming(*timing_info); - } - - inline static GAME_REGION ADDON_GetRegion(const AddonInstance_Game* instance) - { - return instance->toAddon.addonInstance->GetRegion(); - } - - inline static bool ADDON_RequiresGameLoop(const AddonInstance_Game* instance) - { - return instance->toAddon.addonInstance->RequiresGameLoop(); - } - - inline static GAME_ERROR ADDON_RunFrame(const AddonInstance_Game* instance) - { - return instance->toAddon.addonInstance->RunFrame(); - } - - inline static GAME_ERROR ADDON_Reset(const AddonInstance_Game* instance) - { - return instance->toAddon.addonInstance->Reset(); - } - - - // --- Hardware rendering operations ------------------------------------------- - - inline static GAME_ERROR ADDON_HwContextReset(const AddonInstance_Game* instance) - { - return instance->toAddon.addonInstance->HwContextReset(); - } - - inline static GAME_ERROR ADDON_HwContextDestroy(const AddonInstance_Game* instance) - { - return instance->toAddon.addonInstance->HwContextDestroy(); - } - - - // --- Input operations -------------------------------------------------------- - - inline static bool ADDON_HasFeature(const AddonInstance_Game* instance, - const char* controller_id, - const char* feature_name) - { - return instance->toAddon.addonInstance->HasFeature(controller_id, feature_name); - } - - inline static game_input_topology* ADDON_GetTopology(const AddonInstance_Game* instance) - { - return instance->toAddon.addonInstance->GetTopology(); - } - - inline static void ADDON_FreeTopology(const AddonInstance_Game* instance, - game_input_topology* topology) - { - instance->toAddon.addonInstance->FreeTopology(topology); - } - - inline static void ADDON_SetControllerLayouts(const AddonInstance_Game* instance, - const game_controller_layout* controllers, - unsigned int controller_count) - { - if (controllers == nullptr) - return; - - std::vector controllerList; - for (unsigned int i = 0; i < controller_count; ++i) - controllerList.push_back(controllers[i]); - - instance->toAddon.addonInstance->SetControllerLayouts(controllerList); - } - - inline static bool ADDON_EnableKeyboard(const AddonInstance_Game* instance, - bool enable, - const char* controller_id) - { - return instance->toAddon.addonInstance->EnableKeyboard(enable, controller_id); - } - - inline static bool ADDON_EnableMouse(const AddonInstance_Game* instance, - bool enable, - const char* controller_id) - { - return instance->toAddon.addonInstance->EnableMouse(enable, controller_id); - } - - inline static bool ADDON_ConnectController(const AddonInstance_Game* instance, - bool connect, - const char* port_address, - const char* controller_id) - { - return instance->toAddon.addonInstance->ConnectController(connect, port_address, controller_id); - } - - inline static bool ADDON_InputEvent(const AddonInstance_Game* instance, - const game_input_event* event) - { - return instance->toAddon.addonInstance->InputEvent(*event); - } - - - // --- Serialization operations ------------------------------------------------ - - inline static size_t ADDON_SerializeSize(const AddonInstance_Game* instance) - { - return instance->toAddon.addonInstance->SerializeSize(); - } - - inline static GAME_ERROR ADDON_Serialize(const AddonInstance_Game* instance, - uint8_t* data, - size_t size) - { - return instance->toAddon.addonInstance->Serialize(data, size); - } - - inline static GAME_ERROR ADDON_Deserialize(const AddonInstance_Game* instance, - const uint8_t* data, - size_t size) - { - return instance->toAddon.addonInstance->Deserialize(data, size); - } - - - // --- Cheat operations -------------------------------------------------------- - - inline static GAME_ERROR ADDON_CheatReset(const AddonInstance_Game* instance) - { - return instance->toAddon.addonInstance->CheatReset(); - } - - inline static GAME_ERROR ADDON_GetMemory(const AddonInstance_Game* instance, - GAME_MEMORY type, - uint8_t** data, - size_t* size) - { - return instance->toAddon.addonInstance->GetMemory(type, *data, *size); - } - - inline static GAME_ERROR ADDON_SetCheat(const AddonInstance_Game* instance, - unsigned int index, - bool enabled, - const char* code) - { - return instance->toAddon.addonInstance->SetCheat(index, enabled, code); - } - - AddonInstance_Game* m_instanceData; -}; - -} /* namespace addon */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/ImageDecoder.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/ImageDecoder.h deleted file mode 100644 index e41e5ef..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/ImageDecoder.h +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../AddonBase.h" -#include "../c-api/addon-instance/image_decoder.h" - -#ifdef __cplusplus -namespace kodi -{ -namespace addon -{ - -//############################################################################## -/// @defgroup cpp_kodi_addon_imagedecoder_Defs Definitions, structures and enumerators -/// @ingroup cpp_kodi_addon_imagedecoder -/// @brief **Image decoder add-on general variables** -/// -/// Used to exchange the available options between Kodi and addon. -/// -/// - -//============================================================================== -/// -/// @addtogroup cpp_kodi_addon_imagedecoder -/// @brief @cpp_class{ kodi::addon::CInstanceImageDecoder } -/// **Image decoder add-on instance**\n -/// This instance type is used to allow Kodi various additional image format -/// types. -/// -/// This usage can be requested under various conditions, by a Mimetype protocol -/// defined in `addon.xml` or supported file extensions. -/// -/// Include the header @ref ImageDecoder.h "#include " -/// to use this class. -/// -/// ---------------------------------------------------------------------------- -/// -/// Here is an example of what the `addon.xml.in` would look like for an -/// image decoder addon: -/// -/// ~~~~~~~~~~~~~{.xml} -/// -/// -/// @ADDON_DEPENDS@ -/// -/// -/// My image decoder addon summary -/// My image decoder description -/// @PLATFORM@ -/// -/// -/// ~~~~~~~~~~~~~ -/// -/// ### Standard values that can be declared for processing in `addon.xml`. -/// -/// These values are used by Kodi to identify associated images and file -/// extensions and then to select the associated addon. -/// -/// \table_start -/// \table_h3{ Labels, Type, Description } -/// \table_row3{ `point`, -/// @anchor cpp_kodi_addon_imagedecoder_point -/// string, -/// The identification of the addon instance to image decoder is mandatory -/// `kodi.imagedecoder`. In addition\, the instance declared in the -/// first `` is also the main type of addon. -/// } -/// \table_row3{ `extension`, -/// @anchor cpp_kodi_addon_imagedecoder_defaultPort -/// string, -/// The from addon operated and supported image file endings.\n -/// Use a `|` to separate between different ones. -/// } -/// \table_row3{ `defaultPort`, -/// @anchor cpp_kodi_addon_imagedecoder_defaultPort -/// string, -/// The from addon operated image [mimetypes](https://en.wikipedia.org/wiki/Media_type).\n -/// Use a `|` to separate between different ones. -/// } -/// \table_row3{ `library_@PLATFORM@`, -/// @anchor cpp_kodi_addon_imagedecoder_library -/// string, -/// The runtime library used for the addon. This is usually declared by `cmake` and correctly displayed in the translated `addon.xml`. -/// } -/// \table_end -/// -/// @remark For more detailed description of the `addon.xml`, see also https://kodi.wiki/view/Addon.xml. -/// -/// -/// -------------------------------------------------------------------------- -/// -/// -/// **Example:** -/// -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// class ATTRIBUTE_HIDDEN CMyImageDecoder : public kodi::addon::CInstanceImageDecoder -/// { -/// public: -/// CMyImageDecoder(KODI_HANDLE instance, const std::string& kodiVersion); -/// -/// bool LoadImageFromMemory(unsigned char* buffer, -/// unsigned int bufSize, -/// unsigned int& width, -/// unsigned int& height) override; -/// -/// bool Decode(unsigned char* pixels, -/// unsigned int width, -/// unsigned int height, -/// unsigned int pitch, -/// ImageFormat format) override; -/// -/// ... -/// }; -/// -/// CMyImageDecoder::CMyImageDecoder(KODI_HANDLE instance, const std::string& kodiVersion) -/// : CInstanceImageDecoder(instance, kodiVersion) -/// { -/// ... -/// } -/// -/// bool CMyImageDecoder::LoadImageFromMemory(unsigned char* buffer, -/// unsigned int bufSize, -/// unsigned int& width, -/// unsigned int& height) -/// { -/// ... -/// return true; -/// } -/// -/// bool CMyImageDecoder::Decode(unsigned char* pixels, -/// unsigned int width, -/// unsigned int height, -/// unsigned int pitch, -/// ImageFormat format) override; -/// { -/// ... -/// return true; -/// } -/// -/// //---------------------------------------------------------------------- -/// -/// class ATTRIBUTE_HIDDEN CMyAddon : public kodi::addon::CAddonBase -/// { -/// public: -/// CMyAddon() = default; -/// ADDON_STATUS CreateInstance(int instanceType, -/// const std::string& instanceID, -/// KODI_HANDLE instance, -/// const std::string& version, -/// KODI_HANDLE& addonInstance) override; -/// }; -/// -/// // If you use only one instance in your add-on, can be instanceType and -/// // instanceID ignored -/// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, -/// const std::string& instanceID, -/// KODI_HANDLE instance, -/// const std::string& version, -/// KODI_HANDLE& addonInstance) -/// { -/// if (instanceType == ADDON_INSTANCE_IMAGEDECODER) -/// { -/// kodi::Log(ADDON_LOG_NOTICE, "Creating my image decoder instance"); -/// addonInstance = new CMyImageDecoder(instance, version); -/// return ADDON_STATUS_OK; -/// } -/// else if (...) -/// { -/// ... -/// } -/// return ADDON_STATUS_UNKNOWN; -/// } -/// -/// ADDONCREATOR(CMyAddon) -/// ~~~~~~~~~~~~~ -/// -/// The destruction of the example class `CMyImageDecoder` is called from -/// Kodi's header. Manually deleting the add-on instance is not required. -/// -//------------------------------------------------------------------------------ -class ATTRIBUTE_HIDDEN CInstanceImageDecoder : public IAddonInstance -{ -public: - //============================================================================ - /// @ingroup cpp_kodi_addon_imagedecoder - /// @brief Class constructor. - /// - /// @param[in] instance The from Kodi given instance given be add-on - /// CreateInstance call with instance id - /// @ref ADDON_INSTANCE_IMAGEDECODER. - /// @param[in] kodiVersion [opt] Version used in Kodi for this instance, to - /// allow compatibility to older Kodi versions. - /// - /// @note Recommended to set `kodiVersion`. - /// - explicit CInstanceImageDecoder(KODI_HANDLE instance, const std::string& kodiVersion = "") - : IAddonInstance(ADDON_INSTANCE_IMAGEDECODER, - !kodiVersion.empty() ? kodiVersion - : GetKodiTypeVersion(ADDON_INSTANCE_IMAGEDECODER)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstanceImageDecoder: Creation of multiple together " - "with single instance way is not allowed!"); - - SetAddonStruct(instance); - } - //---------------------------------------------------------------------------- - - ~CInstanceImageDecoder() override = default; - - //============================================================================ - /// @ingroup cpp_kodi_addon_imagedecoder - /// @brief Initialize an encoder. - /// - /// @param[in] buffer The data to read from memory - /// @param[in] bufSize The buffer size - /// @param[in,out] width The optimal width of image on entry, obtained width - /// on return - /// @param[in,out] height The optimal height of image, actual obtained height - /// on return - /// @return true if successful done, false on error - /// - virtual bool LoadImageFromMemory(unsigned char* buffer, - unsigned int bufSize, - unsigned int& width, - unsigned int& height) = 0; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_imagedecoder - /// @brief Decode previously loaded image. - /// - /// @param[in] pixels Output buffer - /// @param[in] width Width of output image - /// @param[in] height Height of output image - /// @param[in] pitch Pitch of output image - /// @param[in] format Format of output image - /// @return true if successful done, false on error - /// - virtual bool Decode(unsigned char* pixels, - unsigned int width, - unsigned int height, - unsigned int pitch, - ImageFormat format) = 0; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_imagedecoder - /// @brief **Callback to Kodi Function**\n - /// Get the wanted mime type from Kodi. - /// - /// @return the mimetype wanted from Kodi - /// - /// @remarks Only called from addon itself. - /// - inline std::string MimeType() { return m_instanceData->props->mimetype; } - //---------------------------------------------------------------------------- - -private: - void SetAddonStruct(KODI_HANDLE instance) - { - if (instance == nullptr) - throw std::logic_error("kodi::addon::CInstanceImageDecoder: Creation with empty addon " - "structure not allowed, table must be given from Kodi!"); - - m_instanceData = static_cast(instance); - m_instanceData->toAddon->addonInstance = this; - m_instanceData->toAddon->load_image_from_memory = ADDON_LoadImageFromMemory; - m_instanceData->toAddon->decode = ADDON_Decode; - } - - inline static bool ADDON_LoadImageFromMemory(const AddonInstance_ImageDecoder* instance, - unsigned char* buffer, - unsigned int bufSize, - unsigned int* width, - unsigned int* height) - { - return static_cast(instance->toAddon->addonInstance) - ->LoadImageFromMemory(buffer, bufSize, *width, *height); - } - - inline static bool ADDON_Decode(const AddonInstance_ImageDecoder* instance, - unsigned char* pixels, - unsigned int width, - unsigned int height, - unsigned int pitch, - enum ImageFormat format) - { - return static_cast(instance->toAddon->addonInstance) - ->Decode(pixels, width, height, pitch, format); - } - - AddonInstance_ImageDecoder* m_instanceData; -}; - -} /* namespace addon */ -} /* namespace kodi */ -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h deleted file mode 100644 index 354806e..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h +++ /dev/null @@ -1,881 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -/* - * Parts with a comment named "internal" are only used inside header and not - * used or accessed direct during add-on development! - */ - -#include "../AddonBase.h" -#include "../StreamCodec.h" -#include "../StreamCrypto.h" - -#ifdef BUILD_KODI_ADDON -#include "../DemuxPacket.h" -#include "../InputStreamConstants.h" -#else -#include "cores/VideoPlayer/Interface/Addon/DemuxPacket.h" -#include "cores/VideoPlayer/Interface/Addon/InputStreamConstants.h" -#endif - -//Increment this level always if you add features which can lead to compile failures in the addon -#define INPUTSTREAM_VERSION_LEVEL 2 - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - /*! - * @brief InputStream add-on capabilities. All capabilities are set to "false" as default. - */ - struct INPUTSTREAM_CAPABILITIES - { - enum MASKTYPE : uint32_t - { - /// supports interface IDemux - SUPPORTS_IDEMUX = (1 << 0), - - /// supports interface IPosTime - SUPPORTS_IPOSTIME = (1 << 1), - - /// supports interface IDisplayTime - SUPPORTS_IDISPLAYTIME = (1 << 2), - - /// supports seek - SUPPORTS_SEEK = (1 << 3), - - /// supports pause - SUPPORTS_PAUSE = (1 << 4), - - /// supports interface ITime - SUPPORTS_ITIME = (1 << 5), - - /// supports interface IChapter - SUPPORTS_ICHAPTER = (1 << 6), - }; - - /// set of supported capabilities - uint32_t m_mask; - }; - - /*! - * @brief structure of key/value pairs passed to addon on Open() - */ - struct INPUTSTREAM - { - const char* m_strURL; - const char* m_mimeType; - - unsigned int m_nCountInfoValues; - struct LISTITEMPROPERTY - { - const char* m_strKey; - const char* m_strValue; - } m_ListItemProperties[STREAM_MAX_PROPERTY_COUNT]; - - const char* m_libFolder; - const char* m_profileFolder; - }; - - /*! - * @brief Array of stream IDs - */ - struct INPUTSTREAM_IDS - { - static const unsigned int MAX_STREAM_COUNT = 256; - unsigned int m_streamCount; - unsigned int m_streamIds[MAX_STREAM_COUNT]; - }; - - /*! - * @brief MASTERING Metadata - */ - struct INPUTSTREAM_MASTERING_METADATA - { - double primary_r_chromaticity_x; - double primary_r_chromaticity_y; - double primary_g_chromaticity_x; - double primary_g_chromaticity_y; - double primary_b_chromaticity_x; - double primary_b_chromaticity_y; - double white_point_chromaticity_x; - double white_point_chromaticity_y; - double luminance_max; - double luminance_min; - }; - - /*! - * @brief CONTENTLIGHT Metadata - */ - struct INPUTSTREAM_CONTENTLIGHT_METADATA - { - uint64_t max_cll; - uint64_t max_fall; - }; - - /*! - * @brief stream properties - */ - struct INPUTSTREAM_INFO - { - enum STREAM_TYPE - { - TYPE_NONE = 0, - TYPE_VIDEO, - TYPE_AUDIO, - TYPE_SUBTITLE, - TYPE_TELETEXT, - TYPE_RDS, - } m_streamType; - - enum Codec_FEATURES : uint32_t - { - FEATURE_DECODE = 1 - }; - uint32_t m_features; - - enum STREAM_FLAGS : uint32_t - { - FLAG_NONE = 0x0000, - FLAG_DEFAULT = 0x0001, - FLAG_DUB = 0x0002, - FLAG_ORIGINAL = 0x0004, - FLAG_COMMENT = 0x0008, - FLAG_LYRICS = 0x0010, - FLAG_KARAOKE = 0x0020, - FLAG_FORCED = 0x0040, - FLAG_HEARING_IMPAIRED = 0x0080, - FLAG_VISUAL_IMPAIRED = 0x0100, - }; - - // Keep in sync with AVColorSpace - enum COLORSPACE - { - COLORSPACE_RGB = 0, - COLORSPACE_BT709 = 1, - COLORSPACE_UNSPECIFIED = 2, - COLORSPACE_UNKNOWN = COLORSPACE_UNSPECIFIED, // compatibility - COLORSPACE_RESERVED = 3, - COLORSPACE_FCC = 4, - COLORSPACE_BT470BG = 5, - COLORSPACE_SMPTE170M = 6, - COLORSPACE_SMPTE240M = 7, - COLORSPACE_YCGCO = 8, - COLORSPACE_YCOCG = COLORSPACE_YCGCO, - COLORSPACE_BT2020_NCL = 9, - COLORSPACE_BT2020_CL = 10, - COLORSPACE_SMPTE2085 = 11, - COLORSPACE_CHROMA_DERIVED_NCL = 12, - COLORSPACE_CHROMA_DERIVED_CL = 13, - COLORSPACE_ICTCP = 14, - COLORSPACE_MAX - }; - - // Keep in sync with AVColorPrimaries - enum COLORPRIMARIES : int32_t - { - COLORPRIMARY_RESERVED0 = 0, - COLORPRIMARY_BT709 = 1, - COLORPRIMARY_UNSPECIFIED = 2, - COLORPRIMARY_RESERVED = 3, - COLORPRIMARY_BT470M = 4, - COLORPRIMARY_BT470BG = 5, - COLORPRIMARY_SMPTE170M = 6, - COLORPRIMARY_SMPTE240M = 7, - COLORPRIMARY_FILM = 8, - COLORPRIMARY_BT2020 = 9, - COLORPRIMARY_SMPTE428 = 10, - COLORPRIMARY_SMPTEST428_1 = COLORPRIMARY_SMPTE428, - COLORPRIMARY_SMPTE431 = 11, - COLORPRIMARY_SMPTE432 = 12, - COLORPRIMARY_JEDEC_P22 = 22, - COLORPRIMARY_MAX - }; - - // Keep in sync with AVColorRange - enum COLORRANGE - { - COLORRANGE_UNKNOWN = 0, - COLORRANGE_LIMITED, - COLORRANGE_FULLRANGE, - COLORRANGE_MAX - }; - - // keep in sync with AVColorTransferCharacteristic - enum COLORTRC : int32_t - { - COLORTRC_RESERVED0 = 0, - COLORTRC_BT709 = 1, - COLORTRC_UNSPECIFIED = 2, - COLORTRC_RESERVED = 3, - COLORTRC_GAMMA22 = 4, - COLORTRC_GAMMA28 = 5, - COLORTRC_SMPTE170M = 6, - COLORTRC_SMPTE240M = 7, - COLORTRC_LINEAR = 8, - COLORTRC_LOG = 9, - COLORTRC_LOG_SQRT = 10, - COLORTRC_IEC61966_2_4 = 11, - COLORTRC_BT1361_ECG = 12, - COLORTRC_IEC61966_2_1 = 13, - COLORTRC_BT2020_10 = 14, - COLORTRC_BT2020_12 = 15, - COLORTRC_SMPTE2084 = 16, - COLORTRC_SMPTEST2084 = COLORTRC_SMPTE2084, - COLORTRC_SMPTE428 = 17, - COLORTRC_SMPTEST428_1 = COLORTRC_SMPTE428, - COLORTRC_ARIB_STD_B67 = 18, - COLORTRC_MAX - }; - - uint32_t m_flags; - - char m_name[256]; /*!< @brief (optinal) name of the stream, \0 for default handling */ - char m_codecName[32]; /*!< @brief (required) name of codec according to ffmpeg */ - char m_codecInternalName - [32]; /*!< @brief (optional) internal name of codec (selectionstream info) */ - STREAMCODEC_PROFILE m_codecProfile; /*!< @brief (optional) the profile of the codec */ - unsigned int m_pID; /*!< @brief (required) physical index */ - - const uint8_t* m_ExtraData; - unsigned int m_ExtraSize; - - char m_language[64]; /*!< @brief RFC 5646 language code (empty string if undefined) */ - - unsigned int - m_FpsScale; /*!< @brief Scale of 1000 and a rate of 29970 will result in 29.97 fps */ - unsigned int m_FpsRate; - unsigned int m_Height; /*!< @brief height of the stream reported by the demuxer */ - unsigned int m_Width; /*!< @brief width of the stream reported by the demuxer */ - float m_Aspect; /*!< @brief display aspect of stream */ - - - unsigned int m_Channels; /*!< @brief (required) amount of channels */ - unsigned int m_SampleRate; /*!< @brief (required) sample rate */ - unsigned int m_BitRate; /*!< @brief (required) bit rate */ - unsigned int m_BitsPerSample; /*!< @brief (required) bits per sample */ - unsigned int m_BlockAlign; - - CRYPTO_INFO m_cryptoInfo; - - // new in API version 2.0.8 - unsigned int m_codecFourCC; /*!< @brief Codec If available, the fourcc code codec */ - COLORSPACE m_colorSpace; /*!< @brief definition of colorspace */ - COLORRANGE m_colorRange; /*!< @brief color range if available */ - - //new in API 2.0.9 / INPUTSTREAM_VERSION_LEVEL 1 - COLORPRIMARIES m_colorPrimaries; - COLORTRC m_colorTransferCharacteristic; - INPUTSTREAM_MASTERING_METADATA* m_masteringMetadata; /*!< @brief mastering static Metadata */ - INPUTSTREAM_CONTENTLIGHT_METADATA* - m_contentLightMetadata; /*!< @brief content light static Metadata */ - }; - - struct INPUTSTREAM_TIMES - { - time_t startTime; - double ptsStart; - double ptsBegin; - double ptsEnd; - }; - - /*! - * @brief "C" ABI Structures to transfer the methods from this to Kodi - */ - - // this are properties given to the addon on create - // at this time we have no parameters for the addon - typedef struct AddonProps_InputStream /* internal */ - { - int dummy; - } AddonProps_InputStream; - - typedef struct AddonToKodiFuncTable_InputStream /* internal */ - { - KODI_HANDLE kodiInstance; - DemuxPacket* (*allocate_demux_packet)(void* kodiInstance, int data_size); - DemuxPacket* (*allocate_encrypted_demux_packet)(void* kodiInstance, - unsigned int data_size, - unsigned int encrypted_subsample_count); - void (*free_demux_packet)(void* kodiInstance, DemuxPacket* packet); - } AddonToKodiFuncTable_InputStream; - - struct AddonInstance_InputStream; - typedef struct KodiToAddonFuncTable_InputStream /* internal */ - { - KODI_HANDLE addonInstance; - - bool(__cdecl* open)(const AddonInstance_InputStream* instance, INPUTSTREAM* props); - void(__cdecl* close)(const AddonInstance_InputStream* instance); - const char*(__cdecl* get_path_list)(const AddonInstance_InputStream* instance); - void(__cdecl* get_capabilities)(const AddonInstance_InputStream* instance, - INPUTSTREAM_CAPABILITIES* capabilities); - - // IDemux - struct INPUTSTREAM_IDS(__cdecl* get_stream_ids)(const AddonInstance_InputStream* instance); - struct INPUTSTREAM_INFO(__cdecl* get_stream)(const AddonInstance_InputStream* instance, - int streamid); - void(__cdecl* enable_stream)(const AddonInstance_InputStream* instance, - int streamid, - bool enable); - bool(__cdecl* open_stream)(const AddonInstance_InputStream* instance, int streamid); - void(__cdecl* demux_reset)(const AddonInstance_InputStream* instance); - void(__cdecl* demux_abort)(const AddonInstance_InputStream* instance); - void(__cdecl* demux_flush)(const AddonInstance_InputStream* instance); - DemuxPacket*(__cdecl* demux_read)(const AddonInstance_InputStream* instance); - bool(__cdecl* demux_seek_time)(const AddonInstance_InputStream* instance, - double time, - bool backwards, - double* startpts); - void(__cdecl* demux_set_speed)(const AddonInstance_InputStream* instance, int speed); - void(__cdecl* set_video_resolution)(const AddonInstance_InputStream* instance, - int width, - int height); - - // IDisplayTime - int(__cdecl* get_total_time)(const AddonInstance_InputStream* instance); - int(__cdecl* get_time)(const AddonInstance_InputStream* instance); - - // ITime - bool(__cdecl* get_times)(const AddonInstance_InputStream* instance, INPUTSTREAM_TIMES* times); - - // IPosTime - bool(__cdecl* pos_time)(const AddonInstance_InputStream* instance, int ms); - - int(__cdecl* read_stream)(const AddonInstance_InputStream* instance, - uint8_t* buffer, - unsigned int bufferSize); - int64_t(__cdecl* seek_stream)(const AddonInstance_InputStream* instance, - int64_t position, - int whence); - int64_t(__cdecl* position_stream)(const AddonInstance_InputStream* instance); - int64_t(__cdecl* length_stream)(const AddonInstance_InputStream* instance); - bool(__cdecl* is_real_time_stream)(const AddonInstance_InputStream* instance); - - // IChapter - int(__cdecl* get_chapter)(const AddonInstance_InputStream* instance); - int(__cdecl* get_chapter_count)(const AddonInstance_InputStream* instance); - const char*(__cdecl* get_chapter_name)(const AddonInstance_InputStream* instance, int ch); - int64_t(__cdecl* get_chapter_pos)(const AddonInstance_InputStream* instance, int ch); - bool(__cdecl* seek_chapter)(const AddonInstance_InputStream* instance, int ch); - - int(__cdecl* block_size_stream)(const AddonInstance_InputStream* instance); - } KodiToAddonFuncTable_InputStream; - - typedef struct AddonInstance_InputStream /* internal */ - { - AddonProps_InputStream props; - AddonToKodiFuncTable_InputStream toKodi; - KodiToAddonFuncTable_InputStream toAddon; - } AddonInstance_InputStream; - -#ifdef __cplusplus -} /* extern "C" */ - -namespace kodi -{ -namespace addon -{ - -class ATTRIBUTE_HIDDEN CInstanceInputStream : public IAddonInstance -{ -public: - explicit CInstanceInputStream(KODI_HANDLE instance, const std::string& kodiVersion = "") - : IAddonInstance(ADDON_INSTANCE_INPUTSTREAM, - !kodiVersion.empty() ? kodiVersion - : GetKodiTypeVersion(ADDON_INSTANCE_INPUTSTREAM)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstanceInputStream: Creation of multiple together " - "with single instance way is not allowed!"); - - SetAddonStruct(instance, m_kodiVersion); - } - - ~CInstanceInputStream() override = default; - - /*! - * Open a stream. - * @param props - * @return True if the stream has been opened successfully, false otherwise. - * @remarks - */ - virtual bool Open(INPUTSTREAM& props) = 0; - - /*! - * Close an open stream. - * @remarks - */ - virtual void Close() = 0; - - /*! - * Get Capabilities of this addon. - * @param capabilities The add-on's capabilities. - * @remarks - */ - virtual void GetCapabilities(INPUTSTREAM_CAPABILITIES& capabilities) = 0; - - /*! - * Get IDs of available streams - * @remarks - */ - virtual INPUTSTREAM_IDS GetStreamIds() = 0; - - /*! - * Get stream properties of a stream. - * @param streamid unique id of stream - * @return struc of stream properties - * @remarks - */ - virtual INPUTSTREAM_INFO GetStream(int streamid) = 0; - - /*! - * Enable or disable a stream. - * A disabled stream does not send demux packets - * @param streamid unique id of stream - * @param enable true for enable, false for disable - * @remarks - */ - virtual void EnableStream(int streamid, bool enable) = 0; - - /*! - * Opens a stream for playback. - * @param streamid unique id of stream - * @remarks - */ - virtual bool OpenStream(int streamid) = 0; - - /*! - * Reset the demultiplexer in the add-on. - * @remarks Required if bHandlesDemuxing is set to true. - */ - virtual void DemuxReset() {} - - /*! - * Abort the demultiplexer thread in the add-on. - * @remarks Required if bHandlesDemuxing is set to true. - */ - virtual void DemuxAbort() {} - - /*! - * Flush all data that's currently in the demultiplexer buffer in the add-on. - * @remarks Required if bHandlesDemuxing is set to true. - */ - virtual void DemuxFlush() {} - - /*! - * Read the next packet from the demultiplexer, if there is one. - * @return The next packet. - * If there is no next packet, then the add-on should return the - * packet created by calling AllocateDemuxPacket(0) on the callback. - * If the stream changed and Kodi's player needs to be reinitialised, - * then, the add-on should call AllocateDemuxPacket(0) on the - * callback, and set the streamid to DMX_SPECIALID_STREAMCHANGE and - * return the value. - * The add-on should return NULL if an error occurred. - * @remarks Return NULL if this add-on won't provide this function. - */ - virtual DemuxPacket* DemuxRead() { return nullptr; } - - /*! - * Notify the InputStream addon/demuxer that Kodi wishes to seek the stream by time - * Demuxer is required to set stream to an IDR frame - * @param time The absolute time since stream start - * @param backwards True to seek to keyframe BEFORE time, else AFTER - * @param startpts can be updated to point to where display should start - * @return True if the seek operation was possible - * @remarks Optional, and only used if addon has its own demuxer. - */ - virtual bool DemuxSeekTime(double time, bool backwards, double& startpts) { return false; } - - /*! - * Notify the InputStream addon/demuxer that Kodi wishes to change playback speed - * @param speed The requested playback speed - * @remarks Optional, and only used if addon has its own demuxer. - */ - virtual void DemuxSetSpeed(int speed) {} - - /*! - * Sets desired width / height - * @param width / hight - */ - virtual void SetVideoResolution(int width, int height) {} - - /*! - * Totel time in ms - * @remarks - */ - virtual int GetTotalTime() { return -1; } - - /*! - * Playing time in ms - * @remarks - */ - virtual int GetTime() { return -1; } - - /*! - * Get current timing values in PTS scale - * @remarks - */ - virtual bool GetTimes(INPUTSTREAM_TIMES& times) { return false; } - - /*! - * Positions inputstream to playing time given in ms - * @remarks - */ - virtual bool PosTime(int ms) { return false; } - - /*! - * Return currently selected chapter - * @remarks - */ - virtual int GetChapter() { return -1; }; - - /*! - * Return number of available chapters - * @remarks - */ - virtual int GetChapterCount() { return 0; }; - - /*! - * Return name of chapter # ch - * @remarks - */ - virtual const char* GetChapterName(int ch) { return nullptr; }; - - /*! - * Return position if chapter # ch in milliseconds - * @remarks - */ - virtual int64_t GetChapterPos(int ch) { return 0; }; - - /*! - * Seek to the beginning of chapter # ch - * @remarks - */ - virtual bool SeekChapter(int ch) { return false; }; - - /*! - * Read from an open stream. - * @param buffer The buffer to store the data in. - * @param bufferSize The amount of bytes to read. - * @return The amount of bytes that were actually read from the stream. - * @remarks Return -1 if this add-on won't provide this function. - */ - virtual int ReadStream(uint8_t* buffer, unsigned int bufferSize) { return -1; } - - /*! - * Seek in a stream. - * @param position The position to seek to. - * @param whence ? - * @return The new position. - * @remarks Return -1 if this add-on won't provide this function. - */ - virtual int64_t SeekStream(int64_t position, int whence = SEEK_SET) { return -1; } - - /*! - * @return The position in the stream that's currently being read. - * @remarks Return -1 if this add-on won't provide this function. - */ - virtual int64_t PositionStream() { return -1; } - - /*! - * @return The total length of the stream that's currently being read. - * @remarks Return -1 if this add-on won't provide this function. - */ - virtual int64_t LengthStream() { return -1; } - - /*! - * @return Obtain the chunk size to use when reading streams. - * @remarks Return 0 if this add-on won't provide this function. - */ - virtual int GetBlockSize() { return 0; } - - /*! - * Check for real-time streaming - * @return true if current stream is real-time - */ - virtual bool IsRealTimeStream() { return true; } - - /*! - * @brief Allocate a demux packet. Free with FreeDemuxPacket - * @param dataSize The size of the data that will go into the packet - * @return The allocated packet - */ - DemuxPacket* AllocateDemuxPacket(int dataSize) - { - return m_instanceData->toKodi.allocate_demux_packet(m_instanceData->toKodi.kodiInstance, - dataSize); - } - - /*! - * @brief Allocate a demux packet. Free with FreeDemuxPacket - * @param dataSize The size of the data that will go into the packet - * @return The allocated packet - */ - DemuxPacket* AllocateEncryptedDemuxPacket(int dataSize, unsigned int encryptedSubsampleCount) - { - return m_instanceData->toKodi.allocate_encrypted_demux_packet( - m_instanceData->toKodi.kodiInstance, dataSize, encryptedSubsampleCount); - } - - /*! - * @brief Free a packet that was allocated with AllocateDemuxPacket - * @param packet The packet to free - */ - void FreeDemuxPacket(DemuxPacket* packet) - { - return m_instanceData->toKodi.free_demux_packet(m_instanceData->toKodi.kodiInstance, packet); - } - -private: - static int compareVersion(const int v1[3], const int v2[3]) - { - for (unsigned i(0); i < 3; ++i) - if (v1[i] != v2[i]) - return v1[i] - v2[i]; - return 0; - } - - void SetAddonStruct(KODI_HANDLE instance, const std::string& kodiVersion) - { - if (instance == nullptr) - throw std::logic_error("kodi::addon::CInstanceInputStream: Creation with empty addon " - "structure not allowed, table must be given from Kodi!"); - int api[3] = { 0, 0, 0 }; - sscanf(kodiVersion.c_str(), "%d.%d.%d", &api[0], &api[1], &api[2]); - - m_instanceData = static_cast(instance); - m_instanceData->toAddon.addonInstance = this; - m_instanceData->toAddon.open = ADDON_Open; - m_instanceData->toAddon.close = ADDON_Close; - m_instanceData->toAddon.get_capabilities = ADDON_GetCapabilities; - - m_instanceData->toAddon.get_stream_ids = ADDON_GetStreamIds; - m_instanceData->toAddon.get_stream = ADDON_GetStream; - m_instanceData->toAddon.enable_stream = ADDON_EnableStream; - m_instanceData->toAddon.open_stream = ADDON_OpenStream; - m_instanceData->toAddon.demux_reset = ADDON_DemuxReset; - m_instanceData->toAddon.demux_abort = ADDON_DemuxAbort; - m_instanceData->toAddon.demux_flush = ADDON_DemuxFlush; - m_instanceData->toAddon.demux_read = ADDON_DemuxRead; - m_instanceData->toAddon.demux_seek_time = ADDON_DemuxSeekTime; - m_instanceData->toAddon.demux_set_speed = ADDON_DemuxSetSpeed; - m_instanceData->toAddon.set_video_resolution = ADDON_SetVideoResolution; - - m_instanceData->toAddon.get_total_time = ADDON_GetTotalTime; - m_instanceData->toAddon.get_time = ADDON_GetTime; - - m_instanceData->toAddon.get_times = ADDON_GetTimes; - m_instanceData->toAddon.pos_time = ADDON_PosTime; - - m_instanceData->toAddon.read_stream = ADDON_ReadStream; - m_instanceData->toAddon.seek_stream = ADDON_SeekStream; - m_instanceData->toAddon.position_stream = ADDON_PositionStream; - m_instanceData->toAddon.length_stream = ADDON_LengthStream; - m_instanceData->toAddon.is_real_time_stream = ADDON_IsRealTimeStream; - - int minChapterVersion[3] = { 2, 0, 10 }; - if (compareVersion(api, minChapterVersion) >= 0) - { - m_instanceData->toAddon.get_chapter = ADDON_GetChapter; - m_instanceData->toAddon.get_chapter_count = ADDON_GetChapterCount; - m_instanceData->toAddon.get_chapter_name = ADDON_GetChapterName; - m_instanceData->toAddon.get_chapter_pos = ADDON_GetChapterPos; - m_instanceData->toAddon.seek_chapter = ADDON_SeekChapter; - } - - int minBlockSizeVersion[3] = {2, 0, 12}; - if (compareVersion(api, minBlockSizeVersion) >= 0) - { - m_instanceData->toAddon.block_size_stream = ADDON_GetBlockSize; - } - } - - inline static bool ADDON_Open(const AddonInstance_InputStream* instance, INPUTSTREAM* props) - { - return static_cast(instance->toAddon.addonInstance)->Open(*props); - } - - inline static void ADDON_Close(const AddonInstance_InputStream* instance) - { - static_cast(instance->toAddon.addonInstance)->Close(); - } - - inline static void ADDON_GetCapabilities(const AddonInstance_InputStream* instance, - INPUTSTREAM_CAPABILITIES* capabilities) - { - static_cast(instance->toAddon.addonInstance) - ->GetCapabilities(*capabilities); - } - - - // IDemux - inline static struct INPUTSTREAM_IDS ADDON_GetStreamIds(const AddonInstance_InputStream* instance) - { - return static_cast(instance->toAddon.addonInstance)->GetStreamIds(); - } - - inline static struct INPUTSTREAM_INFO ADDON_GetStream(const AddonInstance_InputStream* instance, - int streamid) - { - return static_cast(instance->toAddon.addonInstance)->GetStream(streamid); - } - - inline static void ADDON_EnableStream(const AddonInstance_InputStream* instance, - int streamid, - bool enable) - { - static_cast(instance->toAddon.addonInstance) - ->EnableStream(streamid, enable); - } - - inline static bool ADDON_OpenStream(const AddonInstance_InputStream* instance, int streamid) - { - return static_cast(instance->toAddon.addonInstance) - ->OpenStream(streamid); - } - - inline static void ADDON_DemuxReset(const AddonInstance_InputStream* instance) - { - static_cast(instance->toAddon.addonInstance)->DemuxReset(); - } - - inline static void ADDON_DemuxAbort(const AddonInstance_InputStream* instance) - { - static_cast(instance->toAddon.addonInstance)->DemuxAbort(); - } - - inline static void ADDON_DemuxFlush(const AddonInstance_InputStream* instance) - { - static_cast(instance->toAddon.addonInstance)->DemuxFlush(); - } - - inline static DemuxPacket* ADDON_DemuxRead(const AddonInstance_InputStream* instance) - { - return static_cast(instance->toAddon.addonInstance)->DemuxRead(); - } - - inline static bool ADDON_DemuxSeekTime(const AddonInstance_InputStream* instance, - double time, - bool backwards, - double* startpts) - { - return static_cast(instance->toAddon.addonInstance) - ->DemuxSeekTime(time, backwards, *startpts); - } - - inline static void ADDON_DemuxSetSpeed(const AddonInstance_InputStream* instance, int speed) - { - static_cast(instance->toAddon.addonInstance)->DemuxSetSpeed(speed); - } - - inline static void ADDON_SetVideoResolution(const AddonInstance_InputStream* instance, - int width, - int height) - { - static_cast(instance->toAddon.addonInstance) - ->SetVideoResolution(width, height); - } - - - // IDisplayTime - inline static int ADDON_GetTotalTime(const AddonInstance_InputStream* instance) - { - return static_cast(instance->toAddon.addonInstance)->GetTotalTime(); - } - - inline static int ADDON_GetTime(const AddonInstance_InputStream* instance) - { - return static_cast(instance->toAddon.addonInstance)->GetTime(); - } - - // ITime - inline static bool ADDON_GetTimes(const AddonInstance_InputStream* instance, - INPUTSTREAM_TIMES* times) - { - return static_cast(instance->toAddon.addonInstance)->GetTimes(*times); - } - - // IPosTime - inline static bool ADDON_PosTime(const AddonInstance_InputStream* instance, int ms) - { - return static_cast(instance->toAddon.addonInstance)->PosTime(ms); - } - - inline static int ADDON_GetChapter(const AddonInstance_InputStream* instance) - { - return static_cast(instance->toAddon.addonInstance)->GetChapter(); - } - - inline static int ADDON_GetChapterCount(const AddonInstance_InputStream* instance) - { - return static_cast(instance->toAddon.addonInstance)->GetChapterCount(); - } - - inline static const char* ADDON_GetChapterName(const AddonInstance_InputStream* instance, int ch) - { - return static_cast(instance->toAddon.addonInstance)->GetChapterName(ch); - } - - inline static int64_t ADDON_GetChapterPos(const AddonInstance_InputStream* instance, int ch) - { - return static_cast(instance->toAddon.addonInstance)->GetChapterPos(ch); - } - - inline static bool ADDON_SeekChapter(const AddonInstance_InputStream* instance, int ch) - { - return static_cast(instance->toAddon.addonInstance)->SeekChapter(ch); - } - - inline static int ADDON_ReadStream(const AddonInstance_InputStream* instance, - uint8_t* buffer, - unsigned int bufferSize) - { - return static_cast(instance->toAddon.addonInstance) - ->ReadStream(buffer, bufferSize); - } - - inline static int64_t ADDON_SeekStream(const AddonInstance_InputStream* instance, - int64_t position, - int whence) - { - return static_cast(instance->toAddon.addonInstance) - ->SeekStream(position, whence); - } - - inline static int64_t ADDON_PositionStream(const AddonInstance_InputStream* instance) - { - return static_cast(instance->toAddon.addonInstance)->PositionStream(); - } - - inline static int64_t ADDON_LengthStream(const AddonInstance_InputStream* instance) - { - return static_cast(instance->toAddon.addonInstance)->LengthStream(); - } - - inline static int ADDON_GetBlockSize(const AddonInstance_InputStream* instance) - { - return static_cast(instance->toAddon.addonInstance)->GetBlockSize(); - } - - inline static bool ADDON_IsRealTimeStream(const AddonInstance_InputStream* instance) - { - return static_cast(instance->toAddon.addonInstance)->IsRealTimeStream(); - } - - AddonInstance_InputStream* m_instanceData; -}; - -} /* namespace addon */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/PVR.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/PVR.h deleted file mode 100644 index 0bca8e2..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/PVR.h +++ /dev/null @@ -1,3423 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../c-api/addon-instance/pvr.h" -#include "pvr/ChannelGroups.h" -#include "pvr/Channels.h" -#include "pvr/EDL.h" -#include "pvr/EPG.h" -#include "pvr/General.h" -#include "pvr/MenuHook.h" -#include "pvr/Recordings.h" -#include "pvr/Stream.h" -#include "pvr/Timers.h" - -#ifdef __cplusplus - -/*! - * @internal - * @brief PVR "C++" API interface - * - * In this field are the pure addon-side C++ data. - * - * @note Changes can be made without problems and have no influence on other - * PVR addons that have already been created.\n - * \n - * Therefore, @ref ADDON_INSTANCE_VERSION_PVR_MIN can be ignored for these - * fields and only the @ref ADDON_INSTANCE_VERSION_PVR needs to be increased.\n - * \n - * Only must be min version increased if a new compile of addon breaks after - * changes here. - * - * Have by add of new parts a look about **Doxygen** `\\ingroup`, so that - * added parts included in documentation. - * - * If you add addon side related documentation, where his dev need know, use `///`. - * For parts only for Kodi make it like here. - * - * @endinternal - */ - -namespace kodi -{ -namespace addon -{ - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" Doxygen group set for the definitions -//{{{ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs Definitions, structures and enumerators -/// @ingroup cpp_kodi_addon_pvr -/// @brief **PVR client add-on instance definition values**\n -/// All PVR functions associated data structures. -/// -/// Used to exchange the available options between Kodi and addon.\n -/// The groups described here correspond to the groups of functions on PVR -/// instance class. -/// - -//############################################################################## -/// @defgroup cpp_kodi_addon_pvr_Defs_General 1. General -/// @ingroup cpp_kodi_addon_pvr_Defs -/// @brief **PVR add-on general variables**\n -/// Used to exchange the available options between Kodi and addon. -/// -/// This group also includes @ref cpp_kodi_addon_pvr_Defs_PVRCapabilities with -/// which Kodi an @ref kodi::addon::CInstancePVRClient::GetCapabilities() -/// queries the supported **modules** of the addon. -/// -/// The standard values are also below, once for error messages and once to -/// @ref kodi::addon::CInstancePVRClient::ConnectionStateChange() to give Kodi -/// any information. -/// -///@{ -//############################################################################## -/// @defgroup cpp_kodi_addon_pvr_Defs_General_Inputstream class PVRStreamProperty & definition PVR_STREAM_PROPERTY -/// @ingroup cpp_kodi_addon_pvr_Defs_General -/// @brief **Inputstream variables**\n -/// This includes values related to the outside of PVR available inputstream -/// system. -/// -/// This can be by separate instance on same addon, by handling in Kodi itself -/// or to reference of another addon where support needed inputstream. -/// -/// @note This is complete independent from own system included here -/// @ref cpp_kodi_addon_pvr_Streams "inputstream". -/// -//------------------------------------------------------------------------------ -///@} - -//############################################################################## -/// @defgroup cpp_kodi_addon_pvr_Defs_Channel 2. Channel -/// @ingroup cpp_kodi_addon_pvr_Defs -/// @brief **PVR add-on channel**\n -/// Used to exchange the available channel options between Kodi and addon. -/// -/// Modules here are mainly intended for @ref cpp_kodi_addon_pvr_Channels "channels", -/// but are also used on other modules to identify the respective TV/radio -/// channel. -/// -/// Because of @ref cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus and -/// @ref cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo is a special case at -/// this point. This is currently only used on running streams, but it may be -/// possible that this must always be usable in connection with PiP in the -/// future. -/// -//------------------------------------------------------------------------------ - -//############################################################################## -/// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup 3. Channel Group -/// @ingroup cpp_kodi_addon_pvr_Defs -/// @brief **PVR add-on channel group**\n -/// This group contains data classes and values which are used in PVR on -/// @ref cpp_kodi_addon_pvr_supportsChannelGroups "channel groups". -/// -//------------------------------------------------------------------------------ - -//############################################################################## -/// @defgroup cpp_kodi_addon_pvr_Defs_epg 4. EPG Tag -/// @ingroup cpp_kodi_addon_pvr_Defs -/// @brief **PVR add-on EPG data**\n -/// Used on @ref cpp_kodi_addon_pvr_EPGTag "EPG methods in PVR instance class". -/// -/// See related modules about, also below in this view are few macros where -/// default values of associated places. -/// -//------------------------------------------------------------------------------ - -//############################################################################## -/// @defgroup cpp_kodi_addon_pvr_Defs_Recording 5. Recording -/// @ingroup cpp_kodi_addon_pvr_Defs -/// @brief **Representation of a recording**\n -/// Used to exchange the available recording data between Kodi and addon on -/// @ref cpp_kodi_addon_pvr_Recordings "Recordings methods in PVR instance class". -/// -//------------------------------------------------------------------------------ - -//############################################################################## -/// @defgroup cpp_kodi_addon_pvr_Defs_Timer 6. Timer -/// @ingroup cpp_kodi_addon_pvr_Defs -/// @brief **PVR add-on timer data**\n -/// Used to exchange the available timer data between Kodi and addon on -/// @ref cpp_kodi_addon_pvr_Timers "Timers methods in PVR instance class". -/// -//------------------------------------------------------------------------------ - -//############################################################################## -/// @defgroup cpp_kodi_addon_pvr_Defs_Menuhook 7. Menuhook -/// @ingroup cpp_kodi_addon_pvr_Defs -/// @brief **PVR Context menu data**\n -/// Define data for the context menus available to the user -/// -//------------------------------------------------------------------------------ - -//############################################################################## -/// @defgroup cpp_kodi_addon_pvr_Defs_EDLEntry 8. Edit decision list (EDL) -/// @ingroup cpp_kodi_addon_pvr_Defs -/// @brief **An edit decision list or EDL is used in the post-production process -/// of film editing and video editing**\n -/// Used on @ref kodi::addon::CInstancePVRClient::GetEPGTagEdl and -/// @ref kodi::addon::CInstancePVRClient::GetRecordingEdl -/// -//------------------------------------------------------------------------------ - -//############################################################################## -/// @defgroup cpp_kodi_addon_pvr_Defs_Stream 9. Inputstream -/// @ingroup cpp_kodi_addon_pvr_Defs -/// @brief **Inputstream**\n -/// This includes classes and values that are used in the PVR inputstream. -/// -/// Used on @ref cpp_kodi_addon_pvr_Streams "Inputstream methods in PVR instance class". -/// -/// @note The parts here will be removed in the future and replaced by the -/// separate @ref cpp_kodi_addon_inputstream "inputstream addon instance". -/// If there is already a possibility, new addons should do it via the -/// inputstream instance. -/// -//------------------------------------------------------------------------------ - -//}}} -//______________________________________________________________________________ - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" PVR addon instance class -//{{{ - -//============================================================================== -/// @addtogroup cpp_kodi_addon_pvr -/// @brief \cpp_class{ kodi::addon::CInstancePVRClient } -/// **PVR client add-on instance** -/// -/// Kodi features powerful [Live TV](https://kodi.wiki/view/Live_TV) and -/// [video recording (DVR/PVR)](http://en.wikipedia.org/wiki/Digital_video_recorder) -/// abilities using a very flexible distributed application structure. That is, by -/// leveraging other existing third-party -/// [PVR backend applications](https://kodi.wiki/view/PVR_backend) or -/// [DVR devices](https://kodi.wiki/view/PVR_backend) -/// that specialize in receiving television signals and also support the same type -/// of [client–server model](http://en.wikipedia.org/wiki/client%E2%80%93server_model) -/// which Kodi uses, (following a [frontend-backend](http://en.wikipedia.org/wiki/Front_and_back_ends) -/// design principle for [separation of concerns](http://en.wikipedia.org/wiki/Separation_of_concerns)), -/// these PVR features in Kodi allow you to watch Live TV, listen to radio, view an EPG TV-Guide -/// and schedule recordings, and also enables many other TV related features, all using -/// Kodi as your primary interface once the initial pairing connection and -/// configuration have been done. -/// -/// @note It is very important to understand that with "Live TV" in the reference -/// to PVR in Kodi, we do not mean [streaming video](http://en.wikipedia.org/wiki/Streaming_media) -/// from the internet via websites providing [free content](https://kodi.wiki/view/Free_content) -/// or online services such as Netflix, Hulu, Vudu and similar, no matter if that -/// content is actually streamed live or not. If that is what you are looking for -/// then you might want to look into [Video Addons](https://kodi.wiki/view/Add-ons) -/// for Kodi instead, (which again is not the same as the "PVR" or "Live TV" we -/// discuss in this article), but remember that [Kodi does not provide any video -/// content or video streaming services](https://kodi.wiki/view/Free_content). -/// -/// The use of the PVR is based on the @ref CInstancePVRClient. -/// -/// Include the header @ref PVR.h "#include " -/// to use this class. -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// Here is an example of what the `addon.xml.in` would look like for an PVR addon: -/// -/// ~~~~~~~~~~~~~{.xml} -/// -/// -/// @ADDON_DEPENDS@ -/// -/// -/// My PVR addon addon -/// My PVR addon description -/// @PLATFORM@ -/// -/// -/// ~~~~~~~~~~~~~ -/// -/// -/// At `` the basic instance definition is declared, this is intended to identify the addon as an PVR and to see its supported types: -/// | Name | Description -/// |------|---------------------- -/// | `point` | The identification of the addon instance to inputstream is mandatory `kodi.pvrclient`. In addition, the instance declared in the first `` is also the main type of addon. -/// | `library_@PLATFORM@` | The runtime library used for the addon. This is usually declared by cmake and correctly displayed in the translated `addon.xml`. -/// -/// -/// @remark For more detailed description of the `addon.xml`, see also https://kodi.wiki/view/Addon.xml. -/// -/// -/// -------------------------------------------------------------------------- -/// -/// **Example:** -/// -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// class CMyPVRClient : public ::kodi::addon::CInstancePVRClient -/// { -/// public: -/// CMyPVRClient(KODI_HANDLE instance, const std::string& kodiVersion); -/// -/// PVR_ERROR GetCapabilities(kodi::addon::PVRCapabilities& capabilities) override; -/// PVR_ERROR GetBackendName(std::string& name) override; -/// PVR_ERROR GetBackendVersion(std::string& version) override; -/// -/// PVR_ERROR GetChannelsAmount(int& amount) override; -/// PVR_ERROR GetChannels(bool radio, std::vector& channels) override; -/// PVR_ERROR GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, -/// std::vector& properties) override; -/// -/// private: -/// std::vector m_myChannels; -/// }; -/// -/// CMyPVRClient::CMyPVRClient(KODI_HANDLE instance, const std::string& kodiVersion) -/// : CInstancePVRClient(instance, kodiVersion) -/// { -/// kodi::addon::PVRChannel channel; -/// channel.SetUniqueId(123); -/// channel.SetChannelNumber(1); -/// channel.SetChannelName("My test channel"); -/// m_myChannels.push_back(channel); -/// } -/// -/// PVR_ERROR CMyPVRClient::GetCapabilities(kodi::addon::PVRCapabilities& capabilities) -/// { -/// capabilities.SetSupportsTV(true); -/// return PVR_ERROR_NO_ERROR; -/// } -/// -/// PVR_ERROR CMyPVRClient::GetBackendName(std::string& name) -/// { -/// name = "My special PVR client"; -/// return PVR_ERROR_NO_ERROR; -/// } -/// -/// PVR_ERROR CMyPVRClient::GetBackendVersion(std::string& version) -/// { -/// version = "1.0.0"; -/// return PVR_ERROR_NO_ERROR; -/// } -/// -/// PVR_ERROR CMyInstance::GetChannelsAmount(int& amount) -/// { -/// amount = m_myChannels.size(); -/// return PVR_ERROR_NO_ERROR; -/// } -/// -/// PVR_ERROR CMyPVRClient::GetChannels(bool radio, std::vector& channels) -/// { -/// channels = m_myChannels; -/// return PVR_ERROR_NO_ERROR; -/// } -/// -/// PVR_ERROR CMyPVRClient::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, -/// std::vector& properties) -/// { -/// if (channel.GetUniqueId() == 123) -/// { -/// properties.push_back(PVR_STREAM_PROPERTY_STREAMURL, "http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4"); -/// properties.push_back(PVR_STREAM_PROPERTY_ISREALTIMESTREAM, "true"); -/// return PVR_ERROR_NO_ERROR; -/// } -/// return PVR_ERROR_UNKNOWN; -/// } -/// -/// ... -/// -/// //---------------------------------------------------------------------- -/// -/// class CMyAddon : public ::kodi::addon::CAddonBase -/// { -/// public: -/// CMyAddon() = default; -/// ADDON_STATUS CreateInstance(int instanceType, -/// const std::string& instanceID, -/// KODI_HANDLE instance, -/// const std::string& version, -/// KODI_HANDLE& addonInstance) override; -/// }; -/// -/// // If you use only one instance in your add-on, can be instanceType and -/// // instanceID ignored -/// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, -/// const std::string& instanceID, -/// KODI_HANDLE instance, -/// const std::string& version, -/// KODI_HANDLE& addonInstance) -/// { -/// if (instanceType == ADDON_INSTANCE_PVR) -/// { -/// kodi::Log(ADDON_LOG_NOTICE, "Creating my PVR client instance"); -/// addonInstance = new CMyPVRClient(instance, version); -/// return ADDON_STATUS_OK; -/// } -/// else if (...) -/// { -/// ... -/// } -/// return ADDON_STATUS_UNKNOWN; -/// } -/// -/// ADDONCREATOR(CMyAddon) -/// ~~~~~~~~~~~~~ -/// -/// The destruction of the example class `CMyPVRClient` is called from -/// Kodi's header. Manually deleting the add-on instance is not required. -/// -class ATTRIBUTE_HIDDEN CInstancePVRClient : public IAddonInstance -{ -public: - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Base 1. Basic functions - /// @ingroup cpp_kodi_addon_pvr - /// @brief **Functions to manage the addon and get basic information about it**\n - /// These are e.g. @ref GetCapabilities to know supported groups at - /// this addon or the others to get information about the source of the PVR - /// stream. - /// - /// The with "Valid implementation required." declared functions are mandatory, - /// all others are an option. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Basic parts in interface:**\n - /// Copy this to your project and extend with your parts or leave functions - /// complete away where not used or supported. - /// - /// @copydetails cpp_kodi_addon_pvr_Base_header_addon_auto_check - /// @copydetails cpp_kodi_addon_pvr_Base_source_addon_auto_check - /// - ///@{ - - //============================================================================ - /// @brief PVR client class constructor. - /// - /// Used by an add-on that only supports only PVR and only in one instance. - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Here's example about the use of this:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// ... - /// - /// class ATTRIBUTE_HIDDEN CPVRExample - /// : public kodi::addon::CAddonBase, - /// public kodi::addon::CInstancePVRClient - /// { - /// public: - /// CPVRExample() - /// { - /// } - /// - /// ~CPVRExample() override; - /// { - /// } - /// - /// ... - /// }; - /// - /// ADDONCREATOR(CPVRExample) - /// ~~~~~~~~~~~~~ - /// - CInstancePVRClient() : IAddonInstance(ADDON_INSTANCE_PVR, GetKodiTypeVersion(ADDON_INSTANCE_PVR)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstancePVRClient: Creation of more as one in single " - "instance way is not allowed!"); - - SetAddonStruct(CAddonBase::m_interface->firstKodiInstance, m_kodiVersion); - CAddonBase::m_interface->globalSingleInstance = this; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief PVR client class constructor used to support multiple instance - /// types. - /// - /// @param[in] instance The instance value given to - /// `kodi::addon::CAddonBase::CreateInstance(...)`. - /// @param[in] kodiVersion [opt] Version used in Kodi for this instance, to - /// allow compatibility to older Kodi versions. - /// - /// @note Recommended to set `kodiVersion`. - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Here's example about the use of this:** - /// ~~~~~~~~~~~~~{.cpp} - /// class CMyPVRClient : public ::kodi::addon::CInstancePVRClient - /// { - /// public: - /// CMyPVRClient(KODI_HANDLE instance, const std::string& kodiVersion) - /// : CInstancePVRClient(instance, kodiVersion) - /// { - /// ... - /// } - /// - /// ... - /// }; - /// - /// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, - /// const std::string& instanceID, - /// KODI_HANDLE instance, - /// const std::string& version, - /// KODI_HANDLE& addonInstance) - /// { - /// kodi::Log(ADDON_LOG_NOTICE, "Creating my PVR client instance"); - /// addonInstance = new CMyPVRClient(instance, version); - /// return ADDON_STATUS_OK; - /// } - /// ~~~~~~~~~~~~~ - /// - explicit CInstancePVRClient(KODI_HANDLE instance, const std::string& kodiVersion = "") - : IAddonInstance(ADDON_INSTANCE_PVR, - !kodiVersion.empty() ? kodiVersion : GetKodiTypeVersion(ADDON_INSTANCE_PVR)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstancePVRClient: Creation of multiple together with " - "single instance way is not allowed!"); - - SetAddonStruct(instance, m_kodiVersion); - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Destructor - /// - ~CInstancePVRClient() override = default; - //---------------------------------------------------------------------------- - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - //============================================================================ - /// @brief Get the list of features that this add-on provides. - /// - /// Called by Kodi to query the add-on's capabilities. - /// Used to check which options should be presented in the UI, which methods to call, etc. - /// All capabilities that the add-on supports should be set to true. - /// - /// @param capabilities The with @ref cpp_kodi_addon_pvr_Defs_PVRCapabilities defined add-on's capabilities. - /// @return @ref PVR_ERROR_NO_ERROR if the properties were fetched successfully. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_PVRCapabilities_Help - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// PVR_ERROR CMyPVRClient::GetCapabilities(kodi::addon::PVRCapabilities& capabilities) - /// { - /// capabilities.SetSupportsTV(true); - /// capabilities.SetSupportsEPG(true); - /// return PVR_ERROR_NO_ERROR; - /// } - /// ~~~~~~~~~~~~~ - /// - /// -------------------------------------------------------------------------- - /// - /// @note Valid implementation required. - /// - virtual PVR_ERROR GetCapabilities(kodi::addon::PVRCapabilities& capabilities) = 0; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get the name reported by the backend that will be displayed in the UI. - /// - /// @param[out] name The name reported by the backend that will be displayed in the UI. - /// @return @ref PVR_ERROR_NO_ERROR if successfully done - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// PVR_ERROR CMyPVRClient::GetBackendName(std::string& name) - /// { - /// name = "My special PVR client"; - /// return PVR_ERROR_NO_ERROR; - /// } - /// ~~~~~~~~~~~~~ - /// - /// -------------------------------------------------------------------------- - /// - /// @note Valid implementation required. - /// - virtual PVR_ERROR GetBackendName(std::string& name) = 0; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get the version string reported by the backend that will be - /// displayed in the UI. - /// - /// @param[out] version The version string reported by the backend that will be - /// displayed in the UI. - /// @return @ref PVR_ERROR_NO_ERROR if successfully done - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// PVR_ERROR CMyPVRClient::GetBackendVersion(std::string& version) - /// { - /// version = "1.0.0"; - /// return PVR_ERROR_NO_ERROR; - /// } - /// ~~~~~~~~~~~~~ - /// - /// -------------------------------------------------------------------------- - /// - /// @note Valid implementation required. - /// - virtual PVR_ERROR GetBackendVersion(std::string& version) = 0; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get the hostname of the pvr backend server - /// - /// @param[out] hostname Hostname as ip address or alias. If backend does not - /// utilize a server, return empty string. - /// @return @ref PVR_ERROR_NO_ERROR if successfully done - /// - virtual PVR_ERROR GetBackendHostname(std::string& hostname) { return PVR_ERROR_NOT_IMPLEMENTED; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief To get the connection string reported by the backend that will be - /// displayed in the UI. - /// - /// @param[out] connection The connection string reported by the backend that - /// will be displayed in the UI. - /// @return @ref PVR_ERROR_NO_ERROR if successfully done - /// - virtual PVR_ERROR GetConnectionString(std::string& connection) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get the disk space reported by the backend (if supported). - /// - /// @param[in] total The total disk space in bytes. - /// @param[in] used The used disk space in bytes. - /// @return @ref PVR_ERROR_NO_ERROR if the drive space has been fetched - /// successfully. - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// PVR_ERROR CMyPVRClient::GetDriveSpace(uint64_t& total, uint64_t& used) - /// { - /// total = 10 * 1024 * 1024 * 1024; // To set complete size of drive in bytes - /// used = 122324243; // To set the used amount - /// return PVR_ERROR_NO_ERROR; - /// } - /// ~~~~~~~~~~~~~ - /// - virtual PVR_ERROR GetDriveSpace(uint64_t& total, uint64_t& used) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Call one of the settings related menu hooks (if supported). - /// - /// Supported @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook "menu hook " - /// instances have to be added in `constructor()`, by calling @ref AddMenuHook() - /// on the callback. - /// - /// @param[in] menuhook The hook to call. - /// @return @ref PVR_ERROR_NO_ERROR if the hook was called successfully. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// PVR_ERROR CMyPVRClient::CallSettingsMenuHook(const kodi::addon::PVRMenuhook& menuhook) - /// { - /// if (menuhook.GetHookId() == 2) - /// kodi::QueueNotification(QUEUE_INFO, "", kodi::GetLocalizedString(menuhook.GetLocalizedStringId())); - /// return PVR_ERROR_NO_ERROR; - /// } - /// ~~~~~~~~~~~~~ - /// - virtual PVR_ERROR CallSettingsMenuHook(const kodi::addon::PVRMenuhook& menuhook) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief **Callback to Kodi Function**\nAdd or replace a menu hook for the context menu for this add-on - /// - /// This is a callback function, called from addon to give Kodi his context menu's. - /// - /// @param[in] menuhook The with @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook defined hook to add - /// - /// @remarks Only called from addon itself - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Here's an example of the use of it:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// ... - /// - /// { - /// kodi::addon::PVRMenuhook hook; - /// hook.SetHookId(1); - /// hook.SetCategory(PVR_MENUHOOK_CHANNEL); - /// hook.SetLocalizedStringId(30000); - /// AddMenuHook(hook); - /// } - /// - /// { - /// kodi::addon::PVRMenuhook hook; - /// hook.SetHookId(2); - /// hook.SetCategory(PVR_MENUHOOK_SETTING); - /// hook.SetLocalizedStringId(30001); - /// AddMenuHook(hook); - /// } - /// ... - /// ~~~~~~~~~~~~~ - /// - /// **Here another way:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// ... - /// - /// AddMenuHook(kodi::addon::PVRMenuhook(1, 30000, PVR_MENUHOOK_CHANNEL)); - /// AddMenuHook(kodi::addon::PVRMenuhook(2, 30001, PVR_MENUHOOK_SETTING)); - /// ... - /// ~~~~~~~~~~~~~ - /// - inline void AddMenuHook(const kodi::addon::PVRMenuhook& hook) - { - m_instanceData->toKodi->AddMenuHook(m_instanceData->toKodi->kodiInstance, hook); - } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief **Callback to Kodi Function**\n - /// Notify a state change for a PVR backend connection. - /// - /// @param[in] connectionString The connection string reported by the backend - /// that can be displayed in the UI. - /// @param[in] newState The by @ref PVR_CONNECTION_STATE defined new state. - /// @param[in] message A localized addon-defined string representing the new - /// state, that can be displayed in the UI or **empty** if - /// the Kodi-defined default string for the new state - /// shall be displayed. - /// - /// @remarks Only called from addon itself - /// - /// - /// -------------------------------------------------------------------------- - /// - /// - /// **Here's an example of the use of it:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// #include /* for kodi::GetLocalizedString(...) */ - /// ... - /// - /// ConnectionStateChange("PVR demo connection lost", PVR_CONNECTION_STATE_DISCONNECTED, kodi::GetLocalizedString(30005, "Lost connection to Server");); - /// ... - /// ~~~~~~~~~~~~~ - /// - inline void ConnectionStateChange(const std::string& connectionString, - PVR_CONNECTION_STATE newState, - const std::string& message) - { - m_instanceData->toKodi->ConnectionStateChange( - m_instanceData->toKodi->kodiInstance, connectionString.c_str(), newState, message.c_str()); - } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief **Callback to Kodi Function**\n - /// Get user data path of the PVR addon. - /// - /// @return Path of current Kodi user - /// - /// @remarks Only called from addon itself - /// - /// @note Alternatively, @ref kodi::GetAddonPath() can be used for this. - /// - inline std::string UserPath() const { return m_instanceData->props->strUserPath; } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief **Callback to Kodi Function**\n - /// Get main client path of the PVR addon. - /// - /// @return Path of addon client - /// - /// @remarks Only called from addon itself. - /// - /// @note Alternatively, @ref kodi::GetBaseUserPath() can be used for this. - /// - inline std::string ClientPath() const { return m_instanceData->props->strClientPath; } - //---------------------------------------------------------------------------- - - ///@} - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Channels 2. Channels (required) - /// @ingroup cpp_kodi_addon_pvr - /// @brief **Functions to get available TV or Radio channels**\n - /// These are mandatory functions for using this addon to get the available - /// channels. - /// - /// @remarks Either @ref PVRCapabilities::SetSupportsTV "SetSupportsTV()" or - /// @ref PVRCapabilities::SetSupportsRadio "SetSupportsRadio()" is required to - /// be set to `true`.\n - /// If a channel changes after the initial import, or if a new one was added, - /// then the add-on should call @ref TriggerChannelUpdate(). - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Channel parts in interface:**\n - /// Copy this to your project and extend with your parts or leave functions - /// complete away where not used or supported. - /// - /// @copydetails cpp_kodi_addon_pvr_Channels_header_addon_auto_check - /// @copydetails cpp_kodi_addon_pvr_Channels_source_addon_auto_check - /// - ///@{ - - //============================================================================ - /// @brief The total amount of channels on the backend - /// - /// @param[out] amount The total amount of channels on the backend - /// @return @ref PVR_ERROR_NO_ERROR if the amount has been fetched successfully. - /// - /// @remarks Valid implementation required. - /// - virtual PVR_ERROR GetChannelsAmount(int& amount) { return PVR_ERROR_NOT_IMPLEMENTED; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Request the list of all channels from the backend. - /// - /// @param[in] radio True to get the radio channels, false to get the TV channels. - /// @param[out] results The channels defined with @ref cpp_kodi_addon_pvr_Defs_Channel_PVRChannel - /// and available at the addon, them transferred with - /// @ref cpp_kodi_addon_pvr_Defs_Channel_PVRChannelsResultSet. - /// @return @ref PVR_ERROR_NO_ERROR if the list has been fetched successfully. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRChannel_Help - /// - /// - /// -------------------------------------------------------------------------- - /// - /// @remarks - /// If @ref PVRCapabilities::SetSupportsTV() is set to - /// `true`, a valid result set needs to be provided for `radio = false`.\n - /// If @ref PVRCapabilities::SetSupportsRadio() is set to - /// `true`, a valid result set needs to be provided for `radio = true`. - /// At least one of these two must provide a valid result set. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// PVR_ERROR CMyPVRInstance::GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& results) - /// { - /// // Minimal demo example, in reality bigger and loop to transfer all - /// kodi::addon::PVRChannel channel; - /// channel.SetUniqueId(123); - /// channel.SetIsRadio(false); - /// channel.SetChannelNumber(1); - /// channel.SetChannelName("My channel name"); - /// ... - /// - /// // Give it now to Kodi - /// results.Add(channel); - /// return PVR_ERROR_NO_ERROR; - /// } - /// ... - /// ~~~~~~~~~~~~~ - /// - virtual PVR_ERROR GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& results) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get the stream properties for a channel from the backend. - /// - /// @param[in] channel The channel to get the stream properties for. - /// @param[out] properties the properties required to play the stream. - /// @return @ref PVR_ERROR_NO_ERROR if the stream is available. - /// - /// @remarks If @ref PVRCapabilities::SetSupportsTV "SetSupportsTV" or - /// @ref PVRCapabilities::SetSupportsRadio "SetSupportsRadio" are set to true - /// and @ref PVRCapabilities::SetHandlesInputStream "SetHandlesInputStream" is - /// set to false.\n\n - /// In this case the implementation must fill the property @ref PVR_STREAM_PROPERTY_STREAMURL - /// with the URL Kodi should resolve to playback the channel. - /// - /// @note The value directly related to inputstream must always begin with the - /// name of the associated add-on, e.g. `"inputstream.adaptive.manifest_update_parameter"`. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// PVR_ERROR CMyPVRInstance::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, - /// std::vector& properties) - /// { - /// ... - /// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM, "inputstream.adaptive"); - /// properties.emplace_back("inputstream.adaptive.manifest_type", "mpd"); - /// properties.emplace_back("inputstream.adaptive.manifest_update_parameter", "full"); - /// properties.emplace_back(PVR_STREAM_PROPERTY_MIMETYPE, "application/xml+dash"); - /// return PVR_ERROR_NO_ERROR; - /// } - /// ... - /// ~~~~~~~~~~~~~ - /// - virtual PVR_ERROR GetChannelStreamProperties( - const kodi::addon::PVRChannel& channel, - std::vector& properties) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get the signal status of the stream that's currently open. - /// - /// @param[out] signalStatus The signal status. - /// @return @ref PVR_ERROR_NO_ERROR if the signal status has been read successfully, false otherwise. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetHandlesInputStream "SetHandlesInputStream" - /// is set to true. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus_Help - /// - /// - /// -------------------------------------------------------------------------- - /// - /// - /// **Here's example about the use of this:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// ... - /// - /// class ATTRIBUTE_HIDDEN CPVRExample - /// : public kodi::addon::CAddonBase, - /// public kodi::addon::CInstancePVRClient - /// { - /// public: - /// ... - /// PVR_ERROR SignalStatus(PVRSignalStatus &signalStatus) override - /// { - /// signalStatus.SetAapterName("Example adapter 1"); - /// signalStatus.SetAdapterStatus("OK"); - /// signalStatus.SetSignal(0xFFFF); // 100% - /// - /// return PVR_ERROR_NO_ERROR; - /// } - /// }; - /// - /// ADDONCREATOR(CPVRExample) - /// ~~~~~~~~~~~~~ - /// - virtual PVR_ERROR GetSignalStatus(int channelUid, kodi::addon::PVRSignalStatus& signalStatus) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get the descramble information of the stream that's currently open. - /// - /// @param[out] descrambleInfo The descramble information. - /// @return @ref PVR_ERROR_NO_ERROR if the descramble information has been - /// read successfully, false otherwise. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsDescrambleInfo "supportsDescrambleInfo" - /// is set to true. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo_Help - /// - virtual PVR_ERROR GetDescrambleInfo(int channelUid, - kodi::addon::PVRDescrambleInfo& descrambleInfo) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief **Callback to Kodi Function**\n - /// Request Kodi to update it's list of channels. - /// - /// @remarks Only called from addon itself. - /// - inline void TriggerChannelUpdate() - { - m_instanceData->toKodi->TriggerChannelUpdate(m_instanceData->toKodi->kodiInstance); - } - //---------------------------------------------------------------------------- - - ///@} - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_supportsChannelGroups 3. Channel Groups (optional) - /// @ingroup cpp_kodi_addon_pvr - /// @brief Bring in this functions if you have set @ref PVRCapabilities::SetSupportsChannelGroups "supportsChannelGroups" - /// to true\n - /// This is used to divide available addon channels into groups, which can - /// then be selected by the user. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Channel group parts in interface:**\n - /// Copy this to your project and extend with your parts or leave functions - /// complete away where not used or supported. - /// - /// @copydetails cpp_kodi_addon_pvr_supportsChannelGroups_header_addon_auto_check - /// @copydetails cpp_kodi_addon_pvr_supportsChannelGroups_source_addon_auto_check - /// - ///@{ - - //============================================================================ - /// @brief Get the total amount of channel groups on the backend if it supports channel groups. - /// - /// @param[out] amount The total amount of channel groups on the backend - /// @return @ref PVR_ERROR_NO_ERROR if the amount has been fetched successfully. - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelGroups "supportsChannelGroups" is set to true. - /// - virtual PVR_ERROR GetChannelGroupsAmount(int& amount) { return PVR_ERROR_NOT_IMPLEMENTED; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get a list of available channel groups on addon - /// - /// Request the list of all channel groups from the backend if it supports - /// channel groups. - /// - /// @param[in] radio True to get the radio channel groups, false to get the - /// TV channel groups. - /// @param[out] results List of available groups on addon defined with - /// @ref cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup, - /// them transferred with - /// @ref cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupsResultSet. - /// @return @ref PVR_ERROR_NO_ERROR if the list has been fetched successfully. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup_Help - /// - /// - /// -------------------------------------------------------------------------- - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelGroups "supportsChannelGroups" - /// is set to true. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// PVR_ERROR CMyPVRInstance::GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResultSet& groups) - /// { - /// kodi::addon::PVRChannelGroup group; - /// group.SetIsRadio(false); - /// group.SetGroupName("My group name"); - /// group.SetPosition(1); - /// ... - /// - /// // Give it now to Kodi - /// results.Add(group); - /// return PVR_ERROR_NO_ERROR; - /// } - /// ... - /// ~~~~~~~~~~~~~ - /// - virtual PVR_ERROR GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResultSet& results) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get a list of members on a group - /// - /// Request the list of all group members of a group from the backend if it - /// supports channel groups. - /// - /// @param[in] group The group to get the members for. - /// @param[out] results List of available group member channels defined with - /// @ref cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember, - /// them transferred with - /// @ref PVRChannelGroupMembersResultSet. - /// @return @ref PVR_ERROR_NO_ERROR if the list has been fetched successfully. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember_Help - /// - /// -------------------------------------------------------------------------- - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelGroups "supportsChannelGroups" - /// is set to true. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// PVR_ERROR CMyPVRInstance::GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& group, - /// kodi::addon::PVRChannelGroupMembersResultSet& results) - /// { - /// for (const auto& myGroup : m_myGroups) - /// { - /// if (myGroup.strGroupName == group.GetGroupName()) - /// { - /// for (unsigned int iChannelPtr = 0; iChannelPtr < myGroup.members.size(); iChannelPtr++) - /// { - /// int iId = myGroup.members.at(iChannelPtr) - 1; - /// if (iId < 0 || iId > (int)m_channels.size() - 1) - /// continue; - /// - /// PVRDemoChannel &channel = m_channels.at(iId); - /// kodi::addon::PVRChannelGroupMember kodiGroupMember; - /// kodiGroupMember.SetGroupName(group.GetGroupName()); - /// kodiGroupMember.SetChannelUniqueId(channel.iUniqueId); - /// kodiGroupMember.SetChannelNumber(channel.iChannelNumber); - /// kodiGroupMember.SetSubChannelNumber(channel.iSubChannelNumber); - /// - /// results.Add(kodiGroupMember); - /// } - /// } - /// } - /// return PVR_ERROR_NO_ERROR; - /// } - /// ... - /// ~~~~~~~~~~~~~ - /// - virtual PVR_ERROR GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& group, - kodi::addon::PVRChannelGroupMembersResultSet& results) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief **Callback to Kodi Function**\n - /// Request Kodi to update it's list of channel groups. - /// - /// @remarks Only called from addon itself - /// - inline void TriggerChannelGroupsUpdate() - { - m_instanceData->toKodi->TriggerChannelGroupsUpdate(m_instanceData->toKodi->kodiInstance); - } - //---------------------------------------------------------------------------- - - ///@} - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_supportsChannelEdit 4. Channel edit (optional) - /// @ingroup cpp_kodi_addon_pvr - /// @brief Bring in this functions if you have set @ref PVRCapabilities::SetSupportsChannelSettings "supportsChannelSettings" - /// to true or for @ref OpenDialogChannelScan() set @ref PVRCapabilities::SetSupportsChannelScan "supportsChannelScan" - /// to true\n - /// The support of this is a pure option and not mandatory. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Channel edit parts in interface:**\n - /// Copy this to your project and extend with your parts or leave functions - /// complete away where not used or supported. - /// - /// @copydetails cpp_kodi_addon_pvr_supportsChannelEdit_header_addon_auto_check - /// @copydetails cpp_kodi_addon_pvr_supportsChannelEdit_source_addon_auto_check - /// - ///@{ - - //============================================================================ - /// @brief Delete a channel from the backend. - /// - /// @param[in] channel The channel to delete. - /// @return @ref PVR_ERROR_NO_ERROR if the channel has been deleted successfully. - /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelSettings "supportsChannelSettings" - /// is set to true. - /// - virtual PVR_ERROR DeleteChannel(const kodi::addon::PVRChannel& channel) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief Rename a channel on the backend. - /// - /// @param[in] channel The channel to rename, containing the new channel name. - /// @return @ref PVR_ERROR_NO_ERROR if the channel has been renamed successfully. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRChannel_Help - /// - /// - /// -------------------------------------------------------------------------- - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsChannelSettings "supportsChannelSettings" - /// is set to true. - /// - virtual PVR_ERROR RenameChannel(const kodi::addon::PVRChannel& channel) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief Show the channel settings dialog, if supported by the backend. - /// - /// @param[in] channel The channel to show the dialog for. - /// @return @ref PVR_ERROR_NO_ERROR if the dialog has been displayed successfully. - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelSettings "supportsChannelSettings" is set to true. - /// @note Use @ref cpp_kodi_gui_CWindow "kodi::gui::CWindow" to create dialog for them. - /// - virtual PVR_ERROR OpenDialogChannelSettings(const kodi::addon::PVRChannel& channel) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief Show the dialog to add a channel on the backend, if supported by the backend. - /// - /// @param[in] channel The channel to add. - /// @return @ref PVR_ERROR_NO_ERROR if the channel has been added successfully. - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelSettings "supportsChannelSettings" is set to true. - /// @note Use @ref cpp_kodi_gui_CWindow "kodi::gui::CWindow" to create dialog for them. - /// - virtual PVR_ERROR OpenDialogChannelAdd(const kodi::addon::PVRChannel& channel) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief Show the channel scan dialog if this backend supports it. - /// - /// @return @ref PVR_ERROR_NO_ERROR if the dialog was displayed successfully. - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelScan "supportsChannelScan" is set to true. - /// @note Use @ref cpp_kodi_gui_CWindow "kodi::gui::CWindow" to create dialog for them. - /// - virtual PVR_ERROR OpenDialogChannelScan() { return PVR_ERROR_NOT_IMPLEMENTED; } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief Call one of the channel related menu hooks (if supported). - /// - /// Supported @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook instances have to be added in - /// `constructor()`, by calling @ref AddMenuHook() on the callback. - /// - /// @param[in] menuhook The hook to call. - /// @param[in] item The selected channel item for which the hook was called. - /// @return @ref PVR_ERROR_NO_ERROR if the hook was called successfully. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help - /// - virtual PVR_ERROR CallChannelMenuHook(const kodi::addon::PVRMenuhook& menuhook, - const kodi::addon::PVRChannel& item) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - ///@} - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_EPGTag 4. EPG methods (optional) - /// @ingroup cpp_kodi_addon_pvr - /// @brief **PVR EPG methods**\n - /// These C ++ class functions of are intended for processing EPG information - /// and for giving it to Kodi. - /// - /// The necessary data is transferred with @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag. - /// - /// @remarks Only used by Kodi if @ref PVRCapabilities::SetSupportsEPG "supportsEPG" - /// is set to true.\n\n - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **EPG parts in interface:**\n - /// Copy this to your project and extend with your parts or leave functions - /// complete away where not used or supported. - /// - /// @copydetails cpp_kodi_addon_pvr_EPGTag_header_addon_auto_check - /// @copydetails cpp_kodi_addon_pvr_EPGTag_source_addon_auto_check - /// - ///@{ - - //============================================================================ - /// @brief Request the EPG for a channel from the backend. - /// - /// @param[in] channelUid The UID of the channel to get the EPG table for. - /// @param[in] start Get events after this time (UTC). - /// @param[in] end Get events before this time (UTC). - /// @param[out] results List where available EPG information becomes - /// transferred with @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag - /// and given to Kodi - /// @return @ref PVR_ERROR_NO_ERROR if the table has been fetched successfully. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_epg_PVREPGTag_Help - /// - /// - /// -------------------------------------------------------------------------- - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsEPG "supportsEPG" is set to true. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// PVR_ERROR CMyPVRInstance::GetEPGForChannel(int channelUid, - /// time_t start, - /// time_t end, - /// kodi::addon::PVREPGTagsResultSet& results) - /// { - /// // Minimal demo example, in reality bigger, loop to transfer all and to - /// // match wanted times. - /// kodi::addon::PVREPGTag tag; - /// tag.SetUniqueBroadcastId(123); - /// tag.SetUniqueChannelId(123); - /// tag.SetTitle("My epg entry name"); - /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MOVIEDRAMA); - /// tag.SetStartTime(1589148283); // Seconds elapsed since 00:00 hours, Jan 1, 1970 UTC - /// tag.SetEndTime(1589151913); - /// ... - /// - /// // Give it now to Kodi - /// results.Add(tag); - /// return PVR_ERROR_NO_ERROR; - /// } - /// ... - /// ~~~~~~~~~~~~~ - /// - virtual PVR_ERROR GetEPGForChannel(int channelUid, - time_t start, - time_t end, - kodi::addon::PVREPGTagsResultSet& results) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Check if the given EPG tag can be recorded. - /// - /// @param[in] tag the @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "epg tag" to check. - /// @param[out] isRecordable Set to true if the tag can be recorded. - /// @return @ref PVR_ERROR_NO_ERROR if bIsRecordable has been set successfully. - /// - /// @remarks Optional, it return @ref PVR_ERROR_NOT_IMPLEMENTED by parent to let Kodi decide. - /// - virtual PVR_ERROR IsEPGTagRecordable(const kodi::addon::PVREPGTag& tag, bool& isRecordable) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Check if the given EPG tag can be played. - /// - /// @param[in] tag the @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "epg tag" to check. - /// @param[out] isPlayable Set to true if the tag can be played. - /// @return @ref PVR_ERROR_NO_ERROR if bIsPlayable has been set successfully. - /// - /// @remarks Required if add-on supports playing epg tags. - /// - virtual PVR_ERROR IsEPGTagPlayable(const kodi::addon::PVREPGTag& tag, bool& isPlayable) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Retrieve the edit decision list (EDL) of an EPG tag on the backend. - /// - /// @param[in] tag The @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "epg tag". - /// @param[out] edl The function has to write the EDL into this array. - /// @return @ref PVR_ERROR_NO_ERROR if the EDL was successfully read or no EDL exists. - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsEPGEdl "supportsEPGEdl" is set to true. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry_Help - /// - /// - /// -------------------------------------------------------------------------- - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsEPGEdl "supportsEPGEdl" is set to true. - /// - virtual PVR_ERROR GetEPGTagEdl(const kodi::addon::PVREPGTag& tag, - std::vector& edl) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get the stream properties for an epg tag from the backend. - /// - /// @param[in] tag The @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "epg tag" to get the stream properties for. - /// @param[out] properties the properties required to play the stream. - /// @return @ref PVR_ERROR_NO_ERROR if the stream is available. - /// - /// @remarks Required if add-on supports playing epg tags. - /// In this case your implementation must fill the property @ref PVR_STREAM_PROPERTY_STREAMURL - /// with the URL Kodi should resolve to playback the epg tag. - /// It return @ref PVR_ERROR_NOT_IMPLEMENTED from parent if this add-on won't provide this function. - /// - /// @note The value directly related to inputstream must always begin with the - /// name of the associated add-on, e.g. `"inputstream.adaptive.manifest_update_parameter"`. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// PVR_ERROR CMyPVRInstance::GetEPGTagStreamProperties(const kodi::addon::PVREPGTag& tag, - /// std::vector& properties) - /// { - /// ... - /// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM, "inputstream.adaptive"); - /// properties.emplace_back("inputstream.adaptive.manifest_type", "mpd"); - /// properties.emplace_back("inputstream.adaptive.manifest_update_parameter", "full"); - /// properties.emplace_back(PVR_STREAM_PROPERTY_MIMETYPE, "application/xml+dash"); - /// return PVR_ERROR_NO_ERROR; - /// } - /// ... - /// ~~~~~~~~~~~~~ - /// - virtual PVR_ERROR GetEPGTagStreamProperties( - const kodi::addon::PVREPGTag& tag, std::vector& properties) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Tell the client the time frame to use when notifying epg events back to Kodi - /// - /// The client might push epg events asynchronously to Kodi using the callback function - /// @ref EpgEventStateChange. To be able to only push events that are actually of - /// interest for Kodi, client needs to know about the epg time frame Kodi uses. Kodi - /// supplies the current epg time frame value in @ref EpgMaxDays() when creating the - /// addon and calls @ref SetEPGTimeFrame later whenever Kodi's epg time frame value - /// changes. - /// - /// @param[in] days number of days from "now". @ref EPG_TIMEFRAME_UNLIMITED means that Kodi - /// is interested in all epg events, regardless of event times. - /// @return @ref PVR_ERROR_NO_ERROR if new value was successfully set. - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsEPG "supportsEPG" is set to true. - /// - virtual PVR_ERROR SetEPGTimeFrame(int days) { return PVR_ERROR_NOT_IMPLEMENTED; } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief Call one of the EPG related menu hooks (if supported). - /// - /// Supported @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook instances have to be added in - /// `constructor()`, by calling @ref AddMenuHook() on the callback. - /// - /// @param[in] menuhook The hook to call. - /// @param[in] tag The selected EPG item for which the hook was called. - /// @return @ref PVR_ERROR_NO_ERROR if the hook was called successfully. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help - /// - virtual PVR_ERROR CallEPGMenuHook(const kodi::addon::PVRMenuhook& menuhook, - const kodi::addon::PVREPGTag& tag) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief **Callback to Kodi Function**\n - /// Get the Max days handled by Kodi. - /// - /// If > @ref EPG_TIMEFRAME_UNLIMITED, in async epg mode, deliver only events - /// in the range from 'end time > now' to 'start time < now + EpgMaxDays(). - /// @ref EPG_TIMEFRAME_UNLIMITED, notify all events. - /// - /// @return The Max days handled by Kodi - /// - inline int EpgMaxDays() const { return m_instanceData->props->iEpgMaxDays; } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief **Callback to Kodi Function**\n - /// Schedule an EPG update for the given channel channel. - /// - /// @param[in] channelUid The unique id of the channel for this add-on - /// - /// @remarks Only called from addon itself - /// - inline void TriggerEpgUpdate(unsigned int channelUid) - { - m_instanceData->toKodi->TriggerEpgUpdate(m_instanceData->toKodi->kodiInstance, channelUid); - } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief **Callback to Kodi Function**\n - /// Notify a state change for an EPG event. - /// - /// @param[in] tag The @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "EPG tag" where have event. - /// @param[in] newState The new state. - /// - For @ref EPG_EVENT_CREATED and @ref EPG_EVENT_UPDATED, tag must be filled with all available event data, not just a delta. - /// - For @ref EPG_EVENT_DELETED, it is sufficient to fill @ref kodi::addon::PVREPGTag::SetUniqueBroadcastId - /// - /// @remarks Only called from addon itself, - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// - /// void CMyPVRInstance::MyProcessFunction() - /// { - /// ... - /// kodi::addon::PVREPGTag tag; // Here as mini add, in real it should be a complete tag - /// tag.SetUniqueId(123); - /// - /// // added namespace here not needed to have, only to have more clear for where is - /// kodi::addon::CInstancePVRClient::EpgEventStateChange(tag, EPG_EVENT_UPDATED); - /// ... - /// } - /// - /// ... - /// ~~~~~~~~~~~~~ - /// - inline void EpgEventStateChange(kodi::addon::PVREPGTag& tag, EPG_EVENT_STATE newState) - { - m_instanceData->toKodi->EpgEventStateChange(m_instanceData->toKodi->kodiInstance, tag.GetTag(), - newState); - } - //---------------------------------------------------------------------------- - - ///@} - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Recordings 5. Recordings (optional) - /// @ingroup cpp_kodi_addon_pvr - /// @brief **PVR recording methods**\n - /// To transfer available recordings of the PVR backend and to allow possible - /// playback. - /// - /// @remarks Only used by Kodi if @ref PVRCapabilities::SetSupportsRecordings "supportsRecordings" - /// is set to true.\n\n - /// If a recordings changes after the initial import, or if a new one was added, - /// then the add-on should call @ref TriggerRecordingUpdate(). - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Recordings parts in interface:**\n - /// Copy this to your project and extend with your parts or leave functions - /// complete away where not used or supported. - /// - /// @copydetails cpp_kodi_addon_pvr_Recordings_header_addon_auto_check - /// @copydetails cpp_kodi_addon_pvr_Recordings_source_addon_auto_check - /// - ///@{ - - //============================================================================ - /// @brief To get amount of recording present on backend - /// - /// @param[in] deleted if set return deleted recording (called if - /// @ref PVRCapabilities::SetSupportsRecordingsUndelete "supportsRecordingsUndelete" - /// set to true) - /// @param[out] amount The total amount of recordings on the backend - /// @return @ref PVR_ERROR_NO_ERROR if the amount has been fetched successfully. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings "supportsRecordings" is set to true. - /// - virtual PVR_ERROR GetRecordingsAmount(bool deleted, int& amount) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Request the list of all recordings from the backend, if supported. - /// - /// Recording entries are added to Kodi by calling TransferRecordingEntry() on the callback. - /// - /// @param[in] deleted if set return deleted recording (called if - /// @ref PVRCapabilities::SetSupportsRecordingsUndelete "supportsRecordingsUndelete" - /// set to true) - /// @param[out] results List of available recordings with @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording - /// becomes transferred with @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecordingsResultSet - /// and given to Kodi - /// @return @ref PVR_ERROR_NO_ERROR if the recordings have been fetched successfully. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings "supportsRecordings" - /// is set to true. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Recording_PVRRecording_Help - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// PVR_ERROR CMyPVRInstance::GetRecordings(bool deleted, kodi::addon::PVRRecordingsResultSet& results) - /// { - /// // Minimal demo example, in reality bigger and loop to transfer all - /// kodi::addon::PVRRecording recording; - /// recording.SetRecordingId(123); - /// recording.SetTitle("My recording name"); - /// ... - /// - /// // Give it now to Kodi - /// results.Add(recording); - /// return PVR_ERROR_NO_ERROR; - /// } - /// ... - /// ~~~~~~~~~~~~~ - /// - virtual PVR_ERROR GetRecordings(bool deleted, kodi::addon::PVRRecordingsResultSet& results) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Delete a recording on the backend. - /// - /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording to delete. - /// @return @ref PVR_ERROR_NO_ERROR if the recording has been deleted successfully. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings "supportsRecordings" - /// is set to true. - /// - virtual PVR_ERROR DeleteRecording(const kodi::addon::PVRRecording& recording) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Undelete a recording on the backend. - /// - /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording to undelete. - /// @return @ref PVR_ERROR_NO_ERROR if the recording has been undeleted successfully. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordingsUndelete "supportsRecordingsUndelete" - /// is set to true. - /// - virtual PVR_ERROR UndeleteRecording(const kodi::addon::PVRRecording& recording) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Delete all recordings permanent which in the deleted folder on the backend. - /// - /// @return @ref PVR_ERROR_NO_ERROR if the recordings has been deleted successfully. - /// - virtual PVR_ERROR DeleteAllRecordingsFromTrash() { return PVR_ERROR_NOT_IMPLEMENTED; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Rename a recording on the backend. - /// - /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording - /// to rename, containing the new name. - /// @return @ref PVR_ERROR_NO_ERROR if the recording has been renamed successfully. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings "supportsRecordings" - /// is set to true. - /// - virtual PVR_ERROR RenameRecording(const kodi::addon::PVRRecording& recording) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Set the lifetime of a recording on the backend. - /// - /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording - /// to change the lifetime for. recording.iLifetime - /// contains the new lieftime value. - /// @return @ref PVR_ERROR_NO_ERROR if the recording's lifetime has been set - /// successfully. - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsRecordingsLifetimeChange "supportsRecordingsLifetimeChange" - /// is set to true. - /// - virtual PVR_ERROR SetRecordingLifetime(const kodi::addon::PVRRecording& recording) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Set the play count of a recording on the backend. - /// - /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording - /// to change the play count. - /// @param[in] count Play count. - /// @return @ref PVR_ERROR_NO_ERROR if the recording's play count has been set - /// successfully. - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsRecordingPlayCount "supportsRecordingPlayCount" - /// is set to true. - /// - virtual PVR_ERROR SetRecordingPlayCount(const kodi::addon::PVRRecording& recording, int count) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Set the last watched position of a recording on the backend. - /// - /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording. - /// @param[in] lastplayedposition The last watched position in seconds - /// @return @ref PVR_ERROR_NO_ERROR if the position has been stored successfully. - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsLastPlayedPosition "supportsLastPlayedPosition" - /// is set to true. - /// - virtual PVR_ERROR SetRecordingLastPlayedPosition(const kodi::addon::PVRRecording& recording, - int lastplayedposition) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Retrieve the last watched position of a recording on the backend. - /// - /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording. - /// @param[out] position The last watched position in seconds - /// @return @ref PVR_ERROR_NO_ERROR if the amount has been fetched successfully. - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsRecordingPlayCount "supportsRecordingPlayCount" - /// is set to true. - /// - virtual PVR_ERROR GetRecordingLastPlayedPosition(const kodi::addon::PVRRecording& recording, - int& position) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Retrieve the edit decision list (EDL) of a recording on the backend. - /// - /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording. - /// @param[out] edl The function has to write the EDL into this array. - /// @return @ref PVR_ERROR_NO_ERROR if the EDL was successfully read or no EDL exists. - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsRecordingEdl "supportsRecordingEdl" - /// is set to true. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry_Help - /// - virtual PVR_ERROR GetRecordingEdl(const kodi::addon::PVRRecording& recording, - std::vector& edl) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Retrieve the size of a recording on the backend. - /// - /// @param[in] recording The recording to get the size in bytes for. - /// @param[out] size The size in bytes of the recording - /// @return @ref PVR_ERROR_NO_ERROR if the recording's size has been set successfully. - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsRecordingSize "supportsRecordingSize" - /// is set to true. - /// - virtual PVR_ERROR GetRecordingSize(const kodi::addon::PVRRecording& recording, int64_t& size) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Get the stream properties for a recording from the backend. - /// - /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording - /// to get the stream properties for. - /// @param[out] properties The properties required to play the stream. - /// @return @ref PVR_ERROR_NO_ERROR if the stream is available. - /// - /// @remarks Required if @ref PVRCapabilities::SetSupportsRecordings "supportsRecordings" - /// is set to true and the add-on does not implement recording stream functions - /// (@ref OpenRecordedStream, ...).\n - /// In this case your implementation must fill the property @ref PVR_STREAM_PROPERTY_STREAMURL - /// with the URL Kodi should resolve to playback the recording. - /// - /// @note The value directly related to inputstream must always begin with the - /// name of the associated add-on, e.g. `"inputstream.adaptive.manifest_update_parameter"`. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// PVR_ERROR CMyPVRInstance::GetRecordingStreamProperties(const kodi::addon::PVRRecording& recording, - /// std::vector& properties) - /// { - /// ... - /// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM, "inputstream.adaptive"); - /// properties.emplace_back("inputstream.adaptive.manifest_type", "mpd"); - /// properties.emplace_back("inputstream.adaptive.manifest_update_parameter", "full"); - /// properties.emplace_back(PVR_STREAM_PROPERTY_MIMETYPE, "application/xml+dash"); - /// return PVR_ERROR_NO_ERROR; - /// } - /// ... - /// ~~~~~~~~~~~~~ - /// - virtual PVR_ERROR GetRecordingStreamProperties( - const kodi::addon::PVRRecording& recording, - std::vector& properties) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //========================================================================== - /// @brief Call one of the recording related menu hooks (if supported). - /// - /// Supported @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook instances have to be added in - /// `constructor()`, by calling @ref AddMenuHook() on the callback. - /// - /// @param[in] menuhook The hook to call. - /// @param[in] item The selected recording item for which the hook was called. - /// @return @ref PVR_ERROR_NO_ERROR if the hook was called successfully. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help - /// - virtual PVR_ERROR CallRecordingMenuHook(const kodi::addon::PVRMenuhook& menuhook, - const kodi::addon::PVRRecording& item) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief **Callback to Kodi Function**\n - /// Display a notification in Kodi that a recording started or stopped on the - /// server. - /// - /// @param[in] recordingName The name of the recording to display - /// @param[in] fileName The filename of the recording - /// @param[in] on True when recording started, false when it stopped - /// - /// @remarks Only called from addon itself - /// - inline void RecordingNotification(const std::string& recordingName, - const std::string& fileName, - bool on) - { - m_instanceData->toKodi->RecordingNotification(m_instanceData->toKodi->kodiInstance, - recordingName.c_str(), fileName.c_str(), on); - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief **Callback to Kodi Function**\n - /// Request Kodi to update it's list of recordings. - /// - /// @remarks Only called from addon itself - /// - inline void TriggerRecordingUpdate() - { - m_instanceData->toKodi->TriggerRecordingUpdate(m_instanceData->toKodi->kodiInstance); - } - //---------------------------------------------------------------------------- - - ///@} - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Timers 6. Timers (optional) - /// @ingroup cpp_kodi_addon_pvr - /// @brief **PVR timer methods**\n - /// For editing and displaying timed work, such as video recording. - /// - /// @remarks Only used by Kodi if @ref PVRCapabilities::SetSupportsTimers "supportsTimers" - /// is set to true.\n\n - /// If a timer changes after the initial import, or if a new one was added, - /// then the add-on should call @ref TriggerTimerUpdate(). - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Timer parts in interface:**\n - /// Copy this to your project and extend with your parts or leave functions - /// complete away where not used or supported. - /// - /// @copydetails cpp_kodi_addon_pvr_Timers_header_addon_auto_check - /// @copydetails cpp_kodi_addon_pvr_Timers_source_addon_auto_check - /// - ///@{ - - //============================================================================ - /// @brief Retrieve the timer types supported by the backend. - /// - /// @param[out] types The function has to write the definition of the - /// @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType types - /// into this array. - /// @return @ref PVR_ERROR_NO_ERROR if the types were successfully written to - /// the array. - /// - /// @note Maximal 32 entries are allowed inside. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType_Help - /// - virtual PVR_ERROR GetTimerTypes(std::vector& types) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief To get total amount of timers on the backend or -1 on error. - /// - /// @param[out] amount The total amount of timers on the backend - /// @return @ref PVR_ERROR_NO_ERROR if the amount has been fetched successfully. - /// - /// @note Required to use if @ref PVRCapabilities::SetSupportsTimers "supportsTimers" - /// is set to true. - /// - virtual PVR_ERROR GetTimersAmount(int& amount) { return PVR_ERROR_NOT_IMPLEMENTED; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Request the list of all timers from the backend if supported. - /// - /// @param[out] results List of available timers with @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimer - /// becomes transferred with @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimersResultSet - /// and given to Kodi - /// @return @ref PVR_ERROR_NO_ERROR if the list has been fetched successfully. - /// - /// @note Required to use if @ref PVRCapabilities::SetSupportsTimers "supportsTimers" - /// is set to true. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Timer_PVRTimer_Help - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// PVR_ERROR CMyPVRInstance::GetTimers(kodi::addon::PVRTimersResultSet& results) - /// { - /// // Minimal demo example, in reality bigger and loop to transfer all - /// kodi::addon::PVRTimer timer; - /// timer.SetClientIndex(123); - /// timer.SetState(PVR_TIMER_STATE_SCHEDULED); - /// timer.SetTitle("My timer name"); - /// ... - /// - /// // Give it now to Kodi - /// results.Add(timer); - /// return PVR_ERROR_NO_ERROR; - /// } - /// ... - /// ~~~~~~~~~~~~~ - /// - virtual PVR_ERROR GetTimers(kodi::addon::PVRTimersResultSet& results) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Add a timer on the backend. - /// - /// @param[in] timer The timer to add. - /// @return @ref PVR_ERROR_NO_ERROR if the timer has been added successfully. - /// - /// @note Required to use if @ref PVRCapabilities::SetSupportsTimers "supportsTimers" - /// is set to true. - /// - virtual PVR_ERROR AddTimer(const kodi::addon::PVRTimer& timer) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Delete a timer on the backend. - /// - /// @param[in] timer The timer to delete. - /// @param[in] forceDelete Set to true to delete a timer that is currently - /// recording a program. - /// @return @ref PVR_ERROR_NO_ERROR if the timer has been deleted successfully. - /// - /// @note Required to use if @ref PVRCapabilities::SetSupportsTimers "supportsTimers" - /// is set to true. - /// - virtual PVR_ERROR DeleteTimer(const kodi::addon::PVRTimer& timer, bool forceDelete) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Update the timer information on the backend. - /// - /// @param[in] timer The timer to update. - /// @return @ref PVR_ERROR_NO_ERROR if the timer has been updated successfully. - /// - /// @note Required to use if @ref PVRCapabilities::SetSupportsTimers "supportsTimers" - /// is set to true. - /// - virtual PVR_ERROR UpdateTimer(const kodi::addon::PVRTimer& timer) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Call one of the timer related menu hooks (if supported). - /// - /// Supported @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook instances have - /// to be added in `constructor()`, by calling @ref AddMenuHook() on the - /// callback. - /// - /// @param[in] menuhook The hook to call. - /// @param[in] item The selected timer item for which the hook was called. - /// @return @ref PVR_ERROR_NO_ERROR if the hook was called successfully. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help - /// - virtual PVR_ERROR CallTimerMenuHook(const kodi::addon::PVRMenuhook& menuhook, - const kodi::addon::PVRTimer& item) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief **Callback to Kodi Function**\n - /// Request Kodi to update it's list of timers. - /// - /// @remarks Only called from addon itself - /// - inline void TriggerTimerUpdate() - { - m_instanceData->toKodi->TriggerTimerUpdate(m_instanceData->toKodi->kodiInstance); - } - //---------------------------------------------------------------------------- - - ///@} - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_PowerManagement 7. Power management events (optional) - /// @ingroup cpp_kodi_addon_pvr - /// @brief **Used to notify the pvr addon for power management events**\n - /// Used to allow any energy savings. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Power management events in interface:**\n - /// Copy this to your project and extend with your parts or leave functions - /// complete away where not used or supported. - /// - /// @copydetails cpp_kodi_addon_pvr_PowerManagement_header_addon_auto_check - /// @copydetails cpp_kodi_addon_pvr_PowerManagement_source_addon_auto_check - /// - ///@{ - - //============================================================================ - /// @brief To notify addon about system sleep - /// - /// @return @ref PVR_ERROR_NO_ERROR If successfully done. - /// - virtual PVR_ERROR OnSystemSleep() { return PVR_ERROR_NOT_IMPLEMENTED; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief To notify addon about system wake up - /// - /// @return @ref PVR_ERROR_NO_ERROR If successfully done. - /// - virtual PVR_ERROR OnSystemWake() { return PVR_ERROR_NOT_IMPLEMENTED; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief To notify addon power saving on system is activated - /// - /// @return @ref PVR_ERROR_NO_ERROR If successfully done. - /// - virtual PVR_ERROR OnPowerSavingActivated() { return PVR_ERROR_NOT_IMPLEMENTED; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief To notify addon power saving on system is deactivated - /// - /// @return @ref PVR_ERROR_NO_ERROR If successfully done. - /// - virtual PVR_ERROR OnPowerSavingDeactivated() { return PVR_ERROR_NOT_IMPLEMENTED; } - //---------------------------------------------------------------------------- - - ///@} - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Streams 8. Inputstream - /// @ingroup cpp_kodi_addon_pvr - /// @brief **PVR Inputstream**\n - /// This includes functions that are used in the PVR inputstream. - /// - /// @warning The parts here will be removed in the future and replaced by the - /// separate @ref cpp_kodi_addon_inputstream "inputstream addon instance". - /// If there is already a possibility, new addons should do it via the - /// inputstream instance. - /// - ///@{ - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Streams_TV 8.1. TV stream - /// @ingroup cpp_kodi_addon_pvr_Streams - /// @brief **PVR TV stream**\n - /// Stream processing regarding live TV. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **TV stream parts in interface:**\n - /// Copy this to your project and extend with your parts or leave functions - /// complete away where not used or supported. - /// - /// @copydetails cpp_kodi_addon_pvr_Streams_TV_header_addon_auto_check - /// @copydetails cpp_kodi_addon_pvr_Streams_TV_source_addon_auto_check - /// - ///@{ - - //============================================================================ - /// @brief Open a live stream on the backend. - /// - /// @param[in] channel The channel to stream. - /// @return True if the stream has been opened successfully, false otherwise. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRChannel_Help - /// - /// - /// -------------------------------------------------------------------------- - /// - /// @remarks Required if @ref PVRCapabilities::SetHandlesInputStream() or - /// @ref PVRCapabilities::SetHandlesDemuxing() is set to true. - /// @ref CloseLiveStream() will always be called by Kodi prior to calling this - /// function. - /// - virtual bool OpenLiveStream(const kodi::addon::PVRChannel& channel) { return false; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Close an open live stream. - /// - /// @remarks Required if @ref PVRCapabilities::SetHandlesInputStream() or - /// @ref PVRCapabilities::SetHandlesDemuxing() is set to true. - /// - virtual void CloseLiveStream() {} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Read from an open live stream. - /// - /// @param[in] pBuffer The buffer to store the data in. - /// @param[in] iBufferSize The amount of bytes to read. - /// @return The amount of bytes that were actually read from the stream. - /// - /// @remarks Required if @ref PVRCapabilities::SetHandlesInputStream() is set - /// to true. - /// - virtual int ReadLiveStream(unsigned char* buffer, unsigned int size) { return 0; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Seek in a live stream on a backend that supports timeshifting. - /// - /// @param[in] position The position to seek to. - /// @param[in] whence [optional] offset relative to - /// You can set the value of whence to one of three things: - /// | Value | int | Description | - /// |:--------:|:---:|:----------------------------------------------------| - /// | SEEK_SET | 0 | position is relative to the beginning of the file. This is probably what you had in mind anyway, and is the most commonly used value for whence. - /// | SEEK_CUR | 1 | position is relative to the current file pointer position. So, in effect, you can say, "Move to my current position plus 30 bytes," or, "move to my current position minus 20 bytes." - /// | SEEK_END | 2 | position is relative to the end of the file. Just like SEEK_SET except from the other end of the file. Be sure to use negative values for offset if you want to back up from the end of the file, instead of going past the end into oblivion. - /// - /// @return The new position. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetHandlesInputStream() - /// is set to true. - /// - virtual int64_t SeekLiveStream(int64_t position, int whence) { return 0; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Obtain the length of a live stream. - /// - /// @return The total length of the stream that's currently being read. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetHandlesInputStream() - /// is set to true. - /// - virtual int64_t LengthLiveStream() { return 0; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Streams_TV_Demux 8.1.1. Stream demuxing - /// @ingroup cpp_kodi_addon_pvr_Streams_TV - /// @brief **PVR stream demuxing**\n - /// Read TV streams with own demux within addon. - /// - /// This is only on Live TV streams and only if @ref PVRCapabilities::SetHandlesDemuxing() - /// has been set to "true". - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Stream demuxing parts in interface:**\n - /// Copy this to your project and extend with your parts or leave functions - /// complete away where not used or supported. - /// - /// @copydetails cpp_kodi_addon_pvr_Streams_TV_Demux_header_addon_auto_check - /// @copydetails cpp_kodi_addon_pvr_Streams_TV_Demux_source_addon_auto_check - /// - ///@{ - - //============================================================================ - /// @brief Get the stream properties of the stream that's currently being read. - /// - /// @param[in] properties The properties of the currently playing stream. - /// @return @ref PVR_ERROR_NO_ERROR if the properties have been fetched successfully. - /// - /// @remarks Required, and only used if addon has its own demuxer. - /// - virtual PVR_ERROR GetStreamProperties(std::vector& properties) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Read the next packet from the demultiplexer, if there is one. - /// - /// @return The next packet. - /// If there is no next packet, then the add-on should return the packet - /// created by calling @ref AllocateDemuxPacket(0) on the callback. - /// If the stream changed and Kodi's player needs to be reinitialised, then, - /// the add-on should call @ref AllocateDemuxPacket(0) on the callback, and set - /// the streamid to @ref DMX_SPECIALID_STREAMCHANGE and return the value. - /// The add-on should return `nullptr` if an error occurred. - /// - /// @remarks Required, and only used if addon has its own demuxer. - /// Return `nullptr` if this add-on won't provide this function. - /// - virtual DemuxPacket* DemuxRead() { return nullptr; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Reset the demultiplexer in the add-on. - /// - /// @remarks Required, and only used if addon has its own demuxer. - /// - virtual void DemuxReset() {} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Abort the demultiplexer thread in the add-on. - /// - /// @remarks Required, and only used if addon has its own demuxer. - /// - virtual void DemuxAbort() {} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Flush all data that's currently in the demultiplexer buffer in the - /// add-on. - /// - /// @remarks Required, and only used if addon has its own demuxer. - /// - virtual void DemuxFlush() {} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Notify the pvr addon/demuxer that Kodi wishes to change playback - /// speed. - /// - /// @param[in] speed The requested playback speed - /// - /// @remarks Optional, and only used if addon has its own demuxer. - /// - virtual void SetSpeed(int speed) {} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Notify the pvr addon/demuxer that Kodi wishes to fill demux queue. - /// - /// @param[in] mode The requested filling mode - /// - /// @remarks Optional, and only used if addon has its own demuxer. - /// - virtual void FillBuffer(bool mode) {} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Notify the pvr addon/demuxer that Kodi wishes to seek the stream by - /// time. - /// - /// @param[in] time The absolute time since stream start - /// @param[in] backwards True to seek to keyframe BEFORE time, else AFTER - /// @param[in] startpts can be updated to point to where display should start - /// @return True if the seek operation was possible - /// - /// @remarks Optional, and only used if addon has its own demuxer. - /// Return False if this add-on won't provide this function. - /// - virtual bool SeekTime(double time, bool backwards, double& startpts) { return false; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief **Callback to Kodi Function**\n - /// Get the codec id used by Kodi. - /// - /// @param[in] codecName The name of the codec - /// @return The codec_id, or a codec_id with 0 values when not supported - /// - /// @remarks Only called from addon itself - /// - inline PVRCodec GetCodecByName(const std::string& codecName) const - { - return PVRCodec(m_instanceData->toKodi->GetCodecByName(m_instanceData->toKodi->kodiInstance, - codecName.c_str())); - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief **Callback to Kodi Function**\n - /// Allocate a demux packet. Free with @ref FreeDemuxPacket(). - /// - /// @param[in] iDataSize The size of the data that will go into the packet - /// @return The allocated packet - /// - /// @remarks Only called from addon itself - /// - inline DemuxPacket* AllocateDemuxPacket(int iDataSize) - { - return m_instanceData->toKodi->AllocateDemuxPacket(m_instanceData->toKodi->kodiInstance, - iDataSize); - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief **Callback to Kodi Function**\n - /// Free a packet that was allocated with @ref AllocateDemuxPacket(). - /// - /// @param[in] pPacket The packet to free - /// - /// @remarks Only called from addon itself. - /// - inline void FreeDemuxPacket(DemuxPacket* pPacket) - { - m_instanceData->toKodi->FreeDemuxPacket(m_instanceData->toKodi->kodiInstance, pPacket); - } - //---------------------------------------------------------------------------- - ///@} - - ///@} - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Streams_Recording 8.2. Recording stream - /// @ingroup cpp_kodi_addon_pvr_Streams - /// @brief **PVR Recording stream**\n - /// Stream processing regarding recordings. - /// - /// @note Demuxing is not possible with the recordings. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Recording stream parts in interface:**\n - /// Copy this to your project and extend with your parts or leave functions - /// complete away where not used or supported. - /// - /// @copydetails cpp_kodi_addon_pvr_Streams_Recording_header_addon_auto_check - /// @copydetails cpp_kodi_addon_pvr_Streams_Recording_source_addon_auto_check - /// - ///@{ - - //============================================================================ - /// @brief Open a stream to a recording on the backend. - /// - /// @param[in] recording The recording to open. - /// @return True if the stream has been opened successfully, false otherwise. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings() - /// is set to true. @ref CloseRecordedStream() will always be called by Kodi - /// prior to calling this function. - /// - virtual bool OpenRecordedStream(const kodi::addon::PVRRecording& recording) { return false; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Close an open stream from a recording. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings() - /// is set to true. - /// - virtual void CloseRecordedStream() {} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Read from a recording. - /// - /// @param[in] buffer The buffer to store the data in. - /// @param[in] size The amount of bytes to read. - /// @return The amount of bytes that were actually read from the stream. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings() - /// is set to true. - /// - virtual int ReadRecordedStream(unsigned char* buffer, unsigned int size) { return 0; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Seek in a recorded stream. - /// - /// @param[in] position The position to seek to. - /// @param[in] whence [optional] offset relative to - /// You can set the value of whence to one of three things: - /// | Value | int | Description | - /// |:--------:|:---:|:----------------------------------------------------| - /// | SEEK_SET | 0 | position is relative to the beginning of the file. This is probably what you had in mind anyway, and is the most commonly used value for whence. - /// | SEEK_CUR | 1 | position is relative to the current file pointer position. So, in effect, you can say, "Move to my current position plus 30 bytes," or, "move to my current position minus 20 bytes." - /// | SEEK_END | 2 | position is relative to the end of the file. Just like SEEK_SET except from the other end of the file. Be sure to use negative values for offset if you want to back up from the end of the file, instead of going past the end into oblivion. - /// - /// @return The new position. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings() - /// is set to true. - /// - virtual int64_t SeekRecordedStream(int64_t position, int whence) { return 0; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Obtain the length of a recorded stream. - /// - /// @return The total length of the stream that's currently being read. - /// - /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings() - /// is true (=> @ref ReadRecordedStream). - /// - virtual int64_t LengthRecordedStream() { return 0; } - //---------------------------------------------------------------------------- - - ///@} - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Streams_Various 8.3. Various functions - /// @ingroup cpp_kodi_addon_pvr_Streams - /// @brief **Various other PVR stream related functions**\n - /// These apply to all other groups in inputstream and are therefore declared - /// as several. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Various stream parts in interface:**\n - /// Copy this to your project and extend with your parts or leave functions - /// complete away where not used or supported. - /// - /// @copydetails cpp_kodi_addon_pvr_Streams_Various_header_addon_auto_check - /// @copydetails cpp_kodi_addon_pvr_Streams_Various_source_addon_auto_check - /// - ///@{ - - //============================================================================ - /// - /// @brief Check if the backend support pausing the currently playing stream. - /// - /// This will enable/disable the pause button in Kodi based on the return - /// value. - /// - /// @return false if the PVR addon/backend does not support pausing, true if - /// possible - /// - virtual bool CanPauseStream() { return false; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Check if the backend supports seeking for the currently playing - /// stream. - /// - /// This will enable/disable the rewind/forward buttons in Kodi based on the - /// return value. - /// - /// @return false if the PVR addon/backend does not support seeking, true if - /// possible - /// - virtual bool CanSeekStream() { return false; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Notify the pvr addon that Kodi (un)paused the currently playing - /// stream. - /// - /// @param[in] paused To inform by `true` is paused and with `false` playing - /// - virtual void PauseStream(bool paused) {} - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Check for real-time streaming. - /// - /// @return true if current stream is real-time - /// - virtual bool IsRealTimeStream() { return false; } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Get stream times. - /// - /// @param[out] times A pointer to the data to be filled by the implementation. - /// @return @ref PVR_ERROR_NO_ERROR on success. - /// - virtual PVR_ERROR GetStreamTimes(kodi::addon::PVRStreamTimes& times) - { - return PVR_ERROR_NOT_IMPLEMENTED; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// @brief Obtain the chunk size to use when reading streams. - /// - /// @param[out] chunksize must be filled with the chunk size in bytes. - /// @return @ref PVR_ERROR_NO_ERROR if the chunk size has been fetched successfully. - /// - /// @remarks Optional, and only used if not reading from demuxer (=> @ref DemuxRead) and - /// @ref PVRCapabilities::SetSupportsRecordings() is true (=> @ref ReadRecordedStream) or - /// @ref PVRCapabilities::SetHandlesInputStream() is true (=> @ref ReadLiveStream). - /// - virtual PVR_ERROR GetStreamReadChunkSize(int& chunksize) { return PVR_ERROR_NOT_IMPLEMENTED; } - //---------------------------------------------------------------------------- - - ///@} - //--==----==----==----==----==----==----==----==----==----==----==----==----== - -private: - void SetAddonStruct(KODI_HANDLE instance, const std::string& kodiVersion) - { - if (instance == nullptr) - throw std::logic_error("kodi::addon::CInstancePVRClient: Creation with empty addon " - "structure not allowed, table must be given from Kodi!"); - - m_instanceData = static_cast(instance); - m_instanceData->toAddon->addonInstance = this; - //--==----==----==----==----==----==----==----==----==----==----==----==----== - m_instanceData->toAddon->GetCapabilities = ADDON_GetCapabilities; - m_instanceData->toAddon->GetConnectionString = ADDON_GetConnectionString; - m_instanceData->toAddon->GetBackendName = ADDON_GetBackendName; - m_instanceData->toAddon->GetBackendVersion = ADDON_GetBackendVersion; - m_instanceData->toAddon->GetBackendHostname = ADDON_GetBackendHostname; - m_instanceData->toAddon->GetDriveSpace = ADDON_GetDriveSpace; - m_instanceData->toAddon->CallSettingsMenuHook = ADDON_CallSettingsMenuHook; - //--==----==----==----==----==----==----==----==----==----==----==----==----== - m_instanceData->toAddon->GetChannelsAmount = ADDON_GetChannelsAmount; - m_instanceData->toAddon->GetChannels = ADDON_GetChannels; - m_instanceData->toAddon->GetChannelStreamProperties = ADDON_GetChannelStreamProperties; - m_instanceData->toAddon->GetSignalStatus = ADDON_GetSignalStatus; - m_instanceData->toAddon->GetDescrambleInfo = ADDON_GetDescrambleInfo; - //--==----==----==----==----==----==----==----==----==----==----==----==----== - m_instanceData->toAddon->GetChannelGroupsAmount = ADDON_GetChannelGroupsAmount; - m_instanceData->toAddon->GetChannelGroups = ADDON_GetChannelGroups; - m_instanceData->toAddon->GetChannelGroupMembers = ADDON_GetChannelGroupMembers; - //--==----==----==----==----==----==----==----==----==----==----==----==----== - m_instanceData->toAddon->DeleteChannel = ADDON_DeleteChannel; - m_instanceData->toAddon->RenameChannel = ADDON_RenameChannel; - m_instanceData->toAddon->OpenDialogChannelSettings = ADDON_OpenDialogChannelSettings; - m_instanceData->toAddon->OpenDialogChannelAdd = ADDON_OpenDialogChannelAdd; - m_instanceData->toAddon->OpenDialogChannelScan = ADDON_OpenDialogChannelScan; - m_instanceData->toAddon->CallChannelMenuHook = ADDON_CallChannelMenuHook; - //--==----==----==----==----==----==----==----==----==----==----==----==----== - m_instanceData->toAddon->GetEPGForChannel = ADDON_GetEPGForChannel; - m_instanceData->toAddon->IsEPGTagRecordable = ADDON_IsEPGTagRecordable; - m_instanceData->toAddon->IsEPGTagPlayable = ADDON_IsEPGTagPlayable; - m_instanceData->toAddon->GetEPGTagEdl = ADDON_GetEPGTagEdl; - m_instanceData->toAddon->GetEPGTagStreamProperties = ADDON_GetEPGTagStreamProperties; - m_instanceData->toAddon->SetEPGTimeFrame = ADDON_SetEPGTimeFrame; - m_instanceData->toAddon->CallEPGMenuHook = ADDON_CallEPGMenuHook; - //--==----==----==----==----==----==----==----==----==----==----==----==----== - m_instanceData->toAddon->GetRecordingsAmount = ADDON_GetRecordingsAmount; - m_instanceData->toAddon->GetRecordings = ADDON_GetRecordings; - m_instanceData->toAddon->DeleteRecording = ADDON_DeleteRecording; - m_instanceData->toAddon->UndeleteRecording = ADDON_UndeleteRecording; - m_instanceData->toAddon->DeleteAllRecordingsFromTrash = ADDON_DeleteAllRecordingsFromTrash; - m_instanceData->toAddon->RenameRecording = ADDON_RenameRecording; - m_instanceData->toAddon->SetRecordingLifetime = ADDON_SetRecordingLifetime; - m_instanceData->toAddon->SetRecordingPlayCount = ADDON_SetRecordingPlayCount; - m_instanceData->toAddon->SetRecordingLastPlayedPosition = ADDON_SetRecordingLastPlayedPosition; - m_instanceData->toAddon->GetRecordingLastPlayedPosition = ADDON_GetRecordingLastPlayedPosition; - m_instanceData->toAddon->GetRecordingEdl = ADDON_GetRecordingEdl; - m_instanceData->toAddon->GetRecordingSize = ADDON_GetRecordingSize; - m_instanceData->toAddon->GetRecordingStreamProperties = ADDON_GetRecordingStreamProperties; - m_instanceData->toAddon->CallRecordingMenuHook = ADDON_CallRecordingMenuHook; - //--==----==----==----==----==----==----==----==----==----==----==----==----== - m_instanceData->toAddon->GetTimerTypes = ADDON_GetTimerTypes; - m_instanceData->toAddon->GetTimersAmount = ADDON_GetTimersAmount; - m_instanceData->toAddon->GetTimers = ADDON_GetTimers; - m_instanceData->toAddon->AddTimer = ADDON_AddTimer; - m_instanceData->toAddon->DeleteTimer = ADDON_DeleteTimer; - m_instanceData->toAddon->UpdateTimer = ADDON_UpdateTimer; - m_instanceData->toAddon->CallTimerMenuHook = ADDON_CallTimerMenuHook; - //--==----==----==----==----==----==----==----==----==----==----==----==----== - m_instanceData->toAddon->OnSystemSleep = ADDON_OnSystemSleep; - m_instanceData->toAddon->OnSystemWake = ADDON_OnSystemWake; - m_instanceData->toAddon->OnPowerSavingActivated = ADDON_OnPowerSavingActivated; - m_instanceData->toAddon->OnPowerSavingDeactivated = ADDON_OnPowerSavingDeactivated; - //--==----==----==----==----==----==----==----==----==----==----==----==----== - m_instanceData->toAddon->OpenLiveStream = ADDON_OpenLiveStream; - m_instanceData->toAddon->CloseLiveStream = ADDON_CloseLiveStream; - m_instanceData->toAddon->ReadLiveStream = ADDON_ReadLiveStream; - m_instanceData->toAddon->SeekLiveStream = ADDON_SeekLiveStream; - m_instanceData->toAddon->LengthLiveStream = ADDON_LengthLiveStream; - m_instanceData->toAddon->GetStreamProperties = ADDON_GetStreamProperties; - m_instanceData->toAddon->GetStreamReadChunkSize = ADDON_GetStreamReadChunkSize; - m_instanceData->toAddon->IsRealTimeStream = ADDON_IsRealTimeStream; - //--==----==----==----==----==----==----==----==----==----==----==----==----== - m_instanceData->toAddon->OpenRecordedStream = ADDON_OpenRecordedStream; - m_instanceData->toAddon->CloseRecordedStream = ADDON_CloseRecordedStream; - m_instanceData->toAddon->ReadRecordedStream = ADDON_ReadRecordedStream; - m_instanceData->toAddon->SeekRecordedStream = ADDON_SeekRecordedStream; - m_instanceData->toAddon->LengthRecordedStream = ADDON_LengthRecordedStream; - //--==----==----==----==----==----==----==----==----==----==----==----==----== - m_instanceData->toAddon->DemuxReset = ADDON_DemuxReset; - m_instanceData->toAddon->DemuxAbort = ADDON_DemuxAbort; - m_instanceData->toAddon->DemuxFlush = ADDON_DemuxFlush; - m_instanceData->toAddon->DemuxRead = ADDON_DemuxRead; - //--==----==----==----==----==----==----==----==----==----==----==----==----== - m_instanceData->toAddon->CanPauseStream = ADDON_CanPauseStream; - m_instanceData->toAddon->PauseStream = ADDON_PauseStream; - m_instanceData->toAddon->CanSeekStream = ADDON_CanSeekStream; - m_instanceData->toAddon->SeekTime = ADDON_SeekTime; - m_instanceData->toAddon->SetSpeed = ADDON_SetSpeed; - m_instanceData->toAddon->FillBuffer = ADDON_FillBuffer; - m_instanceData->toAddon->GetStreamTimes = ADDON_GetStreamTimes; - } - - inline static PVR_ERROR ADDON_GetCapabilities(const AddonInstance_PVR* instance, - PVR_ADDON_CAPABILITIES* capabilities) - { - PVRCapabilities cppCapabilities(capabilities); - return static_cast(instance->toAddon->addonInstance) - ->GetCapabilities(cppCapabilities); - } - - inline static PVR_ERROR ADDON_GetBackendName(const AddonInstance_PVR* instance, - char* str, - int memSize) - { - std::string backendName; - PVR_ERROR err = static_cast(instance->toAddon->addonInstance) - ->GetBackendName(backendName); - if (err == PVR_ERROR_NO_ERROR) - strncpy(str, backendName.c_str(), memSize); - return err; - } - - inline static PVR_ERROR ADDON_GetBackendVersion(const AddonInstance_PVR* instance, - char* str, - int memSize) - { - std::string backendVersion; - PVR_ERROR err = static_cast(instance->toAddon->addonInstance) - ->GetBackendVersion(backendVersion); - if (err == PVR_ERROR_NO_ERROR) - strncpy(str, backendVersion.c_str(), memSize); - return err; - } - - inline static PVR_ERROR ADDON_GetBackendHostname(const AddonInstance_PVR* instance, - char* str, - int memSize) - { - std::string backendHostname; - PVR_ERROR err = static_cast(instance->toAddon->addonInstance) - ->GetBackendHostname(backendHostname); - if (err == PVR_ERROR_NO_ERROR) - strncpy(str, backendHostname.c_str(), memSize); - return err; - } - - inline static PVR_ERROR ADDON_GetConnectionString(const AddonInstance_PVR* instance, - char* str, - int memSize) - { - std::string connectionString; - PVR_ERROR err = static_cast(instance->toAddon->addonInstance) - ->GetConnectionString(connectionString); - if (err == PVR_ERROR_NO_ERROR) - strncpy(str, connectionString.c_str(), memSize); - return err; - } - - inline static PVR_ERROR ADDON_GetDriveSpace(const AddonInstance_PVR* instance, - uint64_t* total, - uint64_t* used) - { - return static_cast(instance->toAddon->addonInstance) - ->GetDriveSpace(*total, *used); - } - - inline static PVR_ERROR ADDON_CallSettingsMenuHook(const AddonInstance_PVR* instance, - const PVR_MENUHOOK* menuhook) - { - return static_cast(instance->toAddon->addonInstance) - ->CallSettingsMenuHook(menuhook); - } - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - inline static PVR_ERROR ADDON_GetChannelsAmount(const AddonInstance_PVR* instance, int* amount) - { - return static_cast(instance->toAddon->addonInstance) - ->GetChannelsAmount(*amount); - } - - inline static PVR_ERROR ADDON_GetChannels(const AddonInstance_PVR* instance, - ADDON_HANDLE handle, - bool radio) - { - PVRChannelsResultSet result(instance, handle); - return static_cast(instance->toAddon->addonInstance) - ->GetChannels(radio, result); - } - - inline static PVR_ERROR ADDON_GetChannelStreamProperties(const AddonInstance_PVR* instance, - const PVR_CHANNEL* channel, - PVR_NAMED_VALUE* properties, - unsigned int* propertiesCount) - { - *propertiesCount = 0; - std::vector propertiesList; - PVR_ERROR error = static_cast(instance->toAddon->addonInstance) - ->GetChannelStreamProperties(channel, propertiesList); - if (error == PVR_ERROR_NO_ERROR) - { - for (const auto& property : propertiesList) - { - strncpy(properties[*propertiesCount].strName, property.GetCStructure()->strName, - sizeof(properties[*propertiesCount].strName) - 1); - strncpy(properties[*propertiesCount].strValue, property.GetCStructure()->strValue, - sizeof(properties[*propertiesCount].strValue) - 1); - ++*propertiesCount; - if (*propertiesCount > STREAM_MAX_PROPERTY_COUNT) - break; - } - } - return error; - } - - inline static PVR_ERROR ADDON_GetSignalStatus(const AddonInstance_PVR* instance, - int channelUid, - PVR_SIGNAL_STATUS* signalStatus) - { - PVRSignalStatus cppSignalStatus(signalStatus); - return static_cast(instance->toAddon->addonInstance) - ->GetSignalStatus(channelUid, cppSignalStatus); - } - - inline static PVR_ERROR ADDON_GetDescrambleInfo(const AddonInstance_PVR* instance, - int channelUid, - PVR_DESCRAMBLE_INFO* descrambleInfo) - { - PVRDescrambleInfo cppDescrambleInfo(descrambleInfo); - return static_cast(instance->toAddon->addonInstance) - ->GetDescrambleInfo(channelUid, cppDescrambleInfo); - } - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - inline static PVR_ERROR ADDON_GetChannelGroupsAmount(const AddonInstance_PVR* instance, - int* amount) - { - return static_cast(instance->toAddon->addonInstance) - ->GetChannelGroupsAmount(*amount); - } - - inline static PVR_ERROR ADDON_GetChannelGroups(const AddonInstance_PVR* instance, - ADDON_HANDLE handle, - bool radio) - { - PVRChannelGroupsResultSet result(instance, handle); - return static_cast(instance->toAddon->addonInstance) - ->GetChannelGroups(radio, result); - } - - inline static PVR_ERROR ADDON_GetChannelGroupMembers(const AddonInstance_PVR* instance, - ADDON_HANDLE handle, - const PVR_CHANNEL_GROUP* group) - { - PVRChannelGroupMembersResultSet result(instance, handle); - return static_cast(instance->toAddon->addonInstance) - ->GetChannelGroupMembers(group, result); - } - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - inline static PVR_ERROR ADDON_DeleteChannel(const AddonInstance_PVR* instance, - const PVR_CHANNEL* channel) - { - return static_cast(instance->toAddon->addonInstance) - ->DeleteChannel(channel); - } - - inline static PVR_ERROR ADDON_RenameChannel(const AddonInstance_PVR* instance, - const PVR_CHANNEL* channel) - { - return static_cast(instance->toAddon->addonInstance) - ->RenameChannel(channel); - } - - inline static PVR_ERROR ADDON_OpenDialogChannelSettings(const AddonInstance_PVR* instance, - const PVR_CHANNEL* channel) - { - return static_cast(instance->toAddon->addonInstance) - ->OpenDialogChannelSettings(channel); - } - - inline static PVR_ERROR ADDON_OpenDialogChannelAdd(const AddonInstance_PVR* instance, - const PVR_CHANNEL* channel) - { - return static_cast(instance->toAddon->addonInstance) - ->OpenDialogChannelAdd(channel); - } - - inline static PVR_ERROR ADDON_OpenDialogChannelScan(const AddonInstance_PVR* instance) - { - return static_cast(instance->toAddon->addonInstance) - ->OpenDialogChannelScan(); - } - - inline static PVR_ERROR ADDON_CallChannelMenuHook(const AddonInstance_PVR* instance, - const PVR_MENUHOOK* menuhook, - const PVR_CHANNEL* channel) - { - return static_cast(instance->toAddon->addonInstance) - ->CallChannelMenuHook(menuhook, channel); - } - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - inline static PVR_ERROR ADDON_GetEPGForChannel(const AddonInstance_PVR* instance, - ADDON_HANDLE handle, - int channelUid, - time_t start, - time_t end) - { - PVREPGTagsResultSet result(instance, handle); - return static_cast(instance->toAddon->addonInstance) - ->GetEPGForChannel(channelUid, start, end, result); - } - - inline static PVR_ERROR ADDON_IsEPGTagRecordable(const AddonInstance_PVR* instance, - const EPG_TAG* tag, - bool* isRecordable) - { - return static_cast(instance->toAddon->addonInstance) - ->IsEPGTagRecordable(tag, *isRecordable); - } - - inline static PVR_ERROR ADDON_IsEPGTagPlayable(const AddonInstance_PVR* instance, - const EPG_TAG* tag, - bool* isPlayable) - { - return static_cast(instance->toAddon->addonInstance) - ->IsEPGTagPlayable(tag, *isPlayable); - } - - inline static PVR_ERROR ADDON_GetEPGTagEdl(const AddonInstance_PVR* instance, - const EPG_TAG* tag, - PVR_EDL_ENTRY* edl, - int* size) - { - *size = 0; - std::vector edlList; - PVR_ERROR error = static_cast(instance->toAddon->addonInstance) - ->GetEPGTagEdl(tag, edlList); - if (error == PVR_ERROR_NO_ERROR) - { - for (const auto& edlEntry : edlList) - { - edl[*size] = *edlEntry; - ++*size; - } - } - return error; - } - - inline static PVR_ERROR ADDON_GetEPGTagStreamProperties(const AddonInstance_PVR* instance, - const EPG_TAG* tag, - PVR_NAMED_VALUE* properties, - unsigned int* propertiesCount) - { - *propertiesCount = 0; - std::vector propertiesList; - PVR_ERROR error = static_cast(instance->toAddon->addonInstance) - ->GetEPGTagStreamProperties(tag, propertiesList); - if (error == PVR_ERROR_NO_ERROR) - { - for (const auto& property : propertiesList) - { - strncpy(properties[*propertiesCount].strName, property.GetCStructure()->strName, - sizeof(properties[*propertiesCount].strName) - 1); - strncpy(properties[*propertiesCount].strValue, property.GetCStructure()->strValue, - sizeof(properties[*propertiesCount].strValue) - 1); - ++*propertiesCount; - if (*propertiesCount > STREAM_MAX_PROPERTY_COUNT) - break; - } - } - return error; - } - - inline static PVR_ERROR ADDON_SetEPGTimeFrame(const AddonInstance_PVR* instance, int days) - { - return static_cast(instance->toAddon->addonInstance) - ->SetEPGTimeFrame(days); - } - - inline static PVR_ERROR ADDON_CallEPGMenuHook(const AddonInstance_PVR* instance, - const PVR_MENUHOOK* menuhook, - const EPG_TAG* tag) - { - return static_cast(instance->toAddon->addonInstance) - ->CallEPGMenuHook(menuhook, tag); - } - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - inline static PVR_ERROR ADDON_GetRecordingsAmount(const AddonInstance_PVR* instance, - bool deleted, - int* amount) - { - return static_cast(instance->toAddon->addonInstance) - ->GetRecordingsAmount(deleted, *amount); - } - - inline static PVR_ERROR ADDON_GetRecordings(const AddonInstance_PVR* instance, - ADDON_HANDLE handle, - bool deleted) - { - PVRRecordingsResultSet result(instance, handle); - return static_cast(instance->toAddon->addonInstance) - ->GetRecordings(deleted, result); - } - - inline static PVR_ERROR ADDON_DeleteRecording(const AddonInstance_PVR* instance, - const PVR_RECORDING* recording) - { - return static_cast(instance->toAddon->addonInstance) - ->DeleteRecording(recording); - } - - inline static PVR_ERROR ADDON_UndeleteRecording(const AddonInstance_PVR* instance, - const PVR_RECORDING* recording) - { - return static_cast(instance->toAddon->addonInstance) - ->UndeleteRecording(recording); - } - - inline static PVR_ERROR ADDON_DeleteAllRecordingsFromTrash(const AddonInstance_PVR* instance) - { - return static_cast(instance->toAddon->addonInstance) - ->DeleteAllRecordingsFromTrash(); - } - - inline static PVR_ERROR ADDON_RenameRecording(const AddonInstance_PVR* instance, - const PVR_RECORDING* recording) - { - return static_cast(instance->toAddon->addonInstance) - ->RenameRecording(recording); - } - - inline static PVR_ERROR ADDON_SetRecordingLifetime(const AddonInstance_PVR* instance, - const PVR_RECORDING* recording) - { - return static_cast(instance->toAddon->addonInstance) - ->SetRecordingLifetime(recording); - } - - inline static PVR_ERROR ADDON_SetRecordingPlayCount(const AddonInstance_PVR* instance, - const PVR_RECORDING* recording, - int count) - { - return static_cast(instance->toAddon->addonInstance) - ->SetRecordingPlayCount(recording, count); - } - - inline static PVR_ERROR ADDON_SetRecordingLastPlayedPosition(const AddonInstance_PVR* instance, - const PVR_RECORDING* recording, - int lastplayedposition) - { - return static_cast(instance->toAddon->addonInstance) - ->SetRecordingLastPlayedPosition(recording, lastplayedposition); - } - - inline static PVR_ERROR ADDON_GetRecordingLastPlayedPosition(const AddonInstance_PVR* instance, - const PVR_RECORDING* recording, - int* position) - { - return static_cast(instance->toAddon->addonInstance) - ->GetRecordingLastPlayedPosition(recording, *position); - } - - inline static PVR_ERROR ADDON_GetRecordingEdl(const AddonInstance_PVR* instance, - const PVR_RECORDING* recording, - PVR_EDL_ENTRY* edl, - int* size) - { - *size = 0; - std::vector edlList; - PVR_ERROR error = static_cast(instance->toAddon->addonInstance) - ->GetRecordingEdl(recording, edlList); - if (error == PVR_ERROR_NO_ERROR) - { - for (const auto& edlEntry : edlList) - { - edl[*size] = *edlEntry; - ++*size; - } - } - return error; - } - - inline static PVR_ERROR ADDON_GetRecordingSize(const AddonInstance_PVR* instance, - const PVR_RECORDING* recording, - int64_t* size) - { - return static_cast(instance->toAddon->addonInstance) - ->GetRecordingSize(recording, *size); - } - - inline static PVR_ERROR ADDON_GetRecordingStreamProperties(const AddonInstance_PVR* instance, - const PVR_RECORDING* recording, - PVR_NAMED_VALUE* properties, - unsigned int* propertiesCount) - { - *propertiesCount = 0; - std::vector propertiesList; - PVR_ERROR error = static_cast(instance->toAddon->addonInstance) - ->GetRecordingStreamProperties(recording, propertiesList); - if (error == PVR_ERROR_NO_ERROR) - { - for (const auto& property : propertiesList) - { - strncpy(properties[*propertiesCount].strName, property.GetCStructure()->strName, - sizeof(properties[*propertiesCount].strName) - 1); - strncpy(properties[*propertiesCount].strValue, property.GetCStructure()->strValue, - sizeof(properties[*propertiesCount].strValue) - 1); - ++*propertiesCount; - if (*propertiesCount > STREAM_MAX_PROPERTY_COUNT) - break; - } - } - return error; - } - - inline static PVR_ERROR ADDON_CallRecordingMenuHook(const AddonInstance_PVR* instance, - const PVR_MENUHOOK* menuhook, - const PVR_RECORDING* recording) - { - return static_cast(instance->toAddon->addonInstance) - ->CallRecordingMenuHook(menuhook, recording); - } - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - - inline static PVR_ERROR ADDON_GetTimerTypes(const AddonInstance_PVR* instance, - PVR_TIMER_TYPE* types, - int* typesCount) - { - *typesCount = 0; - std::vector timerTypes; - PVR_ERROR error = static_cast(instance->toAddon->addonInstance) - ->GetTimerTypes(timerTypes); - if (error == PVR_ERROR_NO_ERROR) - { - for (const auto& timerType : timerTypes) - { - types[*typesCount] = *timerType; - ++*typesCount; - if (*typesCount >= PVR_ADDON_TIMERTYPE_ARRAY_SIZE) - break; - } - } - return error; - } - - inline static PVR_ERROR ADDON_GetTimersAmount(const AddonInstance_PVR* instance, int* amount) - { - return static_cast(instance->toAddon->addonInstance) - ->GetTimersAmount(*amount); - } - - inline static PVR_ERROR ADDON_GetTimers(const AddonInstance_PVR* instance, ADDON_HANDLE handle) - { - PVRTimersResultSet result(instance, handle); - return static_cast(instance->toAddon->addonInstance)->GetTimers(result); - } - - inline static PVR_ERROR ADDON_AddTimer(const AddonInstance_PVR* instance, const PVR_TIMER* timer) - { - return static_cast(instance->toAddon->addonInstance)->AddTimer(timer); - } - - inline static PVR_ERROR ADDON_DeleteTimer(const AddonInstance_PVR* instance, - const PVR_TIMER* timer, - bool forceDelete) - { - return static_cast(instance->toAddon->addonInstance) - ->DeleteTimer(timer, forceDelete); - } - - inline static PVR_ERROR ADDON_UpdateTimer(const AddonInstance_PVR* instance, - const PVR_TIMER* timer) - { - return static_cast(instance->toAddon->addonInstance)->UpdateTimer(timer); - } - - inline static PVR_ERROR ADDON_CallTimerMenuHook(const AddonInstance_PVR* instance, - const PVR_MENUHOOK* menuhook, - const PVR_TIMER* timer) - { - return static_cast(instance->toAddon->addonInstance) - ->CallTimerMenuHook(menuhook, timer); - } - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - - inline static PVR_ERROR ADDON_OnSystemSleep(const AddonInstance_PVR* instance) - { - return static_cast(instance->toAddon->addonInstance)->OnSystemSleep(); - } - - inline static PVR_ERROR ADDON_OnSystemWake(const AddonInstance_PVR* instance) - { - return static_cast(instance->toAddon->addonInstance)->OnSystemWake(); - } - - inline static PVR_ERROR ADDON_OnPowerSavingActivated(const AddonInstance_PVR* instance) - { - return static_cast(instance->toAddon->addonInstance) - ->OnPowerSavingActivated(); - } - - inline static PVR_ERROR ADDON_OnPowerSavingDeactivated(const AddonInstance_PVR* instance) - { - return static_cast(instance->toAddon->addonInstance) - ->OnPowerSavingDeactivated(); - } - - // obsolete parts below - ///@{ - - inline static bool ADDON_OpenLiveStream(const AddonInstance_PVR* instance, - const PVR_CHANNEL* channel) - { - return static_cast(instance->toAddon->addonInstance) - ->OpenLiveStream(channel); - } - - inline static void ADDON_CloseLiveStream(const AddonInstance_PVR* instance) - { - static_cast(instance->toAddon->addonInstance)->CloseLiveStream(); - } - - inline static int ADDON_ReadLiveStream(const AddonInstance_PVR* instance, - unsigned char* buffer, - unsigned int size) - { - return static_cast(instance->toAddon->addonInstance) - ->ReadLiveStream(buffer, size); - } - - inline static int64_t ADDON_SeekLiveStream(const AddonInstance_PVR* instance, - int64_t position, - int whence) - { - return static_cast(instance->toAddon->addonInstance) - ->SeekLiveStream(position, whence); - } - - inline static int64_t ADDON_LengthLiveStream(const AddonInstance_PVR* instance) - { - return static_cast(instance->toAddon->addonInstance)->LengthLiveStream(); - } - - inline static PVR_ERROR ADDON_GetStreamProperties(const AddonInstance_PVR* instance, - PVR_STREAM_PROPERTIES* properties) - { - properties->iStreamCount = 0; - std::vector cppProperties; - PVR_ERROR err = static_cast(instance->toAddon->addonInstance) - ->GetStreamProperties(cppProperties); - if (err == PVR_ERROR_NO_ERROR) - { - for (unsigned int i = 0; i < cppProperties.size(); ++i) - { - memcpy(&properties->stream[i], - static_cast(cppProperties[i]), - sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); - ++properties->iStreamCount; - - if (properties->iStreamCount >= PVR_STREAM_MAX_STREAMS) - { - kodi::Log( - ADDON_LOG_ERROR, - "CInstancePVRClient::%s: Addon given with '%li' more allowed streams where '%i'", - __func__, cppProperties.size(), PVR_STREAM_MAX_STREAMS); - break; - } - } - } - - return err; - } - - inline static PVR_ERROR ADDON_GetStreamReadChunkSize(const AddonInstance_PVR* instance, - int* chunksize) - { - return static_cast(instance->toAddon->addonInstance) - ->GetStreamReadChunkSize(*chunksize); - } - - inline static bool ADDON_IsRealTimeStream(const AddonInstance_PVR* instance) - { - return static_cast(instance->toAddon->addonInstance)->IsRealTimeStream(); - } - - inline static bool ADDON_OpenRecordedStream(const AddonInstance_PVR* instance, - const PVR_RECORDING* recording) - { - return static_cast(instance->toAddon->addonInstance) - ->OpenRecordedStream(recording); - } - - inline static void ADDON_CloseRecordedStream(const AddonInstance_PVR* instance) - { - static_cast(instance->toAddon->addonInstance)->CloseRecordedStream(); - } - - inline static int ADDON_ReadRecordedStream(const AddonInstance_PVR* instance, - unsigned char* buffer, - unsigned int size) - { - return static_cast(instance->toAddon->addonInstance) - ->ReadRecordedStream(buffer, size); - } - - inline static int64_t ADDON_SeekRecordedStream(const AddonInstance_PVR* instance, - int64_t position, - int whence) - { - return static_cast(instance->toAddon->addonInstance) - ->SeekRecordedStream(position, whence); - } - - inline static int64_t ADDON_LengthRecordedStream(const AddonInstance_PVR* instance) - { - return static_cast(instance->toAddon->addonInstance) - ->LengthRecordedStream(); - } - - inline static void ADDON_DemuxReset(const AddonInstance_PVR* instance) - { - static_cast(instance->toAddon->addonInstance)->DemuxReset(); - } - - inline static void ADDON_DemuxAbort(const AddonInstance_PVR* instance) - { - static_cast(instance->toAddon->addonInstance)->DemuxAbort(); - } - - inline static void ADDON_DemuxFlush(const AddonInstance_PVR* instance) - { - static_cast(instance->toAddon->addonInstance)->DemuxFlush(); - } - - inline static DemuxPacket* ADDON_DemuxRead(const AddonInstance_PVR* instance) - { - return static_cast(instance->toAddon->addonInstance)->DemuxRead(); - } - - inline static bool ADDON_CanPauseStream(const AddonInstance_PVR* instance) - { - return static_cast(instance->toAddon->addonInstance)->CanPauseStream(); - } - - inline static bool ADDON_CanSeekStream(const AddonInstance_PVR* instance) - { - return static_cast(instance->toAddon->addonInstance)->CanSeekStream(); - } - - inline static void ADDON_PauseStream(const AddonInstance_PVR* instance, bool bPaused) - { - static_cast(instance->toAddon->addonInstance)->PauseStream(bPaused); - } - - inline static bool ADDON_SeekTime(const AddonInstance_PVR* instance, - double time, - bool backwards, - double* startpts) - { - return static_cast(instance->toAddon->addonInstance) - ->SeekTime(time, backwards, *startpts); - } - - inline static void ADDON_SetSpeed(const AddonInstance_PVR* instance, int speed) - { - static_cast(instance->toAddon->addonInstance)->SetSpeed(speed); - } - - inline static void ADDON_FillBuffer(const AddonInstance_PVR* instance, bool mode) - { - static_cast(instance->toAddon->addonInstance)->FillBuffer(mode); - } - - inline static PVR_ERROR ADDON_GetStreamTimes(const AddonInstance_PVR* instance, - PVR_STREAM_TIMES* times) - { - PVRStreamTimes cppTimes(times); - return static_cast(instance->toAddon->addonInstance) - ->GetStreamTimes(cppTimes); - } - ///@} - - AddonInstance_PVR* m_instanceData = nullptr; -}; -//}}} -//______________________________________________________________________________ - -} /* namespace addon */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Peripheral.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Peripheral.h deleted file mode 100644 index 2067d51..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Peripheral.h +++ /dev/null @@ -1,847 +0,0 @@ -/* - * Copyright (C) 2014-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../AddonBase.h" - -namespace kodi { namespace addon { class CInstancePeripheral; }} - -/* indicates a joystick has no preference for port number */ -#define NO_PORT_REQUESTED (-1) - -/* joystick's driver button/hat/axis index is unknown */ -#define DRIVER_INDEX_UNKNOWN (-1) - -extern "C" -{ - - /// @name Peripheral types - ///{ - - /*! - * @brief API error codes - */ - typedef enum PERIPHERAL_ERROR - { - PERIPHERAL_NO_ERROR = 0, // no error occurred - PERIPHERAL_ERROR_UNKNOWN = -1, // an unknown error occurred - PERIPHERAL_ERROR_FAILED = -2, // the command failed - PERIPHERAL_ERROR_INVALID_PARAMETERS = -3, // the parameters of the method are invalid for this operation - PERIPHERAL_ERROR_NOT_IMPLEMENTED = -4, // the method that the frontend called is not implemented - PERIPHERAL_ERROR_NOT_CONNECTED = -5, // no peripherals are connected - PERIPHERAL_ERROR_CONNECTION_FAILED = -6, // peripherals are connected, but command was interrupted - } PERIPHERAL_ERROR; - - /*! - * @brief Peripheral types - */ - typedef enum PERIPHERAL_TYPE - { - PERIPHERAL_TYPE_UNKNOWN, - PERIPHERAL_TYPE_JOYSTICK, - PERIPHERAL_TYPE_KEYBOARD, - } PERIPHERAL_TYPE; - - /*! - * @brief Information shared between peripherals - */ - typedef struct PERIPHERAL_INFO - { - PERIPHERAL_TYPE type; /*!< @brief type of peripheral */ - char* name; /*!< @brief name of peripheral */ - uint16_t vendor_id; /*!< @brief vendor ID of peripheral, 0x0000 if unknown */ - uint16_t product_id; /*!< @brief product ID of peripheral, 0x0000 if unknown */ - unsigned int index; /*!< @brief the order in which the add-on identified this peripheral */ - } ATTRIBUTE_PACKED PERIPHERAL_INFO; - - /*! - * @brief Peripheral add-on capabilities. - */ - typedef struct PERIPHERAL_CAPABILITIES - { - bool provides_joysticks; /*!< @brief true if the add-on provides joysticks */ - bool provides_joystick_rumble; - bool provides_joystick_power_off; - bool provides_buttonmaps; /*!< @brief true if the add-on provides button maps */ - } ATTRIBUTE_PACKED PERIPHERAL_CAPABILITIES; - ///} - - /// @name Event types - ///{ - - /*! - * @brief Types of events that can be sent and received - */ - typedef enum PERIPHERAL_EVENT_TYPE - { - PERIPHERAL_EVENT_TYPE_NONE, /*!< @brief unknown event */ - PERIPHERAL_EVENT_TYPE_DRIVER_BUTTON, /*!< @brief state changed for joystick driver button */ - PERIPHERAL_EVENT_TYPE_DRIVER_HAT, /*!< @brief state changed for joystick driver hat */ - PERIPHERAL_EVENT_TYPE_DRIVER_AXIS, /*!< @brief state changed for joystick driver axis */ - PERIPHERAL_EVENT_TYPE_SET_MOTOR, /*!< @brief set the state for joystick rumble motor */ - } PERIPHERAL_EVENT_TYPE; - - /*! - * @brief States a button can have - */ - typedef enum JOYSTICK_STATE_BUTTON - { - JOYSTICK_STATE_BUTTON_UNPRESSED = 0x0, /*!< @brief button is released */ - JOYSTICK_STATE_BUTTON_PRESSED = 0x1, /*!< @brief button is pressed */ - } JOYSTICK_STATE_BUTTON; - - /*! - * @brief States a D-pad (also called a hat) can have - */ - typedef enum JOYSTICK_STATE_HAT - { - JOYSTICK_STATE_HAT_UNPRESSED = 0x0, /*!< @brief no directions are pressed */ - JOYSTICK_STATE_HAT_LEFT = 0x1, /*!< @brief only left is pressed */ - JOYSTICK_STATE_HAT_RIGHT = 0x2, /*!< @brief only right is pressed */ - JOYSTICK_STATE_HAT_UP = 0x4, /*!< @brief only up is pressed */ - JOYSTICK_STATE_HAT_DOWN = 0x8, /*!< @brief only down is pressed */ - JOYSTICK_STATE_HAT_LEFT_UP = JOYSTICK_STATE_HAT_LEFT | JOYSTICK_STATE_HAT_UP, - JOYSTICK_STATE_HAT_LEFT_DOWN = JOYSTICK_STATE_HAT_LEFT | JOYSTICK_STATE_HAT_DOWN, - JOYSTICK_STATE_HAT_RIGHT_UP = JOYSTICK_STATE_HAT_RIGHT | JOYSTICK_STATE_HAT_UP, - JOYSTICK_STATE_HAT_RIGHT_DOWN = JOYSTICK_STATE_HAT_RIGHT | JOYSTICK_STATE_HAT_DOWN, - } JOYSTICK_STATE_HAT; - - /*! - * @brief Axis value in the closed interval [-1.0, 1.0] - * - * The axis state uses the XInput coordinate system: - * - Negative values signify down or to the left - * - Positive values signify up or to the right - */ - typedef float JOYSTICK_STATE_AXIS; - - /*! - * @brief Motor value in the closed interval [0.0, 1.0] - */ - typedef float JOYSTICK_STATE_MOTOR; - - /*! - * @brief Event information - */ - typedef struct PERIPHERAL_EVENT - { - /*! @brief Index of the peripheral handling/receiving the event */ - unsigned int peripheral_index; - - /*! @brief Type of the event used to determine which enum field to access below */ - PERIPHERAL_EVENT_TYPE type; - - /*! @brief The index of the event source */ - unsigned int driver_index; - - JOYSTICK_STATE_BUTTON driver_button_state; - JOYSTICK_STATE_HAT driver_hat_state; - JOYSTICK_STATE_AXIS driver_axis_state; - JOYSTICK_STATE_MOTOR motor_state; - } ATTRIBUTE_PACKED PERIPHERAL_EVENT; - ///} - - /// @name Joystick types - ///{ - - /*! - * @brief Info specific to joystick peripherals - */ - typedef struct JOYSTICK_INFO - { - PERIPHERAL_INFO peripheral; /*!< @brief peripheral info for this joystick */ - char* provider; /*!< @brief name of the driver or interface providing the joystick */ - int requested_port; /*!< @brief requested port number (such as for 360 controllers), or NO_PORT_REQUESTED */ - unsigned int button_count; /*!< @brief number of buttons reported by the driver */ - unsigned int hat_count; /*!< @brief number of hats reported by the driver */ - unsigned int axis_count; /*!< @brief number of axes reported by the driver */ - unsigned int motor_count; /*!< @brief number of motors reported by the driver */ - bool supports_poweroff; /*!< @brief whether the joystick supports being powered off */ - } ATTRIBUTE_PACKED JOYSTICK_INFO; - - /*! - * @brief Driver input primitives - * - * Mapping lower-level driver values to higher-level controller features is - * non-injective; two triggers can share a single axis. - * - * To handle this, driver values are subdivided into "primitives" that map - * injectively to higher-level features. - */ - typedef enum JOYSTICK_DRIVER_PRIMITIVE_TYPE - { - JOYSTICK_DRIVER_PRIMITIVE_TYPE_UNKNOWN, - JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON, - JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION, - JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS, - JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR, - JOYSTICK_DRIVER_PRIMITIVE_TYPE_KEY, - JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOUSE_BUTTON, - JOYSTICK_DRIVER_PRIMITIVE_TYPE_RELPOINTER_DIRECTION, - } JOYSTICK_DRIVER_PRIMITIVE_TYPE; - - /*! - * @brief Button primitive - */ - typedef struct JOYSTICK_DRIVER_BUTTON - { - int index; - } ATTRIBUTE_PACKED JOYSTICK_DRIVER_BUTTON; - - /*! - * @brief Hat direction - */ - typedef enum JOYSTICK_DRIVER_HAT_DIRECTION - { - JOYSTICK_DRIVER_HAT_UNKNOWN, - JOYSTICK_DRIVER_HAT_LEFT, - JOYSTICK_DRIVER_HAT_RIGHT, - JOYSTICK_DRIVER_HAT_UP, - JOYSTICK_DRIVER_HAT_DOWN, - } JOYSTICK_DRIVER_HAT_DIRECTION; - - /*! - * @brief Hat direction primitive - */ - typedef struct JOYSTICK_DRIVER_HAT - { - int index; - JOYSTICK_DRIVER_HAT_DIRECTION direction; - } ATTRIBUTE_PACKED JOYSTICK_DRIVER_HAT; - - /*! - * @brief Semiaxis direction - */ - typedef enum JOYSTICK_DRIVER_SEMIAXIS_DIRECTION - { - JOYSTICK_DRIVER_SEMIAXIS_NEGATIVE = -1, /*!< @brief negative half of the axis */ - JOYSTICK_DRIVER_SEMIAXIS_UNKNOWN = 0, /*!< @brief unknown direction */ - JOYSTICK_DRIVER_SEMIAXIS_POSITIVE = 1, /*!< @brief positive half of the axis */ - } JOYSTICK_DRIVER_SEMIAXIS_DIRECTION; - - /*! - * @brief Semiaxis primitive - */ - typedef struct JOYSTICK_DRIVER_SEMIAXIS - { - int index; - int center; - JOYSTICK_DRIVER_SEMIAXIS_DIRECTION direction; - unsigned int range; - } ATTRIBUTE_PACKED JOYSTICK_DRIVER_SEMIAXIS; - - /*! - * @brief Motor primitive - */ - typedef struct JOYSTICK_DRIVER_MOTOR - { - int index; - } ATTRIBUTE_PACKED JOYSTICK_DRIVER_MOTOR; - - /*! - * @brief Keyboard key primitive - */ - typedef struct JOYSTICK_DRIVER_KEY - { - char keycode[16]; - } ATTRIBUTE_PACKED JOYSTICK_DRIVER_KEY; - - /*! - * @brief Mouse buttons - */ - typedef enum JOYSTICK_DRIVER_MOUSE_INDEX - { - JOYSTICK_DRIVER_MOUSE_INDEX_UNKNOWN, - JOYSTICK_DRIVER_MOUSE_INDEX_LEFT, - JOYSTICK_DRIVER_MOUSE_INDEX_RIGHT, - JOYSTICK_DRIVER_MOUSE_INDEX_MIDDLE, - JOYSTICK_DRIVER_MOUSE_INDEX_BUTTON4, - JOYSTICK_DRIVER_MOUSE_INDEX_BUTTON5, - JOYSTICK_DRIVER_MOUSE_INDEX_WHEEL_UP, - JOYSTICK_DRIVER_MOUSE_INDEX_WHEEL_DOWN, - JOYSTICK_DRIVER_MOUSE_INDEX_HORIZ_WHEEL_LEFT, - JOYSTICK_DRIVER_MOUSE_INDEX_HORIZ_WHEEL_RIGHT, - } JOYSTICK_DRIVER_MOUSE_INDEX; - - /*! - * @brief Mouse button primitive - */ - typedef struct JOYSTICK_DRIVER_MOUSE_BUTTON - { - JOYSTICK_DRIVER_MOUSE_INDEX button; - } ATTRIBUTE_PACKED JOYSTICK_DRIVER_MOUSE_BUTTON; - - /*! - * @brief Relative pointer direction - */ - typedef enum JOYSTICK_DRIVER_RELPOINTER_DIRECTION - { - JOYSTICK_DRIVER_RELPOINTER_UNKNOWN, - JOYSTICK_DRIVER_RELPOINTER_LEFT, - JOYSTICK_DRIVER_RELPOINTER_RIGHT, - JOYSTICK_DRIVER_RELPOINTER_UP, - JOYSTICK_DRIVER_RELPOINTER_DOWN, - } JOYSTICK_DRIVER_RELPOINTER_DIRECTION; - - /*! - * @brief Relative pointer direction primitive - */ - typedef struct JOYSTICK_DRIVER_RELPOINTER - { - JOYSTICK_DRIVER_RELPOINTER_DIRECTION direction; - } ATTRIBUTE_PACKED JOYSTICK_DRIVER_RELPOINTER; - - /*! - * @brief Driver primitive struct - */ - typedef struct JOYSTICK_DRIVER_PRIMITIVE - { - JOYSTICK_DRIVER_PRIMITIVE_TYPE type; - union - { - struct JOYSTICK_DRIVER_BUTTON button; - struct JOYSTICK_DRIVER_HAT hat; - struct JOYSTICK_DRIVER_SEMIAXIS semiaxis; - struct JOYSTICK_DRIVER_MOTOR motor; - struct JOYSTICK_DRIVER_KEY key; - struct JOYSTICK_DRIVER_MOUSE_BUTTON mouse; - struct JOYSTICK_DRIVER_RELPOINTER relpointer; - }; - } ATTRIBUTE_PACKED JOYSTICK_DRIVER_PRIMITIVE; - - /*! - * @brief Controller feature - * - * Controller features are an abstraction over driver values. Each feature - * maps to one or more driver primitives. - */ - typedef enum JOYSTICK_FEATURE_TYPE - { - JOYSTICK_FEATURE_TYPE_UNKNOWN, - JOYSTICK_FEATURE_TYPE_SCALAR, - JOYSTICK_FEATURE_TYPE_ANALOG_STICK, - JOYSTICK_FEATURE_TYPE_ACCELEROMETER, - JOYSTICK_FEATURE_TYPE_MOTOR, - JOYSTICK_FEATURE_TYPE_RELPOINTER, - JOYSTICK_FEATURE_TYPE_ABSPOINTER, - JOYSTICK_FEATURE_TYPE_WHEEL, - JOYSTICK_FEATURE_TYPE_THROTTLE, - JOYSTICK_FEATURE_TYPE_KEY, - } JOYSTICK_FEATURE_TYPE; - - /*! - * @brief Indices used to access a feature's driver primitives - */ - typedef enum JOYSTICK_FEATURE_PRIMITIVE - { - // Scalar feature (a button, hat direction or semiaxis) - JOYSTICK_SCALAR_PRIMITIVE = 0, - - // Analog stick - JOYSTICK_ANALOG_STICK_UP = 0, - JOYSTICK_ANALOG_STICK_DOWN = 1, - JOYSTICK_ANALOG_STICK_RIGHT = 2, - JOYSTICK_ANALOG_STICK_LEFT = 3, - - // Accelerometer - JOYSTICK_ACCELEROMETER_POSITIVE_X = 0, - JOYSTICK_ACCELEROMETER_POSITIVE_Y = 1, - JOYSTICK_ACCELEROMETER_POSITIVE_Z = 2, - - // Motor - JOYSTICK_MOTOR_PRIMITIVE = 0, - - // Wheel - JOYSTICK_WHEEL_LEFT = 0, - JOYSTICK_WHEEL_RIGHT = 1, - - // Throttle - JOYSTICK_THROTTLE_UP = 0, - JOYSTICK_THROTTLE_DOWN = 1, - - // Key - JOYSTICK_KEY_PRIMITIVE = 0, - - // Mouse button - JOYSTICK_MOUSE_BUTTON = 0, - - // Relative pointer direction - JOYSTICK_RELPOINTER_UP = 0, - JOYSTICK_RELPOINTER_DOWN = 1, - JOYSTICK_RELPOINTER_RIGHT = 2, - JOYSTICK_RELPOINTER_LEFT = 3, - - // Maximum number of primitives - JOYSTICK_PRIMITIVE_MAX = 4, - } JOYSTICK_FEATURE_PRIMITIVE; - - /*! - * @brief Mapping between higher-level controller feature and its driver primitives - */ - typedef struct JOYSTICK_FEATURE - { - char* name; - JOYSTICK_FEATURE_TYPE type; - struct JOYSTICK_DRIVER_PRIMITIVE primitives[JOYSTICK_PRIMITIVE_MAX]; - } ATTRIBUTE_PACKED JOYSTICK_FEATURE; - ///} - - typedef struct AddonProps_Peripheral - { - const char* user_path; /*!< @brief path to the user profile */ - const char* addon_path; /*!< @brief path to this add-on */ - } ATTRIBUTE_PACKED AddonProps_Peripheral; - - struct AddonInstance_Peripheral; - - typedef struct AddonToKodiFuncTable_Peripheral - { - KODI_HANDLE kodiInstance; - void (*trigger_scan)(void* kodiInstance); - void (*refresh_button_maps)(void* kodiInstance, const char* device_name, const char* controller_id); - unsigned int (*feature_count)(void* kodiInstance, const char* controller_id, JOYSTICK_FEATURE_TYPE type); - JOYSTICK_FEATURE_TYPE (*feature_type)(void* kodiInstance, const char* controller_id, const char* feature_name); - } AddonToKodiFuncTable_Peripheral; - - //! @todo Mouse, light gun, multitouch - - typedef struct KodiToAddonFuncTable_Peripheral - { - kodi::addon::CInstancePeripheral* addonInstance; - - void (__cdecl* get_capabilities)(const AddonInstance_Peripheral* addonInstance, PERIPHERAL_CAPABILITIES* capabilities); - PERIPHERAL_ERROR (__cdecl* perform_device_scan)(const AddonInstance_Peripheral* addonInstance, unsigned int* peripheral_count, PERIPHERAL_INFO** scan_results); - void (__cdecl* free_scan_results)(const AddonInstance_Peripheral* addonInstance, unsigned int peripheral_count, PERIPHERAL_INFO* scan_results); - PERIPHERAL_ERROR (__cdecl* get_events)(const AddonInstance_Peripheral* addonInstance, unsigned int* event_count, PERIPHERAL_EVENT** events); - void (__cdecl* free_events)(const AddonInstance_Peripheral* addonInstance, unsigned int event_count, PERIPHERAL_EVENT* events); - bool (__cdecl* send_event)(const AddonInstance_Peripheral* addonInstance, const PERIPHERAL_EVENT* event); - - /// @name Joystick operations - ///{ - PERIPHERAL_ERROR (__cdecl* get_joystick_info)(const AddonInstance_Peripheral* addonInstance, unsigned int index, JOYSTICK_INFO* info); - void (__cdecl* free_joystick_info)(const AddonInstance_Peripheral* addonInstance, JOYSTICK_INFO* info); - PERIPHERAL_ERROR (__cdecl* get_features)(const AddonInstance_Peripheral* addonInstance, const JOYSTICK_INFO* joystick, const char* controller_id, unsigned int* feature_count, JOYSTICK_FEATURE** features); - void (__cdecl* free_features)(const AddonInstance_Peripheral* addonInstance, unsigned int feature_count, JOYSTICK_FEATURE* features); - PERIPHERAL_ERROR (__cdecl* map_features)(const AddonInstance_Peripheral* addonInstance, const JOYSTICK_INFO* joystick, const char* controller_id, unsigned int feature_count, const JOYSTICK_FEATURE* features); - PERIPHERAL_ERROR (__cdecl* get_ignored_primitives)(const AddonInstance_Peripheral* addonInstance, const JOYSTICK_INFO* joystick, unsigned int* feature_count, JOYSTICK_DRIVER_PRIMITIVE** primitives); - void (__cdecl* free_primitives)(const AddonInstance_Peripheral* addonInstance, unsigned int, JOYSTICK_DRIVER_PRIMITIVE* primitives); - PERIPHERAL_ERROR (__cdecl* set_ignored_primitives)(const AddonInstance_Peripheral* addonInstance, const JOYSTICK_INFO* joystick, unsigned int primitive_count, const JOYSTICK_DRIVER_PRIMITIVE* primitives); - void (__cdecl* save_button_map)(const AddonInstance_Peripheral* addonInstance, const JOYSTICK_INFO* joystick); - void (__cdecl* revert_button_map)(const AddonInstance_Peripheral* addonInstance, const JOYSTICK_INFO* joystick); - void (__cdecl* reset_button_map)(const AddonInstance_Peripheral* addonInstance, const JOYSTICK_INFO* joystick, const char* controller_id); - void (__cdecl* power_off_joystick)(const AddonInstance_Peripheral* addonInstance, unsigned int index); - ///} - } KodiToAddonFuncTable_Peripheral; - - typedef struct AddonInstance_Peripheral - { - AddonProps_Peripheral props; - AddonToKodiFuncTable_Peripheral toKodi; - KodiToAddonFuncTable_Peripheral toAddon; - } AddonInstance_Peripheral; - -} /* extern "C" */ - -namespace kodi -{ -namespace addon -{ - - class ATTRIBUTE_HIDDEN CInstancePeripheral : public IAddonInstance - { - public: - CInstancePeripheral() - : IAddonInstance(ADDON_INSTANCE_PERIPHERAL, GetKodiTypeVersion(ADDON_INSTANCE_PERIPHERAL)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstancePeripheral: Creation of more as one in single instance way is not allowed!"); - - SetAddonStruct(CAddonBase::m_interface->firstKodiInstance); - CAddonBase::m_interface->globalSingleInstance = this; - } - - explicit CInstancePeripheral(KODI_HANDLE instance, const std::string& kodiVersion = "") - : IAddonInstance(ADDON_INSTANCE_PERIPHERAL, - !kodiVersion.empty() ? kodiVersion - : GetKodiTypeVersion(ADDON_INSTANCE_PERIPHERAL)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstancePeripheral: Creation of multiple together with single instance way is not allowed!"); - - SetAddonStruct(instance); - } - - ~CInstancePeripheral() override = default; - - /// @name Peripheral operations - ///{ - /*! - * @brief Get the list of features that this add-on provides - * @param capabilities The add-on's capabilities. - * @remarks Valid implementation required. - * - * Called by the frontend to query the add-on's capabilities and supported - * peripherals. All capabilities that the add-on supports should be set to true. - * - */ - virtual void GetCapabilities(PERIPHERAL_CAPABILITIES &capabilities) { } - - /*! - * @brief Perform a scan for joysticks - * @param peripheral_count Assigned to the number of peripherals allocated - * @param scan_results Assigned to allocated memory - * @return PERIPHERAL_NO_ERROR if successful; peripherals must be freed using - * FreeScanResults() in this case - * - * The frontend calls this when a hardware change is detected. If an add-on - * detects a hardware change, it can trigger this function using the - * TriggerScan() callback. - */ - virtual PERIPHERAL_ERROR PerformDeviceScan(unsigned int* peripheral_count, PERIPHERAL_INFO** scan_results) { return PERIPHERAL_ERROR_NOT_IMPLEMENTED; } - - /*! - * @brief Free the memory allocated in PerformDeviceScan() - * - * Must be called if PerformDeviceScan() returns PERIPHERAL_NO_ERROR. - * - * @param peripheral_count The number of events allocated for the events array - * @param scan_results The array of allocated peripherals - */ - virtual void FreeScanResults(unsigned int peripheral_count, PERIPHERAL_INFO* scan_results) { } - - /*! - * @brief Get all events that have occurred since the last call to GetEvents() - * @return PERIPHERAL_NO_ERROR if successful; events must be freed using - * FreeEvents() in this case - */ - virtual PERIPHERAL_ERROR GetEvents(unsigned int* event_count, PERIPHERAL_EVENT** events) { return PERIPHERAL_ERROR_NOT_IMPLEMENTED; } - - /*! - * @brief Free the memory allocated in GetEvents() - * - * Must be called if GetEvents() returns PERIPHERAL_NO_ERROR. - * - * @param event_count The number of events allocated for the events array - * @param events The array of allocated events - */ - virtual void FreeEvents(unsigned int event_count, PERIPHERAL_EVENT* events) { } - - /*! - * @brief Send an input event to the peripheral - * @param event The input event - * @return true if the event was handled, false otherwise - */ - virtual bool SendEvent(const PERIPHERAL_EVENT* event) { return false; } - ///} - - /// @name Joystick operations - /*! - * @note #define PERIPHERAL_ADDON_JOYSTICKS before including kodi_peripheral_dll.h - * in the add-on if the add-on provides joysticks and add provides_joysticks="true" - * to the kodi.peripheral extension point node in addon.xml. - */ - ///{ - /*! - * @brief Get extended info about an attached joystick - * @param index The joystick's driver index - * @param info The container for the allocated joystick info - * @return PERIPHERAL_NO_ERROR if successful; array must be freed using - * FreeJoystickInfo() in this case - */ - virtual PERIPHERAL_ERROR GetJoystickInfo(unsigned int index, JOYSTICK_INFO* info) { return PERIPHERAL_ERROR_NOT_IMPLEMENTED; } - - /*! - * @brief Free the memory allocated in GetJoystickInfo() - */ - virtual void FreeJoystickInfo(JOYSTICK_INFO* info) { } - - /*! - * @brief Get the features that allow translating the joystick into the controller profile - * @param joystick The device's joystick properties; unknown values may be left at their default - * @param controller_id The controller profile being requested, e.g. game.controller.default - * @param feature_count The number of features allocated for the features array - * @param features The array of allocated features - * @return PERIPHERAL_NO_ERROR if successful; array must be freed using - * FreeButtonMap() in this case - */ - virtual PERIPHERAL_ERROR GetFeatures(const JOYSTICK_INFO* joystick, const char* controller_id, - unsigned int* feature_count, JOYSTICK_FEATURE** features) { return PERIPHERAL_ERROR_NOT_IMPLEMENTED; } - - /*! - * @brief Free the memory allocated in GetFeatures() - * - * Must be called if GetFeatures() returns PERIPHERAL_NO_ERROR. - * - * @param feature_count The number of features allocated for the features array - * @param features The array of allocated features - */ - virtual void FreeFeatures(unsigned int feature_count, JOYSTICK_FEATURE* features) { } - - /*! - * @brief Add or update joystick features - * @param joystick The device's joystick properties; unknown values may be left at their default - * @param controller_id The game controller profile being updated - * @param feature_count The number of features in the features array - * @param features The array of features - * @return PERIPHERAL_NO_ERROR if successful - */ - virtual PERIPHERAL_ERROR MapFeatures(const JOYSTICK_INFO* joystick, const char* controller_id, - unsigned int feature_count, const JOYSTICK_FEATURE* features) { return PERIPHERAL_ERROR_NOT_IMPLEMENTED; } - - /*! - * @brief Get the driver primitives that should be ignored while mapping the device - * @param joystick The device's joystick properties; unknown values may be left at their default - * @param primitive_count The number of features allocated for the primitives array - * @param primitives The array of allocated driver primitives to be ignored - * @return PERIPHERAL_NO_ERROR if successful; array must be freed using - * FreePrimitives() in this case - */ - virtual PERIPHERAL_ERROR GetIgnoredPrimitives(const JOYSTICK_INFO* joystick, - unsigned int* primitive_count, - JOYSTICK_DRIVER_PRIMITIVE** primitives) { return PERIPHERAL_ERROR_NOT_IMPLEMENTED; } - - /*! - * @brief Free the memory allocated in GetIgnoredPrimitives() - * - * Must be called if GetIgnoredPrimitives() returns PERIPHERAL_NO_ERROR. - * - * @param primitive_count The number of driver primitives allocated for the primitives array - * @param primitives The array of allocated driver primitives - */ - virtual void FreePrimitives(unsigned int primitive_count, JOYSTICK_DRIVER_PRIMITIVE* primitives) { } - - /*! - * @brief Set the list of driver primitives that are ignored for the device - * @param joystick The device's joystick properties; unknown values may be left at their default - * @param primitive_count The number of driver features in the primitives array - * @param primitives The array of driver primitives to ignore - * @return PERIPHERAL_NO_ERROR if successful - */ - virtual PERIPHERAL_ERROR SetIgnoredPrimitives(const JOYSTICK_INFO* joystick, - unsigned int primitive_count, - const JOYSTICK_DRIVER_PRIMITIVE* primitives) { return PERIPHERAL_ERROR_NOT_IMPLEMENTED; } - - /*! - * @brief Save the button map for the given joystick - * @param joystick The device's joystick properties - */ - virtual void SaveButtonMap(const JOYSTICK_INFO* joystick) { } - - /*! - * @brief Revert the button map to the last time it was loaded or committed to disk - * @param joystick The device's joystick properties - */ - virtual void RevertButtonMap(const JOYSTICK_INFO* joystick) { } - - /*! - * @brief Reset the button map for the given joystick and controller profile ID - * @param joystick The device's joystick properties - * @param controller_id The game controller profile being reset - */ - virtual void ResetButtonMap(const JOYSTICK_INFO* joystick, const char* controller_id) { } - - /*! - * @brief Powers off the given joystick if supported - * @param index The joystick's driver index - */ - virtual void PowerOffJoystick(unsigned int index) { } - - const std::string AddonPath() const - { - return m_instanceData->props.addon_path; - } - - const std::string UserPath() const - { - return m_instanceData->props.user_path; - } - - /*! - * @brief Trigger a scan for peripherals - * - * The add-on calls this if a change in hardware is detected. - */ - void TriggerScan(void) - { - return m_instanceData->toKodi.trigger_scan(m_instanceData->toKodi.kodiInstance); - } - - /*! - * @brief Notify the frontend that button maps have changed - * - * @param[optional] deviceName The name of the device to refresh, or empty/null for all devices - * @param[optional] controllerId The controller ID to refresh, or empty/null for all controllers - */ - void RefreshButtonMaps(const std::string& deviceName = "", const std::string& controllerId = "") - { - return m_instanceData->toKodi.refresh_button_maps(m_instanceData->toKodi.kodiInstance, deviceName.c_str(), controllerId.c_str()); - } - - /*! - * @brief Return the number of features belonging to the specified controller - * - * @param controllerId The controller ID to enumerate - * @param type[optional] Type to filter by, or JOYSTICK_FEATURE_TYPE_UNKNOWN for all features - * - * @return The number of features matching the request parameters - */ - unsigned int FeatureCount(const std::string& controllerId, JOYSTICK_FEATURE_TYPE type = JOYSTICK_FEATURE_TYPE_UNKNOWN) - { - return m_instanceData->toKodi.feature_count(m_instanceData->toKodi.kodiInstance, controllerId.c_str(), type); - } - - /*! - * @brief Return the type of the feature - * - * @param controllerId The controller ID to check - * @param featureName The feature to check - * - * @return The type of the specified feature, or JOYSTICK_FEATURE_TYPE_UNKNOWN - * if unknown - */ - JOYSTICK_FEATURE_TYPE FeatureType(const std::string& controllerId, const std::string &featureName) - { - return m_instanceData->toKodi.feature_type(m_instanceData->toKodi.kodiInstance, controllerId.c_str(), featureName.c_str()); - } - - private: - void SetAddonStruct(KODI_HANDLE instance) - { - if (instance == nullptr) - throw std::logic_error("kodi::addon::CInstancePeripheral: Creation with empty addon structure not allowed, table must be given from Kodi!"); - - m_instanceData = static_cast(instance); - m_instanceData->toAddon.addonInstance = this; - - m_instanceData->toAddon.get_capabilities = ADDON_GetCapabilities; - m_instanceData->toAddon.perform_device_scan = ADDON_PerformDeviceScan; - m_instanceData->toAddon.free_scan_results = ADDON_FreeScanResults; - m_instanceData->toAddon.get_events = ADDON_GetEvents; - m_instanceData->toAddon.free_events = ADDON_FreeEvents; - m_instanceData->toAddon.send_event = ADDON_SendEvent; - - m_instanceData->toAddon.get_joystick_info = ADDON_GetJoystickInfo; - m_instanceData->toAddon.free_joystick_info = ADDON_FreeJoystickInfo; - m_instanceData->toAddon.get_features = ADDON_GetFeatures; - m_instanceData->toAddon.free_features = ADDON_FreeFeatures; - m_instanceData->toAddon.map_features = ADDON_MapFeatures; - m_instanceData->toAddon.get_ignored_primitives = ADDON_GetIgnoredPrimitives; - m_instanceData->toAddon.free_primitives = ADDON_FreePrimitives; - m_instanceData->toAddon.set_ignored_primitives = ADDON_SetIgnoredPrimitives; - m_instanceData->toAddon.save_button_map = ADDON_SaveButtonMap; - m_instanceData->toAddon.revert_button_map = ADDON_RevertButtonMap; - m_instanceData->toAddon.reset_button_map = ADDON_ResetButtonMap; - m_instanceData->toAddon.power_off_joystick = ADDON_PowerOffJoystick; - } - - inline static void ADDON_GetCapabilities(const AddonInstance_Peripheral* addonInstance, PERIPHERAL_CAPABILITIES *capabilities) - { - addonInstance->toAddon.addonInstance->GetCapabilities(*capabilities); - } - - inline static PERIPHERAL_ERROR ADDON_PerformDeviceScan(const AddonInstance_Peripheral* addonInstance, unsigned int* peripheral_count, PERIPHERAL_INFO** scan_results) - { - return addonInstance->toAddon.addonInstance->PerformDeviceScan(peripheral_count, scan_results); - } - - inline static void ADDON_FreeScanResults(const AddonInstance_Peripheral* addonInstance, unsigned int peripheral_count, PERIPHERAL_INFO* scan_results) - { - addonInstance->toAddon.addonInstance->FreeScanResults(peripheral_count, scan_results); - } - - inline static PERIPHERAL_ERROR ADDON_GetEvents(const AddonInstance_Peripheral* addonInstance, unsigned int* event_count, PERIPHERAL_EVENT** events) - { - return addonInstance->toAddon.addonInstance->GetEvents(event_count, events); - } - - inline static void ADDON_FreeEvents(const AddonInstance_Peripheral* addonInstance, unsigned int event_count, PERIPHERAL_EVENT* events) - { - addonInstance->toAddon.addonInstance->FreeEvents(event_count, events); - } - - inline static bool ADDON_SendEvent(const AddonInstance_Peripheral* addonInstance, const PERIPHERAL_EVENT* event) - { - return addonInstance->toAddon.addonInstance->SendEvent(event); - } - - - inline static PERIPHERAL_ERROR ADDON_GetJoystickInfo(const AddonInstance_Peripheral* addonInstance, unsigned int index, JOYSTICK_INFO* info) - { - return addonInstance->toAddon.addonInstance->GetJoystickInfo(index, info); - } - - inline static void ADDON_FreeJoystickInfo(const AddonInstance_Peripheral* addonInstance, JOYSTICK_INFO* info) - { - addonInstance->toAddon.addonInstance->FreeJoystickInfo(info); - } - - inline static PERIPHERAL_ERROR ADDON_GetFeatures(const AddonInstance_Peripheral* addonInstance, - const JOYSTICK_INFO* joystick, const char* controller_id, - unsigned int* feature_count, JOYSTICK_FEATURE** features) - { - return addonInstance->toAddon.addonInstance->GetFeatures(joystick, controller_id, feature_count, features); - } - - inline static void ADDON_FreeFeatures(const AddonInstance_Peripheral* addonInstance, unsigned int feature_count, JOYSTICK_FEATURE* features) - { - addonInstance->toAddon.addonInstance->FreeFeatures(feature_count, features); - } - - inline static PERIPHERAL_ERROR ADDON_MapFeatures(const AddonInstance_Peripheral* addonInstance, - const JOYSTICK_INFO* joystick, const char* controller_id, - unsigned int feature_count, const JOYSTICK_FEATURE* features) - { - return addonInstance->toAddon.addonInstance->MapFeatures(joystick, controller_id, feature_count, features); - } - - inline static PERIPHERAL_ERROR ADDON_GetIgnoredPrimitives(const AddonInstance_Peripheral* addonInstance, - const JOYSTICK_INFO* joystick, unsigned int* primitive_count, - JOYSTICK_DRIVER_PRIMITIVE** primitives) - { - return addonInstance->toAddon.addonInstance->GetIgnoredPrimitives(joystick, primitive_count, primitives); - } - - inline static void ADDON_FreePrimitives(const AddonInstance_Peripheral* addonInstance, - unsigned int primitive_count, JOYSTICK_DRIVER_PRIMITIVE* primitives) - { - addonInstance->toAddon.addonInstance->FreePrimitives(primitive_count, primitives); - } - - inline static PERIPHERAL_ERROR ADDON_SetIgnoredPrimitives(const AddonInstance_Peripheral* addonInstance, - const JOYSTICK_INFO* joystick, unsigned int primitive_count, - const JOYSTICK_DRIVER_PRIMITIVE* primitives) - { - return addonInstance->toAddon.addonInstance->SetIgnoredPrimitives(joystick, primitive_count, primitives); - } - - inline static void ADDON_SaveButtonMap(const AddonInstance_Peripheral* addonInstance, const JOYSTICK_INFO* joystick) - { - addonInstance->toAddon.addonInstance->SaveButtonMap(joystick); - } - - inline static void ADDON_RevertButtonMap(const AddonInstance_Peripheral* addonInstance, const JOYSTICK_INFO* joystick) - { - addonInstance->toAddon.addonInstance->RevertButtonMap(joystick); - } - - inline static void ADDON_ResetButtonMap(const AddonInstance_Peripheral* addonInstance, const JOYSTICK_INFO* joystick, const char* controller_id) - { - addonInstance->toAddon.addonInstance->ResetButtonMap(joystick, controller_id); - } - - inline static void ADDON_PowerOffJoystick(const AddonInstance_Peripheral* addonInstance, unsigned int index) - { - addonInstance->toAddon.addonInstance->PowerOffJoystick(index); - } - - AddonInstance_Peripheral* m_instanceData; - }; - -} /* namespace addon */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/PeripheralUtils.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/PeripheralUtils.h deleted file mode 100644 index 62e5a93..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/PeripheralUtils.h +++ /dev/null @@ -1,735 +0,0 @@ -/* - * Copyright (C) 2014-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "Peripheral.h" - -#include // Requires c++11 -#include -#include -#include -#include - -#define PERIPHERAL_SAFE_DELETE(x) do { delete (x); (x) = NULL; } while (0) -#define PERIPHERAL_SAFE_DELETE_ARRAY(x) do { delete[] (x); (x) = NULL; } while (0) - -namespace kodi -{ -namespace addon -{ - /*! - * Utility class to manipulate arrays of peripheral types. - */ - template - class PeripheralVector - { - public: - static void ToStructs(const std::vector& vecObjects, THE_STRUCT** pStructs) - { - if (!pStructs) - return; - - if (vecObjects.empty()) - { - *pStructs = NULL; - } - else - { - (*pStructs) = new THE_STRUCT[vecObjects.size()]; - for (unsigned int i = 0; i < vecObjects.size(); i++) - vecObjects.at(i).ToStruct((*pStructs)[i]); - } - } - - static void ToStructs(const std::vector& vecObjects, THE_STRUCT** pStructs) - { - if (!pStructs) - return; - - if (vecObjects.empty()) - { - *pStructs = NULL; - } - else - { - *pStructs = new THE_STRUCT[vecObjects.size()]; - for (unsigned int i = 0; i < vecObjects.size(); i++) - vecObjects.at(i)->ToStruct((*pStructs)[i]); - } - } - - static void FreeStructs(unsigned int structCount, THE_STRUCT* structs) - { - if (structs) - { - for (unsigned int i = 0; i < structCount; i++) - THE_CLASS::FreeStruct(structs[i]); - } - PERIPHERAL_SAFE_DELETE_ARRAY(structs); - } - }; - - /*! - * ADDON::Peripheral - * - * Wrapper class providing peripheral information. Classes can extend - * Peripheral to inherit peripheral properties. - */ - class Peripheral - { - public: - Peripheral(PERIPHERAL_TYPE type = PERIPHERAL_TYPE_UNKNOWN, const std::string& strName = "") : - m_type(type), - m_strName(strName) - { - } - - explicit Peripheral(const PERIPHERAL_INFO& info) : - m_type(info.type), - m_strName(info.name ? info.name : ""), - m_vendorId(info.vendor_id), - m_productId(info.product_id), - m_index(info.index) - { - } - - virtual ~Peripheral(void) = default; - - PERIPHERAL_TYPE Type(void) const { return m_type; } - const std::string& Name(void) const { return m_strName; } - uint16_t VendorID(void) const { return m_vendorId; } - uint16_t ProductID(void) const { return m_productId; } - unsigned int Index(void) const { return m_index; } - - // Derived property: VID and PID are 0x0000 if unknown - bool IsVidPidKnown(void) const { return m_vendorId != 0 || m_productId != 0; } - - void SetType(PERIPHERAL_TYPE type) { m_type = type; } - void SetName(const std::string& strName) { m_strName = strName; } - void SetVendorID(uint16_t vendorId) { m_vendorId = vendorId; } - void SetProductID(uint16_t productId) { m_productId = productId; } - void SetIndex(unsigned int index) { m_index = index; } - - void ToStruct(PERIPHERAL_INFO& info) const - { - info.type = m_type; - info.name = new char[m_strName.size() + 1]; - info.vendor_id = m_vendorId; - info.product_id = m_productId; - info.index = m_index; - - std::strcpy(info.name, m_strName.c_str()); - } - - static void FreeStruct(PERIPHERAL_INFO& info) - { - PERIPHERAL_SAFE_DELETE_ARRAY(info.name); - } - - private: - PERIPHERAL_TYPE m_type; - std::string m_strName; - uint16_t m_vendorId = 0; - uint16_t m_productId = 0; - unsigned int m_index = 0; - }; - - typedef PeripheralVector Peripherals; - - /*! - * ADDON::PeripheralEvent - * - * Wrapper class for peripheral events. - */ - class PeripheralEvent - { - public: - PeripheralEvent() = default; - - PeripheralEvent(unsigned int peripheralIndex, unsigned int buttonIndex, JOYSTICK_STATE_BUTTON state) : - m_type(PERIPHERAL_EVENT_TYPE_DRIVER_BUTTON), - m_peripheralIndex(peripheralIndex), - m_driverIndex(buttonIndex), - m_buttonState(state) - { - } - - PeripheralEvent(unsigned int peripheralIndex, unsigned int hatIndex, JOYSTICK_STATE_HAT state) : - m_type(PERIPHERAL_EVENT_TYPE_DRIVER_HAT), - m_peripheralIndex(peripheralIndex), - m_driverIndex(hatIndex), - m_hatState(state) - { - } - - PeripheralEvent(unsigned int peripheralIndex, unsigned int axisIndex, JOYSTICK_STATE_AXIS state) : - m_type(PERIPHERAL_EVENT_TYPE_DRIVER_AXIS), - m_peripheralIndex(peripheralIndex), - m_driverIndex(axisIndex), - m_axisState(state) - { - } - - explicit PeripheralEvent(const PERIPHERAL_EVENT& event) : - m_type(event.type), - m_peripheralIndex(event.peripheral_index), - m_driverIndex(event.driver_index), - m_buttonState(event.driver_button_state), - m_hatState(event.driver_hat_state), - m_axisState(event.driver_axis_state), - m_motorState(event.motor_state) - { - } - - PERIPHERAL_EVENT_TYPE Type(void) const { return m_type; } - unsigned int PeripheralIndex(void) const { return m_peripheralIndex; } - unsigned int DriverIndex(void) const { return m_driverIndex; } - JOYSTICK_STATE_BUTTON ButtonState(void) const { return m_buttonState; } - JOYSTICK_STATE_HAT HatState(void) const { return m_hatState; } - JOYSTICK_STATE_AXIS AxisState(void) const { return m_axisState; } - JOYSTICK_STATE_MOTOR MotorState(void) const { return m_motorState; } - - void SetType(PERIPHERAL_EVENT_TYPE type) { m_type = type; } - void SetPeripheralIndex(unsigned int index) { m_peripheralIndex = index; } - void SetDriverIndex(unsigned int index) { m_driverIndex = index; } - void SetButtonState(JOYSTICK_STATE_BUTTON state) { m_buttonState = state; } - void SetHatState(JOYSTICK_STATE_HAT state) { m_hatState = state; } - void SetAxisState(JOYSTICK_STATE_AXIS state) { m_axisState = state; } - void SetMotorState(JOYSTICK_STATE_MOTOR state) { m_motorState = state; } - - void ToStruct(PERIPHERAL_EVENT& event) const - { - event.type = m_type; - event.peripheral_index = m_peripheralIndex; - event.driver_index = m_driverIndex; - event.driver_button_state = m_buttonState; - event.driver_hat_state = m_hatState; - event.driver_axis_state = m_axisState; - event.motor_state = m_motorState; - } - - static void FreeStruct(PERIPHERAL_EVENT& event) - { - (void)event; - } - - private: - PERIPHERAL_EVENT_TYPE m_type = PERIPHERAL_EVENT_TYPE_NONE; - unsigned int m_peripheralIndex = 0; - unsigned int m_driverIndex = 0; - JOYSTICK_STATE_BUTTON m_buttonState = JOYSTICK_STATE_BUTTON_UNPRESSED; - JOYSTICK_STATE_HAT m_hatState = JOYSTICK_STATE_HAT_UNPRESSED; - JOYSTICK_STATE_AXIS m_axisState = 0.0f; - JOYSTICK_STATE_MOTOR m_motorState = 0.0f; - }; - - typedef PeripheralVector PeripheralEvents; - - /*! - * kodi::addon::Joystick - * - * Wrapper class providing additional joystick information not provided by - * ADDON::Peripheral. - */ - class Joystick : public Peripheral - { - public: - Joystick(const std::string& provider = "", const std::string& strName = "") : - Peripheral(PERIPHERAL_TYPE_JOYSTICK, strName), - m_provider(provider), - m_requestedPort(NO_PORT_REQUESTED) - { - } - - Joystick(const Joystick& other) - { - *this = other; - } - - explicit Joystick(const JOYSTICK_INFO& info) : - Peripheral(info.peripheral), - m_provider(info.provider ? info.provider : ""), - m_requestedPort(info.requested_port), - m_buttonCount(info.button_count), - m_hatCount(info.hat_count), - m_axisCount(info.axis_count), - m_motorCount(info.motor_count), - m_supportsPowerOff(info.supports_poweroff) - { - } - - ~Joystick(void) override = default; - - Joystick& operator=(const Joystick& rhs) - { - if (this != &rhs) - { - Peripheral::operator=(rhs); - - m_provider = rhs.m_provider; - m_requestedPort = rhs.m_requestedPort; - m_buttonCount = rhs.m_buttonCount; - m_hatCount = rhs.m_hatCount; - m_axisCount = rhs.m_axisCount; - m_motorCount = rhs.m_motorCount; - m_supportsPowerOff = rhs.m_supportsPowerOff; - } - return *this; - } - - const std::string& Provider(void) const { return m_provider; } - int RequestedPort(void) const { return m_requestedPort; } - unsigned int ButtonCount(void) const { return m_buttonCount; } - unsigned int HatCount(void) const { return m_hatCount; } - unsigned int AxisCount(void) const { return m_axisCount; } - unsigned int MotorCount(void) const { return m_motorCount; } - bool SupportsPowerOff(void) const { return m_supportsPowerOff; } - - void SetProvider(const std::string& provider) { m_provider = provider; } - void SetRequestedPort(int requestedPort) { m_requestedPort = requestedPort; } - void SetButtonCount(unsigned int buttonCount) { m_buttonCount = buttonCount; } - void SetHatCount(unsigned int hatCount) { m_hatCount = hatCount; } - void SetAxisCount(unsigned int axisCount) { m_axisCount = axisCount; } - void SetMotorCount(unsigned int motorCount) { m_motorCount = motorCount; } - void SetSupportsPowerOff(bool supportsPowerOff) { m_supportsPowerOff = supportsPowerOff; } - - void ToStruct(JOYSTICK_INFO& info) const - { - Peripheral::ToStruct(info.peripheral); - - info.provider = new char[m_provider.size() + 1]; - info.requested_port = m_requestedPort; - info.button_count = m_buttonCount; - info.hat_count = m_hatCount; - info.axis_count = m_axisCount; - info.motor_count = m_motorCount; - info.supports_poweroff = m_supportsPowerOff; - - std::strcpy(info.provider, m_provider.c_str()); - } - - static void FreeStruct(JOYSTICK_INFO& info) - { - Peripheral::FreeStruct(info.peripheral); - - PERIPHERAL_SAFE_DELETE_ARRAY(info.provider); - } - - private: - std::string m_provider; - int m_requestedPort; - unsigned int m_buttonCount = 0; - unsigned int m_hatCount = 0; - unsigned int m_axisCount = 0; - unsigned int m_motorCount = 0; - bool m_supportsPowerOff = false; - }; - - typedef PeripheralVector Joysticks; - - /*! - * ADDON::DriverPrimitive - * - * Base class for joystick driver primitives. A driver primitive can be: - * - * 1) a button - * 2) a hat direction - * 3) a semiaxis (either the positive or negative half of an axis) - * 4) a motor - * 5) a keyboard key - * 6) a mouse button - * 7) a relative pointer direction - * - * The type determines the fields in use: - * - * Button: - * - driver index - * - * Hat direction: - * - driver index - * - hat direction - * - * Semiaxis: - * - driver index - * - center - * - semiaxis direction - * - range - * - * Motor: - * - driver index - * - * Key: - * - key code - * - * Mouse button: - * - driver index - * - * Relative pointer direction: - * - relative pointer direction - */ - struct DriverPrimitive - { - protected: - /*! - * \brief Construct a driver primitive of the specified type - */ - DriverPrimitive(JOYSTICK_DRIVER_PRIMITIVE_TYPE type, unsigned int driverIndex) : - m_type(type), - m_driverIndex(driverIndex) - { - } - - public: - /*! - * \brief Construct an invalid driver primitive - */ - DriverPrimitive(void) = default; - - /*! - * \brief Construct a driver primitive representing a joystick button - */ - static DriverPrimitive CreateButton(unsigned int buttonIndex) - { - return DriverPrimitive(JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON, buttonIndex); - } - - /*! - * \brief Construct a driver primitive representing one of the four direction - * arrows on a dpad - */ - DriverPrimitive(unsigned int hatIndex, JOYSTICK_DRIVER_HAT_DIRECTION direction) : - m_type(JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION), - m_driverIndex(hatIndex), - m_hatDirection(direction) - { - } - - /*! - * \brief Construct a driver primitive representing the positive or negative - * half of an axis - */ - DriverPrimitive(unsigned int axisIndex, int center, JOYSTICK_DRIVER_SEMIAXIS_DIRECTION direction, unsigned int range) : - m_type(JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS), - m_driverIndex(axisIndex), - m_center(center), - m_semiAxisDirection(direction), - m_range(range) - { - } - - /*! - * \brief Construct a driver primitive representing a motor - */ - static DriverPrimitive CreateMotor(unsigned int motorIndex) - { - return DriverPrimitive(JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR, motorIndex); - } - - /*! - * \brief Construct a driver primitive representing a key on a keyboard - */ - DriverPrimitive(std::string keycode) : - m_type(JOYSTICK_DRIVER_PRIMITIVE_TYPE_KEY), - m_keycode(std::move(keycode)) - { - } - - /*! - * \brief Construct a driver primitive representing a mouse button - */ - static DriverPrimitive CreateMouseButton(JOYSTICK_DRIVER_MOUSE_INDEX buttonIndex) - { - return DriverPrimitive(JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOUSE_BUTTON, static_cast(buttonIndex)); - } - - /*! - * \brief Construct a driver primitive representing one of the four - * direction in which a relative pointer can move - */ - DriverPrimitive(JOYSTICK_DRIVER_RELPOINTER_DIRECTION direction) : - m_type(JOYSTICK_DRIVER_PRIMITIVE_TYPE_RELPOINTER_DIRECTION), - m_relPointerDirection(direction) - { - } - - explicit DriverPrimitive(const JOYSTICK_DRIVER_PRIMITIVE& primitive) : - m_type(primitive.type) - { - switch (m_type) - { - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON: - { - m_driverIndex = primitive.button.index; - break; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION: - { - m_driverIndex = primitive.hat.index; - m_hatDirection = primitive.hat.direction; - break; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS: - { - m_driverIndex = primitive.semiaxis.index; - m_center = primitive.semiaxis.center; - m_semiAxisDirection = primitive.semiaxis.direction; - m_range = primitive.semiaxis.range; - break; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR: - { - m_driverIndex = primitive.motor.index; - break; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_KEY: - { - m_keycode = primitive.key.keycode; - break; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOUSE_BUTTON: - { - m_driverIndex = primitive.mouse.button; - break; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_RELPOINTER_DIRECTION: - { - m_relPointerDirection = primitive.relpointer.direction; - break; - } - default: - break; - } - } - - JOYSTICK_DRIVER_PRIMITIVE_TYPE Type(void) const { return m_type; } - unsigned int DriverIndex(void) const { return m_driverIndex; } - JOYSTICK_DRIVER_HAT_DIRECTION HatDirection(void) const { return m_hatDirection; } - int Center(void) const { return m_center; } - JOYSTICK_DRIVER_SEMIAXIS_DIRECTION SemiAxisDirection(void) const { return m_semiAxisDirection; } - unsigned int Range(void) const { return m_range; } - const std::string& Keycode(void) const { return m_keycode; } - JOYSTICK_DRIVER_MOUSE_INDEX MouseIndex(void) const { return static_cast(m_driverIndex); } - JOYSTICK_DRIVER_RELPOINTER_DIRECTION RelPointerDirection(void) const { return m_relPointerDirection; } - - bool operator==(const DriverPrimitive& other) const - { - if (m_type == other.m_type) - { - switch (m_type) - { - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON: - { - return m_driverIndex == other.m_driverIndex; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION: - { - return m_driverIndex == other.m_driverIndex && - m_hatDirection == other.m_hatDirection; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS: - { - return m_driverIndex == other.m_driverIndex && - m_center == other.m_center && - m_semiAxisDirection == other.m_semiAxisDirection && - m_range == other.m_range; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_KEY: - { - return m_keycode == other.m_keycode; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR: - { - return m_driverIndex == other.m_driverIndex; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOUSE_BUTTON: - { - return m_driverIndex == other.m_driverIndex; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_RELPOINTER_DIRECTION: - { - return m_relPointerDirection == other.m_relPointerDirection; - } - default: - break; - } - } - return false; - } - - void ToStruct(JOYSTICK_DRIVER_PRIMITIVE& driver_primitive) const - { - driver_primitive.type = m_type; - switch (m_type) - { - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON: - { - driver_primitive.button.index = m_driverIndex; - break; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION: - { - driver_primitive.hat.index = m_driverIndex; - driver_primitive.hat.direction = m_hatDirection; - break; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS: - { - driver_primitive.semiaxis.index = m_driverIndex; - driver_primitive.semiaxis.center = m_center; - driver_primitive.semiaxis.direction = m_semiAxisDirection; - driver_primitive.semiaxis.range = m_range; - break; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR: - { - driver_primitive.motor.index = m_driverIndex; - break; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_KEY: - { - const size_t size = sizeof(driver_primitive.key.keycode); - std::strncpy(driver_primitive.key.keycode, m_keycode.c_str(), size - 1); - driver_primitive.key.keycode[size - 1] = '\0'; - break; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOUSE_BUTTON: - { - driver_primitive.mouse.button = static_cast(m_driverIndex); - break; - } - case JOYSTICK_DRIVER_PRIMITIVE_TYPE_RELPOINTER_DIRECTION: - { - driver_primitive.relpointer.direction = m_relPointerDirection; - break; - } - default: - break; - } - } - - static void FreeStruct(JOYSTICK_DRIVER_PRIMITIVE& primitive) - { - (void)primitive; - } - - private: - JOYSTICK_DRIVER_PRIMITIVE_TYPE m_type = JOYSTICK_DRIVER_PRIMITIVE_TYPE_UNKNOWN; - unsigned int m_driverIndex = 0; - JOYSTICK_DRIVER_HAT_DIRECTION m_hatDirection = JOYSTICK_DRIVER_HAT_UNKNOWN; - int m_center = 0; - JOYSTICK_DRIVER_SEMIAXIS_DIRECTION m_semiAxisDirection = JOYSTICK_DRIVER_SEMIAXIS_UNKNOWN; - unsigned int m_range = 1; - std::string m_keycode; - JOYSTICK_DRIVER_RELPOINTER_DIRECTION m_relPointerDirection = JOYSTICK_DRIVER_RELPOINTER_UNKNOWN; - }; - - typedef PeripheralVector DriverPrimitives; - - /*! - * kodi::addon::JoystickFeature - * - * Class for joystick features. A feature can be: - * - * 1) scalar[1] - * 2) analog stick - * 3) accelerometer - * 4) motor - * 5) relative pointer[2] - * 6) absolute pointer - * 7) wheel - * 8) throttle - * 9) keyboard key - * - * [1] All three driver primitives (buttons, hats and axes) have a state that - * can be represented using a single scalar value. For this reason, - * features that map to a single primitive are called "scalar features". - * - * [2] Relative pointers are similar to analog sticks, but they use - * relative distances instead of positions. - */ - class JoystickFeature - { - public: - JoystickFeature(const std::string& name = "", JOYSTICK_FEATURE_TYPE type = JOYSTICK_FEATURE_TYPE_UNKNOWN) : - m_name(name), - m_type(type), - m_primitives{} - { - } - - JoystickFeature(const JoystickFeature& other) - { - *this = other; - } - - explicit JoystickFeature(const JOYSTICK_FEATURE& feature) : - m_name(feature.name ? feature.name : ""), - m_type(feature.type) - { - for (unsigned int i = 0; i < JOYSTICK_PRIMITIVE_MAX; i++) - m_primitives[i] = DriverPrimitive(feature.primitives[i]); - } - - JoystickFeature& operator=(const JoystickFeature& rhs) - { - if (this != &rhs) - { - m_name = rhs.m_name; - m_type = rhs.m_type; - m_primitives = rhs.m_primitives; - } - return *this; - } - - bool operator==(const JoystickFeature& other) const - { - return m_name == other.m_name && - m_type == other.m_type && - m_primitives == other.m_primitives; - } - - const std::string& Name(void) const { return m_name; } - JOYSTICK_FEATURE_TYPE Type(void) const { return m_type; } - bool IsValid() const { return m_type != JOYSTICK_FEATURE_TYPE_UNKNOWN; } - - void SetName(const std::string& name) { m_name = name; } - void SetType(JOYSTICK_FEATURE_TYPE type) { m_type = type; } - void SetInvalid(void) { m_type = JOYSTICK_FEATURE_TYPE_UNKNOWN; } - - const DriverPrimitive& Primitive(JOYSTICK_FEATURE_PRIMITIVE which) const { return m_primitives[which]; } - void SetPrimitive(JOYSTICK_FEATURE_PRIMITIVE which, const DriverPrimitive& primitive) { m_primitives[which] = primitive; } - - std::array& Primitives() { return m_primitives; } - const std::array& Primitives() const { return m_primitives; } - - void ToStruct(JOYSTICK_FEATURE& feature) const - { - feature.name = new char[m_name.length() + 1]; - feature.type = m_type; - for (unsigned int i = 0; i < JOYSTICK_PRIMITIVE_MAX; i++) - m_primitives[i].ToStruct(feature.primitives[i]); - - std::strcpy(feature.name, m_name.c_str()); - } - - static void FreeStruct(JOYSTICK_FEATURE& feature) - { - PERIPHERAL_SAFE_DELETE_ARRAY(feature.name); - } - - private: - std::string m_name; - JOYSTICK_FEATURE_TYPE m_type; - std::array m_primitives; - }; - - typedef PeripheralVector JoystickFeatures; - -} /* namespace addon */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Screensaver.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Screensaver.h deleted file mode 100644 index f8a7380..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Screensaver.h +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../AddonBase.h" -#include "../gui/renderHelper.h" - -namespace kodi { namespace addon { class CInstanceScreensaver; }} - -extern "C" -{ - -struct AddonInstance_Screensaver; - -/*! - * @brief Screensaver properties - * - * Not to be used outside this header. - */ -typedef struct AddonProps_Screensaver -{ - void *device; - int x; - int y; - int width; - int height; - float pixelRatio; - const char *name; - const char *presets; - const char *profile; -} AddonProps_Screensaver; - -/*! - * @brief Screensaver callbacks - * - * Not to be used outside this header. - */ -typedef struct AddonToKodiFuncTable_Screensaver -{ - KODI_HANDLE kodiInstance; -} AddonToKodiFuncTable_Screensaver; - -/*! - * @brief Screensaver function hooks - * - * Not to be used outside this header. - */ -typedef struct KodiToAddonFuncTable_Screensaver -{ - kodi::addon::CInstanceScreensaver* addonInstance; - bool (__cdecl* Start) (AddonInstance_Screensaver* instance); - void (__cdecl* Stop) (AddonInstance_Screensaver* instance); - void (__cdecl* Render) (AddonInstance_Screensaver* instance); -} KodiToAddonFuncTable_Screensaver; - -/*! - * @brief Screensaver instance - * - * Not to be used outside this header. - */ -typedef struct AddonInstance_Screensaver -{ - AddonProps_Screensaver props; - AddonToKodiFuncTable_Screensaver toKodi; - KodiToAddonFuncTable_Screensaver toAddon; -} AddonInstance_Screensaver; - -} /* extern "C" */ - -namespace kodi -{ -namespace addon -{ - - //============================================================================ - /// - /// \addtogroup cpp_kodi_addon_screensaver - /// @brief \cpp_class{ kodi::addon::CInstanceScreensaver } - /// **Screensaver add-on instance** - /// - /// A screensaver is a Kodi addon that fills the screen with moving images or - /// patterns when the computer is not in use. Initially designed to prevent - /// phosphor burn-in on CRT and plasma computer monitors (hence the name), - /// screensavers are now used primarily for entertainment, security or to - /// display system status information. - /// - /// Include the header \ref ScreenSaver.h "#include " - /// to use this class. - /// - /// This interface allows the creating of screensavers for Kodi, based upon - /// **DirectX** or/and **OpenGL** rendering with `C++` code. - /// - /// The interface is small and easy usable. It has three functions: - /// - /// * Start() - Called on creation - /// * Render() - Called at render time - /// * Stop() - Called when the screensaver has no work - /// - /// Additionally, there are several \ref cpp_kodi_addon_screensaver_CB "other functions" - /// available in which the child class can ask about the current hardware, - /// including the device, display and several other parts. - /// - /// - /// -------------------------------------------------------------------------- - /// - /// - /// **Here is an example of the minimum required code to start a screensaver:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// class CMyScreenSaver : public kodi::addon::CAddonBase, - /// public kodi::addon::CInstanceScreensaver - /// { - /// public: - /// CMyScreenSaver(); - /// - /// bool Start() override; - /// void Render() override; - /// }; - /// - /// CMyScreenSaver::CMyScreenSaver() - /// { - /// ... - /// } - /// - /// bool CMyScreenSaver::Start() - /// { - /// ... - /// return true; - /// } - /// - /// void CMyScreenSaver::Render() - /// { - /// ... - /// } - /// - /// ADDONCREATOR(CMyScreenSaver) - /// ~~~~~~~~~~~~~ - /// - /// - /// -------------------------------------------------------------------------- - /// - /// - /// **Here is another example where the screensaver is used together with - /// other instance types:** - /// - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// class CMyScreenSaver : public ::kodi::addon::CInstanceScreensaver - /// { - /// public: - /// CMyScreenSaver(KODI_HANDLE instance); - /// - /// bool Start() override; - /// void Render() override; - /// }; - /// - /// CMyScreenSaver::CMyScreenSaver(KODI_HANDLE instance) - /// : CInstanceScreensaver(instance) - /// { - /// ... - /// } - /// - /// bool CMyScreenSaver::Start() - /// { - /// ... - /// return true; - /// } - /// - /// void CMyScreenSaver::Render() - /// { - /// ... - /// } - /// - /// - /// /*----------------------------------------------------------------------*/ - /// - /// class CMyAddon : public ::kodi::addon::CAddonBase - /// { - /// public: - /// CMyAddon() { } - /// ADDON_STATUS CreateInstance(int instanceType, - /// std::string instanceID, - /// KODI_HANDLE instance, - /// KODI_HANDLE& addonInstance) override; - /// }; - /// - /// /* If you use only one instance in your add-on, can be instanceType and - /// * instanceID ignored */ - /// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, - /// std::string instanceID, - /// KODI_HANDLE instance, - /// KODI_HANDLE& addonInstance) - /// { - /// if (instanceType == ADDON_INSTANCE_SCREENSAVER) - /// { - /// kodi::Log(ADDON_LOG_NOTICE, "Creating my Screensaver"); - /// addonInstance = new CMyScreenSaver(instance); - /// return ADDON_STATUS_OK; - /// } - /// else if (...) - /// { - /// ... - /// } - /// return ADDON_STATUS_UNKNOWN; - /// } - /// - /// ADDONCREATOR(CMyAddon) - /// ~~~~~~~~~~~~~ - /// - /// The destruction of the example class `CMyScreenSaver` is called from - /// Kodi's header. Manually deleting the add-on instance is not required. - /// - //---------------------------------------------------------------------------- - class ATTRIBUTE_HIDDEN CInstanceScreensaver : public IAddonInstance - { - public: - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver - /// @brief Screensaver class constructor - /// - /// Used by an add-on that only supports screensavers. - /// - CInstanceScreensaver() - : IAddonInstance(ADDON_INSTANCE_SCREENSAVER, GetKodiTypeVersion(ADDON_INSTANCE_SCREENSAVER)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstanceScreensaver: Creation of more as one in single instance way is not allowed!"); - - SetAddonStruct(CAddonBase::m_interface->firstKodiInstance); - CAddonBase::m_interface->globalSingleInstance = this; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver - /// @brief Screensaver class constructor used to support multiple instance - /// types - /// - /// @param[in] instance The instance value given to - /// `kodi::addon::CAddonBase::CreateInstance(...)`. - /// @param[in] kodiVersion [opt] Version used in Kodi for this instance, to - /// allow compatibility to older Kodi versions. - /// @note Recommended to set. - /// - /// @warning Only use `instance` from the CreateInstance call - /// - explicit CInstanceScreensaver(KODI_HANDLE instance, const std::string& kodiVersion = "") - : IAddonInstance(ADDON_INSTANCE_SCREENSAVER, - !kodiVersion.empty() ? kodiVersion - : GetKodiTypeVersion(ADDON_INSTANCE_SCREENSAVER)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstanceScreensaver: Creation of multiple together with single instance way is not allowed!"); - - SetAddonStruct(instance); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver - /// @brief Destructor - /// - ~CInstanceScreensaver() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver - /// @brief Used to notify the screensaver that it has been started - /// - /// @return true if the screensaver was started - /// successfully, false otherwise - /// - virtual bool Start() { return true; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver - /// @brief Used to inform the screensaver that the rendering control was - /// stopped - /// - virtual void Stop() {} - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver - /// @brief Used to indicate when the add-on should render - /// - virtual void Render() {} - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \defgroup cpp_kodi_addon_screensaver_CB Information functions - /// \ingroup cpp_kodi_addon_screensaver - /// @brief **To get info about the device, display and several other parts** - /// - //@{ - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver_CB - /// @brief Device that represents the display adapter - /// - /// @return A pointer to the device - /// - /// @note This is only available on **DirectX**, It us unused (`nullptr`) on - /// **OpenGL** - /// - inline void* Device() { return m_instanceData->props.device; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver_CB - /// @brief Returns the X position of the rendering window - /// - /// @return The X position, in pixels - /// - inline int X() { return m_instanceData->props.x; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver_CB - /// @brief Returns the Y position of the rendering window - /// - /// @return The Y position, in pixels - /// - inline int Y() { return m_instanceData->props.y; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver_CB - /// @brief Returns the width of the rendering window - /// - /// @return The width, in pixels - /// - inline int Width() { return m_instanceData->props.width; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver_CB - /// @brief Returns the height of the rendering window - /// - /// @return The height, in pixels - /// - inline int Height() { return m_instanceData->props.height; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver_CB - /// @brief Pixel aspect ratio (often abbreviated PAR) is a ratio that - /// describes how the width of a pixel compares to the height of that pixel. - /// - /// @return The pixel aspect ratio used by the display - /// - inline float PixelRatio() { return m_instanceData->props.pixelRatio; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver_CB - /// @brief Used to get the name of the add-on defined in `addon.xml` - /// - /// @return The add-on name - /// - inline std::string Name() { return m_instanceData->props.name; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver_CB - /// @brief Used to get the full path where the add-on is installed - /// - /// @return The add-on installation path - /// - inline std::string Presets() { return m_instanceData->props.presets; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_screensaver_CB - /// @brief Used to get the full path to the add-on's user profile - /// - /// @note The trailing folder (consisting of the add-on's ID) is not created - /// by default. If it is needed, you must call kodi::vfs::CreateDirectory() - /// to create the folder. - /// - /// @return Path to the user profile - /// - inline std::string Profile() { return m_instanceData->props.profile; } - //-------------------------------------------------------------------------- - //@} - - private: - void SetAddonStruct(KODI_HANDLE instance) - { - if (instance == nullptr) - throw std::logic_error("kodi::addon::CInstanceScreensaver: Creation with empty addon structure not allowed, table must be given from Kodi!"); - - m_instanceData = static_cast(instance); - m_instanceData->toAddon.addonInstance = this; - m_instanceData->toAddon.Start = ADDON_Start; - m_instanceData->toAddon.Stop = ADDON_Stop; - m_instanceData->toAddon.Render = ADDON_Render; - } - - inline static bool ADDON_Start(AddonInstance_Screensaver* instance) - { - instance->toAddon.addonInstance->m_renderHelper = kodi::gui::GetRenderHelper(); - return instance->toAddon.addonInstance->Start(); - } - - inline static void ADDON_Stop(AddonInstance_Screensaver* instance) - { - instance->toAddon.addonInstance->Stop(); - instance->toAddon.addonInstance->m_renderHelper = nullptr; - } - - inline static void ADDON_Render(AddonInstance_Screensaver* instance) - { - if (!instance->toAddon.addonInstance->m_renderHelper) - return; - instance->toAddon.addonInstance->m_renderHelper->Begin(); - instance->toAddon.addonInstance->Render(); - instance->toAddon.addonInstance->m_renderHelper->End(); - } - - /* - * Background render helper holds here and in addon base. - * In addon base also to have for the others, and stored here for the worst - * case where this class is independent from base and base becomes closed - * before. - * - * This is on Kodi with GL unused and the calls to there are empty (no work) - * On Kodi with Direct X where angle is present becomes this used. - */ - std::shared_ptr m_renderHelper; - AddonInstance_Screensaver* m_instanceData; - }; - -} /* namespace addon */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VFS.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VFS.h deleted file mode 100644 index efd5de2..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VFS.h +++ /dev/null @@ -1,1265 +0,0 @@ -/* - * Copyright (C) 2015-2018 Team Kodi - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../AddonBase.h" -#include "../Filesystem.h" - -#if !defined(_WIN32) -#include -#if !defined(__stat64) -#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) -#define __stat64 stat -#else -#define __stat64 stat64 -#endif -#endif -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //============================================================================ - /// @ingroup cpp_kodi_addon_vfs_Defs - /// @brief **VFS add-on URL data**\n - /// This class is used to inform the addon of the desired wanted connection. - /// - /// Used on mostly all addon functions to identify related target. - /// - struct VFSURL - { - /// @brief Desired URL of the file system to be edited - /// - /// This includes all available parts of the access and is structured as - /// follows: - /// - ``://``:```@```:``/``?`` - const char* url; - - /// @brief The associated domain name, which is optional and not available - /// in all cases. - const char* domain; - - /// @brief This includes the network address (e.g. `192.168.0.123`) or if - /// the addon refers to file packages the path to it - /// (e.g. `/home/by_me/MyPacket.rar`). - const char* hostname; - - /// @brief With this variable the desired path to a folder or file within - /// the hostname is given (e.g. `storage/videos/00001.ts`). - const char* filename; - - /// @brief [Networking port](https://en.wikipedia.org/wiki/Port_(computer_networking)) - /// to use for protocol. - unsigned int port; - - /// @brief Special options on opened URL, this can e.g. on RAR packages - /// `?flags=8&nextvalue=123` to inform about to not cache a read. - /// - /// Available options from Kodi: - /// | Value: | Description: - /// |-----------|------------------- - /// | flags=8 | Used on RAR packages so that no data is cached from the requested source. - /// | cache=no | Used on ZIP packages so that no data from the requested source is stored in the cache. However, this is currently not available from addons! - /// - /// In addition, other addons can use the URLs given by them to give options - /// that fit the respective VFS addon and allow special operations. - /// - /// @note This procedure is not yet standardized and is currently not - /// exactly available which are handed over. - const char* options; - - /// @brief Desired username. - const char* username; - - /// @brief Desired password. - const char* password; - - /// @brief The complete URL is passed on here, but the user name and - /// password are not shown and only appear to there as `USERNAME:PASSWORD`. - /// - /// As example `sftp://USERNAME:PASSWORD@192.168.178.123/storage/videos/00001.ts`. - const char* redacted; - - /// @brief The name which is taken as the basis by source and would be first - /// in folder view. - /// - /// As example on `sftp://dudu:isprivate@192.168.178.123/storage/videos/00001.ts` - /// becomes then `storage` used here. - const char* sharename; - - /// @brief Protocol name used on this stream, e.g. `sftp`. - const char* protocol; - }; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_vfs_Defs - /// @brief In/out value which is queried at @ref kodi::addon::CInstanceVFS::IoControl.\n - /// This declares the requested value on the addon, this gets or has to - /// transfer data depending on the value. - enum VFS_IOCTRL - { - /// @brief For cases where not supported control becomes asked. - /// - /// @note Should normally not given to addon. - VFS_IOCTRL_INVALID = 0, - - /// @brief @ref VFS_IOCTRL_NATIVE_DATA structure, containing what should be - /// passed to native ioctrl. - VFS_IOCTRL_NATIVE = 1, - - /// @brief To check seek is possible. - /// - //// Return 0 if known not to work, 1 if it should work on related calls. - VFS_IOCTRL_SEEK_POSSIBLE = 2, - - /// @brief @ref VFS_IOCTRL_CACHE_STATUS_DATA structure structure on related call - VFS_IOCTRL_CACHE_STATUS = 3, - - /// @brief Unsigned int with speed limit for caching in bytes per second - VFS_IOCTRL_CACHE_SETRATE = 4, - - /// @brief Enable/disable retry within the protocol handler (if supported) - VFS_IOCTRL_SET_RETRY = 16, - }; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_vfs_Defs - /// @brief Structure used in @ref kodi::addon::CInstanceVFS::IoControl - /// if question value for @ref VFS_IOCTRL_NATIVE is set\n - /// With this structure, data is transmitted to the Kodi addon. - /// - /// This corresponds to POSIX systems with regard to [ioctl](https://en.wikipedia.org/wiki/Ioctl) - /// data (emulated with Windows). - struct VFS_IOCTRL_NATIVE_DATA - { - unsigned long int request; - void* param; - }; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_vfs_Defs - /// @brief Structure used in @ref kodi::addon::CInstanceVFS::IoControl - /// if question value for @ref VFS_IOCTRL_CACHE_STATUS is set\n - /// This data is filled by the addon and returned to Kodi - struct VFS_IOCTRL_CACHE_STATUS_DATA - { - /// @brief Number of bytes cached forward of current position. - uint64_t forward; - - /// @brief Maximum number of bytes per second cache is allowed to fill. - unsigned int maxrate; - - /// @brief Average read rate from source file since last position change. - unsigned int currate; - - /// @brief Cache low speed condition detected? - bool lowspeed; - }; - //---------------------------------------------------------------------------- - - typedef struct VFSGetDirectoryCallbacks /* internal */ - { - bool (__cdecl* get_keyboard_input)(void* ctx, const char* heading, char** input, bool hidden_input); - void (__cdecl* set_error_dialog)(void* ctx, const char* heading, const char* line1, const char* line2, const char* line3); - void (__cdecl* require_authentication)(void* ctx, const char* url); - void* ctx; - } VFSGetDirectoryCallbacks; - - typedef struct AddonProps_VFSEntry /* internal */ - { - int dummy; - } AddonProps_VFSEntry; - - typedef struct AddonToKodiFuncTable_VFSEntry /* internal */ - { - KODI_HANDLE kodiInstance; - } AddonToKodiFuncTable_VFSEntry; - - struct AddonInstance_VFSEntry; - typedef struct KodiToAddonFuncTable_VFSEntry /* internal */ - { - KODI_HANDLE addonInstance; - - void*(__cdecl* open)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url); - void*(__cdecl* open_for_write)(const struct AddonInstance_VFSEntry* instance, - const struct VFSURL* url, - bool overwrite); - ssize_t(__cdecl* read)(const struct AddonInstance_VFSEntry* instance, - void* context, - void* buffer, - size_t buf_size); - ssize_t(__cdecl* write)(const struct AddonInstance_VFSEntry* instance, - void* context, - const void* buffer, - size_t buf_size); - int64_t(__cdecl* seek)(const struct AddonInstance_VFSEntry* instance, - void* context, - int64_t position, - int whence); - int(__cdecl* truncate)(const struct AddonInstance_VFSEntry* instance, - void* context, - int64_t size); - int64_t(__cdecl* get_length)(const struct AddonInstance_VFSEntry* instance, void* context); - int64_t(__cdecl* get_position)(const struct AddonInstance_VFSEntry* instance, void* context); - int(__cdecl* get_chunk_size)(const struct AddonInstance_VFSEntry* instance, void* context); - int(__cdecl* io_control)(const struct AddonInstance_VFSEntry* instance, - void* context, - enum VFS_IOCTRL request, - void* param); - int(__cdecl* stat)(const struct AddonInstance_VFSEntry* instance, - const struct VFSURL* url, - struct __stat64* buffer); - bool(__cdecl* close)(const struct AddonInstance_VFSEntry* instance, void* context); - bool(__cdecl* exists)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url); - void(__cdecl* clear_out_idle)(const struct AddonInstance_VFSEntry* instance); - void(__cdecl* disconnect_all)(const struct AddonInstance_VFSEntry* instance); - bool(__cdecl* delete_it)(const struct AddonInstance_VFSEntry* instance, - const struct VFSURL* url); - bool(__cdecl* rename)(const struct AddonInstance_VFSEntry* instance, - const struct VFSURL* url, - const struct VFSURL* url2); - bool(__cdecl* directory_exists)(const struct AddonInstance_VFSEntry* instance, - const struct VFSURL* url); - bool(__cdecl* remove_directory)(const struct AddonInstance_VFSEntry* instance, - const struct VFSURL* url); - bool(__cdecl* create_directory)(const struct AddonInstance_VFSEntry* instance, - const struct VFSURL* url); - bool(__cdecl* get_directory)(const struct AddonInstance_VFSEntry* instance, - const struct VFSURL* url, - struct VFSDirEntry** entries, - int* num_entries, - VFSGetDirectoryCallbacks* callbacks); - bool(__cdecl* contains_files)(const struct AddonInstance_VFSEntry* instance, - const struct VFSURL* url, - struct VFSDirEntry** entries, - int* num_entries, - char* rootpath); - void(__cdecl* free_directory)(const struct AddonInstance_VFSEntry* instance, - struct VFSDirEntry* entries, - int num_entries); - } KodiToAddonFuncTable_VFSEntry; - - typedef struct AddonInstance_VFSEntry /* internal */ - { - AddonProps_VFSEntry* props; - AddonToKodiFuncTable_VFSEntry* toKodi; - KodiToAddonFuncTable_VFSEntry* toAddon; - } AddonInstance_VFSEntry; - -#ifdef __cplusplus -} /* extern "C" */ - -namespace kodi -{ -namespace addon -{ - -//############################################################################## -/// @defgroup cpp_kodi_addon_vfs_Defs Definitions, structures and enumerators -/// \ingroup cpp_kodi_addon_vfs -/// @brief **VFS add-on general variables** -/// -/// Used to exchange the available options between Kodi and addon. -/// -/// - -//============================================================================== -/// -/// \addtogroup cpp_kodi_addon_vfs -/// @brief \cpp_class{ kodi::addon::CInstanceVFS } -/// **Virtual Filesystem (VFS) add-on instance** -/// -/// This instance type is used to allow Kodi various additional file system -/// types. Be it a special file system, a compressed package or a system -/// available over the network, everything is possible with it. -/// -/// This usage can be requested under various conditions, for example explicitly -/// by another addon, by a Mimetype protocol defined in `addon.xml` or supported -/// file extensions. -/// -/// Include the header @ref VFS.h "#include " -/// to use this class. -/// -/// ---------------------------------------------------------------------------- -/// -/// Here is an example of what the `addon.xml.in` would look like for an VFS addon: -/// -/// ~~~~~~~~~~~~~{.xml} -/// -/// -/// @ADDON_DEPENDS@ -/// -/// -/// My VFS addon summary -/// My VFS description -/// @PLATFORM@ -/// -/// -/// ~~~~~~~~~~~~~ -/// -/// @note Regarding boolean values with "false", these can also be omitted, -/// since this would be the default. -/// -/// -/// ### Standard values that can be declared for processing in `addon.xml`. -/// -/// These values are used by Kodi to identify associated streams and file -/// extensions and then to select the associated addon. -/// -/// \table_start -/// \table_h3{ Labels, Type, Description } -/// \table_row3{ `point`, -/// \anchor cpp_kodi_addon_vfs_point -/// string, -/// The identification of the addon instance to VFS is mandatory `kodi.vfs`. -/// In addition\, the instance declared in the first `` is also the main type of addon. -/// } -/// \table_row3{ `defaultPort`, -/// \anchor cpp_kodi_addon_vfs_defaultPort -/// integer, -/// Default [networking port](https://en.wikipedia.org/wiki/Port_(computer_networking)) -/// to use for protocol. -/// } -/// \table_row3{ `directories`, -/// \anchor cpp_kodi_addon_vfs_directories -/// boolean, -/// VFS entry can list directories. -/// } -/// \table_row3{ `extensions`, -/// \anchor cpp_kodi_addon_vfs_extensions -/// string, -/// Extensions for VFS entry.\n -/// It is possible to declare several using `|`\, e.g. `.abc|.def|.ghi`. -/// } -/// \table_row3{ `encodedhostname`, -/// \anchor cpp_kodi_addon_vfs_encodedhostname -/// boolean, -/// URL protocol from add-ons use encoded hostnames. -/// } -/// \table_row3{ `filedirectories`, -/// \anchor cpp_kodi_addon_vfs_filedirectories -/// boolean, -/// VFS entry contains file directories. -/// } -/// \table_row3{ `files`, -/// \anchor cpp_kodi_addon_vfs_directories -/// boolean, -/// Set to declare that VFS provides files. -/// } -/// \table_row3{ `protocols`, -/// \anchor cpp_kodi_addon_vfs_protocols -/// boolean, -/// Protocols for VFS entry.\n -/// It is possible to declare several using `|`\, e.g. `myprot1|myprot2`.\n -/// @note This field also used to show on GUI\, see `supportBrowsing` below about *2:. -/// When used there\, however\, only a **single** protocol is possible! -/// } -/// \table_row3{ `supportWrite`, -/// \anchor cpp_kodi_addon_vfs_supportWrite -/// boolean, -/// Protocol supports write operations. -/// } -/// \table_row3{ `zeroconf`, -/// \anchor cpp_kodi_addon_vfs_zeroconf -/// string, -/// [Zero conf](https://en.wikipedia.org/wiki/Zero-configuration_networking) announce string for VFS protocol. -/// } -/// \table_row3{ `library_@PLATFORM@`, -/// \anchor cpp_kodi_addon_vfs_library -/// string, -/// The runtime library used for the addon. This is usually declared by `cmake` and correctly displayed in the translated `addon.xml`. -/// } -/// \table_end -/// -/// -/// ### User selectable parts of the addon. -/// -/// The following table describes the values that can be defined by `addon.xml` -/// and which part they relate to for user input. -/// -/// \table_start -/// \table_h3{ Labels, Type, Description } -/// \table_row3{ `supportBrowsing`, -/// \anchor cpp_kodi_addon_vfs_protocol_supportBrowsing -/// boolean, -/// Protocol supports server browsing. Used to open related sources by users in the window.\n\n -/// | Associated places in Kodi: | -/// | :---- | -/// | \image html cpp_kodi_addon_vfs_protocol_1.png | -///
-/// *1: The entry in the menu represented by this option corresponds to the text given with `label`. -/// When the button is pressed\, @ref CInstanceVFS::GetDirectory is called on the add-on to get its content.\n -/// *2: Protocol name of the stream defined with `protocols` in xml.\n -/// @remark See also `supportDialog` about *3:. -/// } -/// \table_row3{ `supportDialog`, -/// \anchor cpp_kodi_addon_vfs_protocol_supportDialog -/// boolean, -/// To point out that Kodi assigns a dialog to this VFS in order to compare it with other values e.g. query supportPassword in it.\n -/// This will be available when adding sources in Kodi under "Add network location...".\n\n -/// | Associated places in Kodi: | -/// | :---- | -/// | \image html cpp_kodi_addon_vfs_protocol_2.png | -///
-/// *1: Field for selecting the VFS handler\, the addon will be available if `supportDialog` is set to `true`.\n -/// *2: To set the associated server address. **Note:** *This field is always activated and cannot be changed by the addon.*\n -/// *3: If `supportBrowsing` is set to `true`\, the button for opening a file selection dialog is given here too\, as in the file window.\n -/// *4: This field is available if `supportPath` is set to `true`.\n -/// *5: To edit the connection port. This field is available if `supportPort` is set to `true`.\n -/// *6: This sets the required username and is available when `supportUsername` is set to `true`.\n -/// *7: This sets the required password and is available when `supportPassword` is set to `true`. -/// } -/// \table_row3{ `supportPath`, -/// \anchor cpp_kodi_addon_vfs_protocol_supportPath -/// boolean, -/// Protocol has path in addition to server name (see `supportDialog` about *4:). -/// } -/// \table_row3{ `supportPort`, -/// \anchor cpp_kodi_addon_vfs_protocol_supportPort -/// boolean, -/// Protocol supports port customization (see `supportDialog` about *5:). -/// } -/// \table_row3{ `supportUsername`, -/// \anchor cpp_kodi_addon_vfs_protocol_supportUsername -/// boolean, -/// Protocol uses logins (see `supportDialog` about *6:). -/// } -/// \table_row3{ `supportPassword`, -/// \anchor cpp_kodi_addon_vfs_protocol_supportPassword -/// boolean, -/// Protocol supports passwords (see `supportDialog` about *7:). -/// } -/// \table_row3{ `protocols`, -/// \anchor cpp_kodi_addon_vfs_protocol_protocols -/// string, -/// Protocols for VFS entry. -/// @note This field is not editable and only used on GUI to show his name\, see `supportBrowsing` about *2: -/// } -/// \table_row3{ `label`, -/// \anchor cpp_kodi_addon_vfs_protocol_label -/// integer, -/// The text identification number used in Kodi for display in the menu at `supportDialog` -/// as a selection option and at `supportBrowsing` (see his image reference *1) as a menu entry.\n -/// This can be a text identifier in Kodi or from addon.\n -/// @remark For addon within 30000-30999 or 32000-32999. -/// } -/// \table_end -/// -/// @remark For more detailed description of the `addon.xml`, see also https://kodi.wiki/view/Addon.xml. -/// -/// -/// -------------------------------------------------------------------------- -/// -/// -/// **Example:** -/// -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// class CMyVFS : public kodi::addon::CInstanceVFS -/// { -/// public: -/// CMyVFS(KODI_HANDLE instance, const std::string& kodiVersion); -/// -/// // Add all your required functions, the most CInstanceVFS functions of -/// // must be included to have addon working correctly. -/// ... -/// }; -/// -/// CMyVFS::CMyVFS(KODI_HANDLE instance, const std::string& kodiVersion) -/// : CInstanceVFS(instance, kodiVersion) -/// { -/// ... -/// } -/// -/// ... -/// -/// /*----------------------------------------------------------------------*/ -/// -/// class CMyAddon : public kodi::addon::CAddonBase -/// { -/// public: -/// CMyAddon() { } -/// ADDON_STATUS CreateInstance(int instanceType, -/// const std::string& instanceID, -/// KODI_HANDLE instance, -/// const std::string& version, -/// KODI_HANDLE& addonInstance) override; -/// }; -/// -/// // If you use only one instance in your add-on, can be instanceType and -/// // instanceID ignored -/// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, -/// const std::string& instanceID, -/// KODI_HANDLE instance, -/// const std::string& version, -/// KODI_HANDLE& addonInstance) -/// { -/// if (instanceType == ADDON_INSTANCE_VFS) -/// { -/// kodi::Log(ADDON_LOG_NOTICE, "Creating my VFS instance"); -/// addonInstance = new CMyVFS(instance, version); -/// return ADDON_STATUS_OK; -/// } -/// else if (...) -/// { -/// ... -/// } -/// return ADDON_STATUS_UNKNOWN; -/// } -/// -/// ADDONCREATOR(CMyAddon) -/// ~~~~~~~~~~~~~ -/// -/// The destruction of the example class `CMyVFS` is called from -/// Kodi's header. Manually deleting the add-on instance is not required. -/// -//---------------------------------------------------------------------------- -class ATTRIBUTE_HIDDEN CInstanceVFS : public IAddonInstance -{ -public: - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs - /// @brief VFS class constructor used to support multiple instance - /// types - /// - /// @param[in] instance The instance value given to - /// `kodi::addon::CAddonBase::CreateInstance(...)`. - /// @param[in] kodiVersion [opt] given from Kodi by @ref CAddonBase::CreateInstance - /// to identify his instance API version - /// - /// @note Instance path as a single is not supported by this type. It must - /// ensure that it can be called up several times. - /// - /// @warning Only use `instance` from the @ref CAddonBase::CreateInstance or - /// @ref CAddonBase::CreateInstance call. - /// - explicit CInstanceVFS(KODI_HANDLE instance, const std::string& kodiVersion = "") - : IAddonInstance(ADDON_INSTANCE_VFS, - !kodiVersion.empty() ? kodiVersion : GetKodiTypeVersion(ADDON_INSTANCE_VFS)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstanceVFS: Creation of multiple together with single " - "instance way is not allowed!"); - - SetAddonStruct(instance); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs - /// @brief Destructor - /// - ~CInstanceVFS() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @defgroup cpp_kodi_addon_vfs_general 1. General access functions - /// @ingroup cpp_kodi_addon_vfs - /// @brief **General access functions** - /// - /// This functions which are intended for getting folders, editing storage - /// locations and file system queries. - /// - - //========================================================================== - /// - /// @defgroup cpp_kodi_addon_vfs_filecontrol 2. File editing functions - /// @ingroup cpp_kodi_addon_vfs - /// @brief **File editing functions.** - /// - /// This value represents the addon-side handlers and to be able to identify - /// his own parts in the event of further access. - /// - - //@{ - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_filecontrol - /// @brief Open a file for input - /// - /// @param[in] url The URL of the file - /// @return Context for the opened file - virtual void* Open(const VFSURL& url) { return nullptr; } - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_filecontrol - /// @brief Open a file for output - /// - /// @param[in] url The URL of the file - /// @param[in] overWrite Whether or not to overwrite an existing file - /// @return Context for the opened file - /// - virtual void* OpenForWrite(const VFSURL& url, bool overWrite) { return nullptr; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_filecontrol - /// @brief Close a file - /// - /// @param[in] context The context of the file - /// @return True on success, false on failure - /// - virtual bool Close(void* context) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_filecontrol - /// @brief Read from a file - /// - /// @param[in] context The context of the file - /// @param[out] buffer The buffer to read data into - /// @param[in] uiBufSize Number of bytes to read - /// @return Number of bytes read - /// - virtual ssize_t Read(void* context, void* buffer, size_t uiBufSize) { return -1; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_filecontrol - /// @brief Write to a file - /// - /// @param[in] context The context of the file - /// @param[in] buffer The buffer to read data from - /// @param[in] uiBufSize Number of bytes to write - /// @return Number of bytes written - /// - virtual ssize_t Write(void* context, const void* buffer, size_t uiBufSize) { return -1; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_filecontrol - /// @brief Seek in a file - /// - /// @param[in] context The context of the file - /// @param[in] position The position to seek to - /// @param[in] whence Position in file 'position' is relative to (SEEK_CUR, SEEK_SET, SEEK_END) - /// @return Offset in file after seek - /// - virtual int64_t Seek(void* context, int64_t position, int whence) { return -1; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_filecontrol - /// @brief Truncate a file - /// - /// @param[in] context The context of the file - /// @param[in] size The size to truncate the file to - /// @return 0 on success, -1 on error - /// - virtual int Truncate(void* context, int64_t size) { return -1; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_filecontrol - /// @brief Get total size of a file - /// - /// @param[in] context The context of the file - /// @return Total file size - /// - virtual int64_t GetLength(void* context) { return 0; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_filecontrol - /// @brief Get current position in a file - /// - /// @param[in] context The context of the file - /// @return Current position - /// - virtual int64_t GetPosition(void* context) { return 0; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_filecontrol - /// @brief Get chunk size of a file - /// - /// @param[in] context The context of the file - /// @return Chunk size - /// - virtual int GetChunkSize(void* context) { return 1; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_filecontrol - /// @brief Perform an IO-control on the file - /// - /// @param[in] context The context of the file - /// @param[in] request The requested IO-control - /// @param[in] param Parameter attached to the IO-control - /// @return -1 on error, >= 0 on success - /// - virtual int IoControl(void* context, VFS_IOCTRL request, void* param) { return -1; } - //-------------------------------------------------------------------------- - //@} - - //@{ - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_general - /// @brief Stat a file - /// - /// @param[in] url The URL of the file - /// @param[in] buffer The buffer to store results in - /// @return -1 on error, 0 otherwise - /// - virtual int Stat(const VFSURL& url, struct __stat64* buffer) { return 0; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_general - /// @brief Check for file existence - /// - /// @param[in] url The URL of the file - /// @return True if file exists, false otherwise - /// - virtual bool Exists(const VFSURL& url) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_general - /// @brief Clear out any idle connections - /// - virtual void ClearOutIdle() {} - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_general - /// @brief Disconnect all connections - /// - virtual void DisconnectAll() {} - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_general - /// @brief Delete a file - /// - /// @param[in] url The URL of the file - /// @return True if deletion was successful, false otherwise - /// - virtual bool Delete(const VFSURL& url) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_general - /// @brief Rename a file - /// - /// @param[in] url The URL of the source file - /// @param[in] url2 The URL of the destination file - /// @return True if deletion was successful, false otherwise - /// - virtual bool Rename(const VFSURL& url, const VFSURL& url2) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_general - /// @brief Check for directory existence - /// - /// @param[in] url The URL of the file - /// @return True if directory exists, false otherwise - /// - virtual bool DirectoryExists(const VFSURL& url) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_general - /// @brief Remove a directory - /// - /// @param[in] url The URL of the directory - /// @return True if removal was successful, false otherwise - /// - virtual bool RemoveDirectory(const VFSURL& url) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_general - /// @brief Create a directory - /// - /// @param[in] url The URL of the file - /// @return True if creation was successful, false otherwise - /// - virtual bool CreateDirectory(const VFSURL& url) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @defgroup cpp_kodi_addon_vfs_general_cb_GetDirectory **Callbacks GetDirectory()** - /// @ingroup cpp_kodi_addon_vfs_general - /// @brief Callback functions on GetDirectory() - /// - /// This functions becomes available during call of GetDirectory() from - /// Kodi. - /// - /// If GetDirectory() returns false becomes the parts from here used on - /// next call of the function. - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// - /// #include - /// - /// ... - /// - /// bool CMyVFS::GetDirectory(const VFSURL& url, std::vector& items, CVFSCallbacks callbacks) - /// { - /// std::string neededString; - /// callbacks.GetKeyboardInput("Test", neededString, true); - /// if (neededString.empty()) - /// return false; - /// - /// // Do the work - /// ... - /// return true; - /// } - /// ~~~~~~~~~~~~~ - /// - class CVFSCallbacks - { - public: - /// @ingroup cpp_kodi_addon_vfs_general_cb_GetDirectory - /// @brief Require keyboard input - /// - /// Becomes called if GetDirectory() returns false and GetDirectory() - /// becomes after entry called again. - /// - /// @param[in] heading The heading of the keyboard dialog - /// @param[out] input The resulting string. Returns string after - /// second call! - /// @param[in] hiddenInput To show input only as "*" on dialog - /// @return True if input was received, false otherwise - /// - bool GetKeyboardInput(const std::string& heading, std::string& input, bool hiddenInput = false) - { - char* cInput = nullptr; - bool ret = m_cb->get_keyboard_input(m_cb->ctx, heading.c_str(), &cInput, hiddenInput); - if (cInput) - { - input = cInput; - ::kodi::addon::CAddonBase::m_interface->toKodi->free_string( - ::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, cInput); - } - return ret; - } - - /// @ingroup cpp_kodi_addon_vfs_general_cb_GetDirectory - /// @brief Display an error dialog - /// - /// @param[in] heading The heading of the error dialog - /// @param[in] line1 The first line of the error dialog - /// @param[in] line2 [opt] The second line of the error dialog - /// @param[in] line3 [opt] The third line of the error dialog - /// - void SetErrorDialog(const std::string& heading, - const std::string& line1, - const std::string& line2 = "", - const std::string& line3 = "") - { - m_cb->set_error_dialog(m_cb->ctx, heading.c_str(), line1.c_str(), line2.c_str(), - line3.c_str()); - } - - /// @ingroup cpp_kodi_addon_vfs_general_cb_GetDirectory - /// @brief Prompt the user for authentication of a URL - /// - /// @param[in] url The URL - void RequireAuthentication(const std::string& url) - { - m_cb->require_authentication(m_cb->ctx, url.c_str()); - } - - explicit CVFSCallbacks(const VFSGetDirectoryCallbacks* cb) : m_cb(cb) {} - - private: - const VFSGetDirectoryCallbacks* m_cb; - }; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_general - /// @brief List a directory - /// - /// @param[in] url The URL of the directory - /// @param[out] entries The entries in the directory, see - /// @ref cpp_kodi_vfs_CDirEntry "kodi::vfs::CDirEntry" - /// about his content - /// @param[in] callbacks A callback structure - /// @return Context for the directory listing - /// - /// - /// -------------------------------------------------------------------------- - /// - /// ### Callbacks: - /// @copydetails cpp_kodi_addon_vfs_general_cb_GetDirectory - /// - /// **Available callback functions** - /// | Function: | Description - /// |--|-- - /// | CVFSCallbacks::GetKeyboardInput | @copybrief CVFSCallbacks::GetKeyboardInput @copydetails CVFSCallbacks::GetKeyboardInput - /// | CVFSCallbacks::SetErrorDialog | @copybrief CVFSCallbacks::SetErrorDialog @copydetails CVFSCallbacks::SetErrorDialog - /// | CVFSCallbacks::RequireAuthentication | @copybrief CVFSCallbacks::RequireAuthentication @copydetails CVFSCallbacks::RequireAuthentication - /// - virtual bool GetDirectory(const VFSURL& url, - std::vector& entries, - CVFSCallbacks callbacks) - { - return false; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_vfs_general - /// @brief Check if file should be presented as a directory (multiple streams) - /// - /// @param[in] url The URL of the file - /// @param[out] entries The entries in the directory, see - /// @ref cpp_kodi_vfs_CDirEntry "kodi::vfs::CDirEntry" - /// about his content - /// @param[out] rootPath Path to root directory if multiple entries - /// @return Context for the directory listing - /// - virtual bool ContainsFiles(const VFSURL& url, - std::vector& entries, - std::string& rootPath) - { - return false; - } - //-------------------------------------------------------------------------- - //@} - -private: - void SetAddonStruct(KODI_HANDLE instance) - { - if (instance == nullptr) - throw std::logic_error("kodi::addon::CInstanceVFS: Creation with empty addon structure not " - "allowed, table must be given from Kodi!"); - - m_instanceData = static_cast(instance); - m_instanceData->toAddon->addonInstance = this; - m_instanceData->toAddon->open = ADDON_Open; - m_instanceData->toAddon->open_for_write = ADDON_OpenForWrite; - m_instanceData->toAddon->read = ADDON_Read; - m_instanceData->toAddon->write = ADDON_Write; - m_instanceData->toAddon->seek = ADDON_Seek; - m_instanceData->toAddon->truncate = ADDON_Truncate; - m_instanceData->toAddon->get_length = ADDON_GetLength; - m_instanceData->toAddon->get_position = ADDON_GetPosition; - m_instanceData->toAddon->get_chunk_size = ADDON_GetChunkSize; - m_instanceData->toAddon->io_control = ADDON_IoControl; - m_instanceData->toAddon->stat = ADDON_Stat; - m_instanceData->toAddon->close = ADDON_Close; - m_instanceData->toAddon->exists = ADDON_Exists; - m_instanceData->toAddon->clear_out_idle = ADDON_ClearOutIdle; - m_instanceData->toAddon->disconnect_all = ADDON_DisconnectAll; - m_instanceData->toAddon->delete_it = ADDON_Delete; - m_instanceData->toAddon->rename = ADDON_Rename; - m_instanceData->toAddon->directory_exists = ADDON_DirectoryExists; - m_instanceData->toAddon->remove_directory = ADDON_RemoveDirectory; - m_instanceData->toAddon->create_directory = ADDON_CreateDirectory; - m_instanceData->toAddon->get_directory = ADDON_GetDirectory; - m_instanceData->toAddon->free_directory = ADDON_FreeDirectory; - m_instanceData->toAddon->contains_files = ADDON_ContainsFiles; - } - - inline static void* ADDON_Open(const AddonInstance_VFSEntry* instance, const VFSURL* url) - { - return static_cast(instance->toAddon->addonInstance)->Open(*url); - } - - inline static void* ADDON_OpenForWrite(const AddonInstance_VFSEntry* instance, - const VFSURL* url, - bool overWrite) - { - return static_cast(instance->toAddon->addonInstance) - ->OpenForWrite(*url, overWrite); - } - - inline static ssize_t ADDON_Read(const AddonInstance_VFSEntry* instance, - void* context, - void* buffer, - size_t uiBufSize) - { - return static_cast(instance->toAddon->addonInstance) - ->Read(context, buffer, uiBufSize); - } - - inline static ssize_t ADDON_Write(const AddonInstance_VFSEntry* instance, - void* context, - const void* buffer, - size_t uiBufSize) - { - return static_cast(instance->toAddon->addonInstance) - ->Write(context, buffer, uiBufSize); - } - - inline static int64_t ADDON_Seek(const AddonInstance_VFSEntry* instance, - void* context, - int64_t position, - int whence) - { - return static_cast(instance->toAddon->addonInstance) - ->Seek(context, position, whence); - } - - inline static int ADDON_Truncate(const AddonInstance_VFSEntry* instance, - void* context, - int64_t size) - { - return static_cast(instance->toAddon->addonInstance)->Truncate(context, size); - } - - inline static int64_t ADDON_GetLength(const AddonInstance_VFSEntry* instance, void* context) - { - return static_cast(instance->toAddon->addonInstance)->GetLength(context); - } - - inline static int64_t ADDON_GetPosition(const AddonInstance_VFSEntry* instance, void* context) - { - return static_cast(instance->toAddon->addonInstance)->GetPosition(context); - } - - inline static int ADDON_GetChunkSize(const AddonInstance_VFSEntry* instance, void* context) - { - return static_cast(instance->toAddon->addonInstance)->GetChunkSize(context); - } - - inline static int ADDON_IoControl(const AddonInstance_VFSEntry* instance, - void* context, - enum VFS_IOCTRL request, - void* param) - { - return static_cast(instance->toAddon->addonInstance) - ->IoControl(context, request, param); - } - - inline static int ADDON_Stat(const AddonInstance_VFSEntry* instance, - const VFSURL* url, - struct __stat64* buffer) - { - return static_cast(instance->toAddon->addonInstance)->Stat(*url, buffer); - } - - inline static bool ADDON_Close(const AddonInstance_VFSEntry* instance, void* context) - { - return static_cast(instance->toAddon->addonInstance)->Close(context); - } - - inline static bool ADDON_Exists(const AddonInstance_VFSEntry* instance, const VFSURL* url) - { - return static_cast(instance->toAddon->addonInstance)->Exists(*url); - } - - inline static void ADDON_ClearOutIdle(const AddonInstance_VFSEntry* instance) - { - return static_cast(instance->toAddon->addonInstance)->ClearOutIdle(); - } - - inline static void ADDON_DisconnectAll(const AddonInstance_VFSEntry* instance) - { - return static_cast(instance->toAddon->addonInstance)->DisconnectAll(); - } - - inline static bool ADDON_Delete(const AddonInstance_VFSEntry* instance, const VFSURL* url) - { - return static_cast(instance->toAddon->addonInstance)->Delete(*url); - } - - inline static bool ADDON_Rename(const AddonInstance_VFSEntry* instance, - const VFSURL* url, - const VFSURL* url2) - { - return static_cast(instance->toAddon->addonInstance)->Rename(*url, *url2); - } - - inline static bool ADDON_DirectoryExists(const AddonInstance_VFSEntry* instance, - const VFSURL* url) - { - return static_cast(instance->toAddon->addonInstance)->DirectoryExists(*url); - } - - inline static bool ADDON_RemoveDirectory(const AddonInstance_VFSEntry* instance, - const VFSURL* url) - { - return static_cast(instance->toAddon->addonInstance)->RemoveDirectory(*url); - } - - inline static bool ADDON_CreateDirectory(const AddonInstance_VFSEntry* instance, - const VFSURL* url) - { - return static_cast(instance->toAddon->addonInstance)->CreateDirectory(*url); - } - - inline static bool ADDON_GetDirectory(const AddonInstance_VFSEntry* instance, - const VFSURL* url, - VFSDirEntry** retEntries, - int* num_entries, - VFSGetDirectoryCallbacks* callbacks) - { - std::vector addonEntries; - bool ret = static_cast(instance->toAddon->addonInstance) - ->GetDirectory(*url, addonEntries, CVFSCallbacks(callbacks)); - if (ret) - { - VFSDirEntry* entries = - static_cast(malloc(sizeof(VFSDirEntry) * addonEntries.size())); - for (unsigned int i = 0; i < addonEntries.size(); ++i) - { - entries[i].label = strdup(addonEntries[i].Label().c_str()); - entries[i].title = strdup(addonEntries[i].Title().c_str()); - entries[i].path = strdup(addonEntries[i].Path().c_str()); - entries[i].folder = addonEntries[i].IsFolder(); - entries[i].size = addonEntries[i].Size(); - entries[i].date_time = addonEntries[i].DateTime(); - - entries[i].num_props = 0; - const std::map& props = addonEntries[i].GetProperties(); - if (!props.empty()) - { - entries[i].properties = - static_cast(malloc(sizeof(VFSProperty) * props.size())); - for (const auto& prop : props) - { - entries[i].properties[entries[i].num_props].name = strdup(prop.first.c_str()); - entries[i].properties[entries[i].num_props].val = strdup(prop.second.c_str()); - ++entries[i].num_props; - } - } - else - entries[i].properties = nullptr; - } - *retEntries = entries; - *num_entries = static_cast(addonEntries.size()); - } - return ret; - } - - inline static void ADDON_FreeDirectory(const AddonInstance_VFSEntry* instance, - VFSDirEntry* entries, - int num_entries) - { - for (int i = 0; i < num_entries; ++i) - { - if (entries[i].properties) - { - for (unsigned int j = 0; j < entries[i].num_props; ++j) - { - free(entries[i].properties[j].name); - free(entries[i].properties[j].val); - } - free(entries[i].properties); - } - free(entries[i].label); - free(entries[i].title); - free(entries[i].path); - } - free(entries); - } - - inline static bool ADDON_ContainsFiles(const AddonInstance_VFSEntry* instance, - const VFSURL* url, - VFSDirEntry** retEntries, - int* num_entries, - char* rootpath) - { - std::string cppRootPath; - std::vector addonEntries; - bool ret = static_cast(instance->toAddon->addonInstance) - ->ContainsFiles(*url, addonEntries, cppRootPath); - if (ret) - { - strncpy(rootpath, cppRootPath.c_str(), ADDON_STANDARD_STRING_LENGTH); - - VFSDirEntry* entries = - static_cast(malloc(sizeof(VFSDirEntry) * addonEntries.size())); - for (size_t i = 0; i < addonEntries.size(); ++i) - { - entries[i].label = strdup(addonEntries[i].Label().c_str()); - entries[i].title = strdup(addonEntries[i].Title().c_str()); - entries[i].path = strdup(addonEntries[i].Path().c_str()); - entries[i].folder = addonEntries[i].IsFolder(); - entries[i].size = addonEntries[i].Size(); - entries[i].date_time = addonEntries[i].DateTime(); - - entries[i].num_props = 0; - const std::map& props = addonEntries[i].GetProperties(); - if (!props.empty()) - { - entries[i].properties = - static_cast(malloc(sizeof(VFSProperty) * props.size())); - for (const auto& prop : props) - { - entries[i].properties[entries[i].num_props].name = strdup(prop.first.c_str()); - entries[i].properties[entries[i].num_props].val = strdup(prop.second.c_str()); - ++entries[i].num_props; - } - } - else - entries[i].properties = nullptr; - } - *retEntries = entries; - *num_entries = static_cast(addonEntries.size()); - } - return ret; - } - - AddonInstance_VFSEntry* m_instanceData; -}; - -} /* namespace addon */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VideoCodec.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VideoCodec.h deleted file mode 100644 index 54246f0..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/VideoCodec.h +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2017-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../AddonBase.h" -#include "../StreamCrypto.h" -#include "../StreamCodec.h" - -#ifdef BUILD_KODI_ADDON -#include "../DemuxPacket.h" -#else -#include "cores/VideoPlayer/Interface/Addon/DemuxPacket.h" -#endif - -namespace kodi { namespace addon { class CInstanceVideoCodec; } } - -extern "C" -{ - enum VIDEOCODEC_FORMAT - { - UnknownVideoFormat = 0, - VideoFormatYV12, - VideoFormatI420, - MaxVideoFormats - }; - - - struct VIDEOCODEC_INITDATA - { - enum Codec { - CodecUnknown = 0, - CodecVp8, - CodecH264, - CodecVp9 - } codec; - - STREAMCODEC_PROFILE codecProfile; - - //UnknownVideoFormat is terminator - VIDEOCODEC_FORMAT *videoFormats; - - uint32_t width, height; - - const uint8_t *extraData; - unsigned int extraDataSize; - - CRYPTO_INFO cryptoInfo; - }; - - struct VIDEOCODEC_PICTURE - { - enum VideoPlane { - YPlane = 0, - UPlane, - VPlane, - MaxPlanes = 3, - }; - - enum Flags : uint32_t { - FLAG_DROP, - FLAG_DRAIN - }; - - VIDEOCODEC_FORMAT videoFormat; - uint32_t flags; - - uint32_t width, height; - - uint8_t *decodedData; - size_t decodedDataSize; - - uint32_t planeOffsets[VideoPlane::MaxPlanes]; - uint32_t stride[VideoPlane::MaxPlanes]; - - int64_t pts; - - KODI_HANDLE buffer; //< will be passed in release_frame_buffer - }; - - enum VIDEOCODEC_RETVAL - { - VC_NONE = 0, //< noop - VC_ERROR, //< an error occurred, no other messages will be returned - VC_BUFFER, //< the decoder needs more data - VC_PICTURE, //< the decoder got a picture - VC_EOF, //< the decoder signals EOF - }; - - // this are properties given to the addon on create - // at this time we have no parameters for the addon - typedef struct AddonProps_VideoCodec - { - int dummy; - } AddonProps_VideoCodec; - - struct AddonInstance_VideoCodec; - typedef struct KodiToAddonFuncTable_VideoCodec - { - kodi::addon::CInstanceVideoCodec* addonInstance; - - //! \brief Opens a codec - bool (__cdecl* open) (const AddonInstance_VideoCodec* instance, VIDEOCODEC_INITDATA *initData); - - //! \brief Reconfigures a codec - bool (__cdecl* reconfigure) (const AddonInstance_VideoCodec* instance, VIDEOCODEC_INITDATA *initData); - - //! \brief Feed codec if requested from GetPicture() (return VC_BUFFER) - bool (__cdecl* add_data) (const AddonInstance_VideoCodec* instance, const DemuxPacket *packet); - - //! \brief Get a decoded picture / request new data - VIDEOCODEC_RETVAL (__cdecl* get_picture) (const AddonInstance_VideoCodec* instance, VIDEOCODEC_PICTURE *picture); - - //! \brief Get the name of this video decoder - const char *(__cdecl* get_name) (const AddonInstance_VideoCodec* instance); - - //! \brief Reset the codec - void (__cdecl* reset)(const AddonInstance_VideoCodec* instance); - } KodiToAddonFuncTable_VideoCodec; - - typedef struct AddonToKodiFuncTable_VideoCodec - { - KODI_HANDLE kodiInstance; - bool(*get_frame_buffer)(void* kodiInstance, VIDEOCODEC_PICTURE *picture); - void(*release_frame_buffer)(void* kodiInstance, void *buffer); - } AddonToKodiFuncTable_VideoCodec; - - typedef struct AddonInstance_VideoCodec - { - AddonProps_VideoCodec props; - AddonToKodiFuncTable_VideoCodec toKodi; - KodiToAddonFuncTable_VideoCodec toAddon; - } AddonInstance_VideoCodec; -} - -namespace kodi -{ - namespace addon - { - - class ATTRIBUTE_HIDDEN CInstanceVideoCodec : public IAddonInstance - { - public: - explicit CInstanceVideoCodec(KODI_HANDLE instance, const std::string& kodiVersion = "") - : IAddonInstance(ADDON_INSTANCE_VIDEOCODEC, - !kodiVersion.empty() ? kodiVersion - : GetKodiTypeVersion(ADDON_INSTANCE_VIDEOCODEC)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstanceVideoCodec: Creation of multiple together with single instance way is not allowed!"); - - SetAddonStruct(instance); - } - - ~CInstanceVideoCodec() override = default; - - //! \copydoc CInstanceVideoCodec::Open - virtual bool Open(VIDEOCODEC_INITDATA &initData) { return false; }; - - //! \copydoc CInstanceVideoCodec::Reconfigure - virtual bool Reconfigure(VIDEOCODEC_INITDATA &initData) { return false; }; - - //! \copydoc CInstanceVideoCodec::AddData - virtual bool AddData(const DemuxPacket &packet) { return false; }; - - //! \copydoc CInstanceVideoCodec::GetPicture - virtual VIDEOCODEC_RETVAL GetPicture(VIDEOCODEC_PICTURE &picture) { return VC_ERROR; }; - - //! \copydoc CInstanceVideoCodec::GetName - virtual const char *GetName() { return nullptr; }; - - //! \copydoc CInstanceVideoCodec::Reset - virtual void Reset() {}; - - /*! - * @brief AddonToKodi interface - */ - - //! \copydoc CInstanceVideoCodec::GetFrameBuffer - bool GetFrameBuffer(VIDEOCODEC_PICTURE &picture) - { - return m_instanceData->toKodi.get_frame_buffer(m_instanceData->toKodi.kodiInstance, &picture); - } - - //! \copydoc CInstanceVideoCodec::ReleaseFrameBuffer - void ReleaseFrameBuffer(void *buffer) - { - return m_instanceData->toKodi.release_frame_buffer(m_instanceData->toKodi.kodiInstance, buffer); - } - - private: - void SetAddonStruct(KODI_HANDLE instance) - { - if (instance == nullptr) - throw std::logic_error("kodi::addon::CInstanceVideoCodec: Creation with empty addon structure not allowed, table must be given from Kodi!"); - - m_instanceData = static_cast(instance); - - m_instanceData->toAddon.addonInstance = this; - m_instanceData->toAddon.open = ADDON_Open; - m_instanceData->toAddon.reconfigure = ADDON_Reconfigure; - m_instanceData->toAddon.add_data = ADDON_AddData; - m_instanceData->toAddon.get_picture = ADDON_GetPicture; - m_instanceData->toAddon.get_name = ADDON_GetName; - m_instanceData->toAddon.reset = ADDON_Reset; - } - - inline static bool ADDON_Open(const AddonInstance_VideoCodec* instance, VIDEOCODEC_INITDATA *initData) - { - return instance->toAddon.addonInstance->Open(*initData); - } - - inline static bool ADDON_Reconfigure(const AddonInstance_VideoCodec* instance, VIDEOCODEC_INITDATA *initData) - { - return instance->toAddon.addonInstance->Reconfigure(*initData); - } - - inline static bool ADDON_AddData(const AddonInstance_VideoCodec* instance, const DemuxPacket *packet) - { - return instance->toAddon.addonInstance->AddData(*packet); - } - - inline static VIDEOCODEC_RETVAL ADDON_GetPicture(const AddonInstance_VideoCodec* instance, VIDEOCODEC_PICTURE *picture) - { - return instance->toAddon.addonInstance->GetPicture(*picture); - } - - inline static const char *ADDON_GetName(const AddonInstance_VideoCodec* instance) - { - return instance->toAddon.addonInstance->GetName(); - } - - inline static void ADDON_Reset(const AddonInstance_VideoCodec* instance) - { - return instance->toAddon.addonInstance->Reset(); - } - - AddonInstance_VideoCodec* m_instanceData; - }; - } // namespace addon -} // namespace kodi diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Visualization.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Visualization.h deleted file mode 100644 index 4be785d..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Visualization.h +++ /dev/null @@ -1,789 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -/* - * Parts with a comment named "internal" are only used inside header and not - * used or accessed direct during add-on development! - */ - -#include "../AddonBase.h" -#include "../gui/renderHelper.h" - -namespace kodi { namespace addon { class CInstanceVisualization; }} - -extern "C" -{ - -struct AddonInstance_Visualization; - -typedef enum VIS_ACTION : unsigned int /* internal */ -{ - VIS_ACTION_NONE = 0, - VIS_ACTION_NEXT_PRESET, - VIS_ACTION_PREV_PRESET, - VIS_ACTION_LOAD_PRESET, - VIS_ACTION_RANDOM_PRESET, - VIS_ACTION_LOCK_PRESET, - VIS_ACTION_RATE_PRESET_PLUS, - VIS_ACTION_RATE_PRESET_MINUS, - VIS_ACTION_UPDATE_ALBUMART, - VIS_ACTION_UPDATE_TRACK -} VIS_ACTION; - -struct VIS_INFO /* internal */ -{ - bool bWantsFreq; - int iSyncDelay; -}; - -typedef struct AddonProps_Visualization /* internal */ -{ - void *device; - int x; - int y; - int width; - int height; - float pixelRatio; - const char *name; - const char *presets; - const char *profile; -} AddonProps_Visualization; - -typedef struct AddonToKodiFuncTable_Visualization /* internal */ -{ - KODI_HANDLE kodiInstance; - void (__cdecl* transfer_preset) (void* kodiInstance, const char* preset); - void (__cdecl* clear_presets) (void* kodiInstance); -} AddonToKodiFuncTable_Visualization; - -typedef struct KodiToAddonFuncTable_Visualization /* internal */ -{ - kodi::addon::CInstanceVisualization* addonInstance; - bool (__cdecl* start)(const AddonInstance_Visualization* instance, int channels, int samples_per_sec, int bits_per_sample, const char* song_name); - void (__cdecl* stop)(const AddonInstance_Visualization* instance); - void (__cdecl* audio_data)(const AddonInstance_Visualization* instance, const float* audio_data, int audio_data_length, float *freq_data, int freq_data_length); - bool (__cdecl* is_dirty)(const AddonInstance_Visualization* instance); - void (__cdecl* render)(const AddonInstance_Visualization* instance); - void (__cdecl* get_info)(const AddonInstance_Visualization* instance, VIS_INFO *info); - bool (__cdecl* on_action)(const AddonInstance_Visualization* instance, VIS_ACTION action, const void *param); - unsigned int (__cdecl *get_presets)(const AddonInstance_Visualization* instance); - int (__cdecl *get_active_preset)(const AddonInstance_Visualization* instance); - bool (__cdecl* is_locked)(const AddonInstance_Visualization* instance); -} KodiToAddonFuncTable_Visualization; - -typedef struct AddonInstance_Visualization /* internal */ -{ - AddonProps_Visualization* props; - AddonToKodiFuncTable_Visualization* toKodi; - KodiToAddonFuncTable_Visualization* toAddon; -} AddonInstance_Visualization; - -//============================================================================ -/// \defgroup cpp_kodi_addon_visualization_VisTrack class VisTrack -/// \ingroup cpp_kodi_addon_visualization -/// @brief **Visualization track information structure** -/// -/// Called from kodi::addon::CInstanceVisualization::UpdateTrack() with the -/// information of the currently-playing song. -/// -//@{ -struct VisTrack -{ - /// @brief Title of the current song. - const char *title; - - /// @brief Artist names, as a single string - const char *artist; - - /// @brief Album that the current song is from. - const char *album; - - /// @brief Album artist names, as a single string - const char *albumArtist; - - /// @brief The genre name from the music tag, if present. - const char *genre; - - /// @brief Comment of the current song stored in the ID tag info. - const char *comment; - - /// @brief Lyrics of the current song, if available. - const char *lyrics; - - const char *reserved1; - const char *reserved2; - - /// @brief Track number of the current song. - int trackNumber; - - /// @brief Disc number of the current song stored in the ID tag info. - int discNumber; - - /// @brief Duration of the current song, in seconds. - int duration; - - /// @brief Year that the current song was released. - int year; - - /// @brief The user-defined rating of the current song. - int rating; - - int reserved3; - int reserved4; -}; -//@} -//---------------------------------------------------------------------------- - -} /* extern "C" */ - -namespace kodi -{ -namespace addon -{ - - //============================================================================ - /// - /// \addtogroup cpp_kodi_addon_visualization - /// @brief \cpp_class{ kodi::addon::CInstanceVisualization } - /// **Visualization add-on instance** - /// - /// [Music visualization](https://en.wikipedia.org/wiki/Music_visualization), - /// or music visualisation, is a feature in Kodi that generates animated - /// imagery based on a piece of music. The imagery is usually generated and - /// rendered in real time synchronized to the music. - /// - /// Visualization techniques range from simple ones (e.g., a simulation of an - /// oscilloscope display) to elaborate ones, which often include a plurality - /// of composited effects. The changes in the music's loudness and frequency - /// spectrum are among the properties used as input to the visualization. - /// - /// Include the header \ref Visualization.h "#include " - /// to use this class. - /// - /// This interface allows the creation of visualizations for Kodi, based upon - /// **DirectX** or/and **OpenGL** rendering with `C++` code. - /// - /// Additionally, there are several \ref cpp_kodi_addon_visualization_CB "other functions" - /// available in which the child class can ask about the current hardware, - /// including the device, display and several other parts. - /// - /// -------------------------------------------------------------------------- - /// - /// - /// **Here is an example of the minimum required code to start a visualization:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// class CMyVisualization : public kodi::addon::CAddonBase, - /// public kodi::addon::CInstanceVisualization - /// { - /// public: - /// CMyVisualization(); - /// - /// bool Start(int channels, int samplesPerSec, int bitsPerSample, std::string songName) override; - /// void AudioData(const float* audioData, int audioDataLength, float* freqData, int freqDataLength) override; - /// void Render() override; - /// }; - /// - /// CMyVisualization::CMyVisualization() - /// { - /// ... - /// } - /// - /// bool CMyVisualization::Start(int channels, int samplesPerSec, int bitsPerSample, std::string songName) - /// { - /// ... - /// return true; - /// } - /// - /// void CMyVisualization::AudioData(const float* audioData, int audioDataLength, float* freqData, int freqDataLength) - /// { - /// ... - /// } - /// - /// void CMyVisualization::Render() - /// { - /// ... - /// } - /// - /// ADDONCREATOR(CMyVisualization) - /// ~~~~~~~~~~~~~ - /// - /// - /// -------------------------------------------------------------------------- - /// - /// - /// **Here is another example where the visualization is used together with - /// other instance types:** - /// - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// class CMyVisualization : public ::kodi::addon::CInstanceVisualization - /// { - /// public: - /// CMyVisualization(KODI_HANDLE instance); - /// - /// bool Start(int channels, int samplesPerSec, int bitsPerSample, std::string songName) override; - /// void AudioData(const float* audioData, int audioDataLength, float* freqData, int freqDataLength) override; - /// void Render() override; - /// }; - /// - /// CMyVisualization::CMyVisualization(KODI_HANDLE instance) - /// : CInstanceVisualization(instance) - /// { - /// ... - /// } - /// - /// bool CMyVisualization::Start(int channels, int samplesPerSec, int bitsPerSample, std::string songName) - /// { - /// ... - /// return true; - /// } - /// - /// void CMyVisualization::AudioData(const float* audioData, int audioDataLength, float* freqData, int freqDataLength) - /// { - /// ... - /// } - /// - /// void CMyVisualization::Render() - /// { - /// ... - /// } - /// - /// - /// /*----------------------------------------------------------------------*/ - /// - /// class CMyAddon : public ::kodi::addon::CAddonBase - /// { - /// public: - /// CMyAddon() { } - /// ADDON_STATUS CreateInstance(int instanceType, - /// std::string instanceID, - /// KODI_HANDLE instance, - /// KODI_HANDLE& addonInstance) override; - /// }; - /// - /// /* If you use only one instance in your add-on, can be instanceType and - /// * instanceID ignored */ - /// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, - /// std::string instanceID, - /// KODI_HANDLE instance, - /// KODI_HANDLE& addonInstance) - /// { - /// if (instanceType == ADDON_INSTANCE_VISUALIZATION) - /// { - /// kodi::Log(ADDON_LOG_NOTICE, "Creating my Visualization"); - /// addonInstance = new CMyVisualization(instance); - /// return ADDON_STATUS_OK; - /// } - /// else if (...) - /// { - /// ... - /// } - /// return ADDON_STATUS_UNKNOWN; - /// } - /// - /// ADDONCREATOR(CMyAddon) - /// ~~~~~~~~~~~~~ - /// - /// The destruction of the example class `CMyVisualization` is called from - /// Kodi's header. Manually deleting the add-on instance is not required. - /// - //---------------------------------------------------------------------------- - class ATTRIBUTE_HIDDEN CInstanceVisualization : public IAddonInstance - { - public: - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Visualization class constructor - /// - /// Used by an add-on that only supports visualizations. - /// - CInstanceVisualization() - : IAddonInstance(ADDON_INSTANCE_VISUALIZATION, - GetKodiTypeVersion(ADDON_INSTANCE_VISUALIZATION)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstanceVisualization: Cannot create multiple instances of add-on."); - - SetAddonStruct(CAddonBase::m_interface->firstKodiInstance); - CAddonBase::m_interface->globalSingleInstance = this; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Visualization class constructor used to support multiple instance - /// types - /// - /// @param[in] instance The instance value given to - /// `kodi::addon::CAddonBase::CreateInstance(...)`. - /// @param[in] kodiVersion [opt] Version used in Kodi for this instance, to - /// allow compatibility to older Kodi versions. - /// @note Recommended to set. - /// - /// @warning Only use `instance` from the CreateInstance call - /// - explicit CInstanceVisualization(KODI_HANDLE instance, const std::string& kodiVersion = "") - : IAddonInstance(ADDON_INSTANCE_VISUALIZATION, - !kodiVersion.empty() ? kodiVersion - : GetKodiTypeVersion(ADDON_INSTANCE_VISUALIZATION)) - { - if (CAddonBase::m_interface->globalSingleInstance != nullptr) - throw std::logic_error("kodi::addon::CInstanceVisualization: Creation of multiple together with single instance way is not allowed!"); - - SetAddonStruct(instance); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Destructor - /// - ~CInstanceVisualization() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Used to notify the visualization that a new song has been started - /// - /// @param[in] channels Number of channels in the stream - /// @param[in] samplesPerSec Samples per second of stream - /// @param[in] bitsPerSample Number of bits in one sample - /// @param[in] songName The name of the currently-playing song - /// @return true if start successful done - /// - virtual bool Start(int channels, int samplesPerSec, int bitsPerSample, std::string songName) { return true; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Used to inform the visualization that the rendering control was - /// stopped - /// - virtual void Stop() {} - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Pass audio data to the visualization - /// - /// @param[in] audioData The raw audio data - /// @param[in] audioDataLength Length of the audioData array - /// @param[in] freqData The [FFT](https://en.wikipedia.org/wiki/Fast_Fourier_transform) - /// of the audio data - /// @param[in] freqDataLength Length of frequency data array - /// - /// Values **freqData** and **freqDataLength** are used if GetInfo() returns - /// true for the `wantsFreq` parameter. Otherwise, **freqData** is set to - /// `nullptr` and **freqDataLength** is `0`. - /// - virtual void AudioData(const float* audioData, int audioDataLength, float* freqData, int freqDataLength) {} - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Used to inform Kodi that the rendered region is dirty and need an - /// update - /// - /// @return True if dirty - /// - virtual bool IsDirty() { return true; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Used to indicate when the add-on should render - /// - virtual void Render() {} - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Used to get the number of buffers from the current visualization - /// - /// @param[out] wantsFreq Indicates whether the add-on wants FFT - /// data. If set to true, the **freqData** - /// and **freqDataLength** parameters of - /// AudioData() are used - /// @param[out] syncDelay The number of buffers to delay before - /// calling AudioData() - /// - /// @note If this function is not implemented, it will default to - /// `wantsFreq` = false and `syncDelay` = 0. - /// - virtual void GetInfo(bool& wantsFreq, int& syncDelay) { wantsFreq = false; syncDelay = 0; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Used to get a list of visualization presets the user can select - /// from - /// - /// @param[out] presets The vector list containing the names of - /// presets that the user can select - /// @return Return true if successful, or false if - /// there are no presets to choose from - /// - virtual bool GetPresets(std::vector& presets) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Get the index of the current preset - /// - /// @return Index number of the current preset - /// - virtual int GetActivePreset() { return -1; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Check if the add-on is locked to the current preset - /// - /// @return True if locked to the current preset - /// - virtual bool IsLocked() { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Load the previous visualization preset - /// - /// @return Return true if the previous preset was loaded - virtual bool PrevPreset() { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Load the next visualization preset - /// - /// @return Return true if the next preset was loaded - virtual bool NextPreset() { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Load a visualization preset - /// - /// This function is called after a new preset is selected. - /// - /// @param[in] select Preset index to use - /// @return Return true if the preset is loaded - virtual bool LoadPreset(int select) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Switch to a new random preset - /// - /// @return Return true if a random preset was loaded - virtual bool RandomPreset() { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Lock the current visualization preset, preventing it from changing - /// - /// @param[in] lockUnlock If set to true, the preset should be locked - /// @return Return true if the current preset is locked - virtual bool LockPreset(bool lockUnlock) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Used to increase/decrease the visualization preset rating - /// - /// @param[in] plusMinus If set to true the rating is increased, otherwise - /// decreased - /// @return Return true if the rating is modified - virtual bool RatePreset(bool plusMinus) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Inform the visualization of the current album art image - /// - /// @param[in] albumart Path to the current album art image - /// @return Return true if the image is used - virtual bool UpdateAlbumart(std::string albumart) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization - /// @brief Inform the visualization of the current track's tag information - /// - /// @param[in] track Visualization track information structure - /// @return Return true if the track information is used - virtual bool UpdateTrack(const VisTrack &track) { return false; } - - //========================================================================== - /// - /// \defgroup cpp_kodi_addon_visualization_CB Information functions - /// \ingroup cpp_kodi_addon_visualization - /// @brief **To get info about the device, display and several other parts** - /// - //@{ - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization_CB - /// @brief To transfer available presets on addon - /// - /// Used if @ref GetPresets not possible to use, e.g. where available presets - /// are only known during @ref Start call. - /// - /// @param[in] presets List to store available presets. - /// - /// @note The function should only be called once, if possible - /// - inline void TransferPresets(const std::vector& presets) - { - m_instanceData->toKodi->clear_presets(m_instanceData->toKodi->kodiInstance); - for (auto it : presets) - m_instanceData->toKodi->transfer_preset(m_instanceData->toKodi->kodiInstance, it.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization_CB - /// @brief Device that represents the display adapter - /// - /// @return A pointer to the used device - /// - /// @note This is only available on **DirectX**, It us unused (`nullptr`) on - /// **OpenGL** - /// - inline void* Device() { return m_instanceData->props->device; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization_CB - /// @brief Returns the X position of the rendering window - /// - /// @return The X position, in pixels - /// - inline int X() { return m_instanceData->props->x; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization_CB - /// @brief Returns the Y position of the rendering window - /// - /// @return The Y position, in pixels - /// - inline int Y() { return m_instanceData->props->y; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization_CB - /// @brief Returns the width of the rendering window - /// - /// @return The width, in pixels - /// - inline int Width() { return m_instanceData->props->width; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization_CB - /// @brief Returns the height of the rendering window - /// - /// @return The height, in pixels - /// - inline int Height() { return m_instanceData->props->height; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization_CB - /// @brief Pixel aspect ratio (often abbreviated PAR) is a ratio that - /// describes how the width of a pixel compares to the height of that pixel. - /// - /// @return The pixel aspect ratio used by the display - /// - inline float PixelRatio() { return m_instanceData->props->pixelRatio; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization_CB - /// @brief Used to get the name of the add-on defined in `addon.xml` - /// - /// @return The add-on name - /// - inline std::string Name() { return m_instanceData->props->name; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization_CB - /// @brief Used to get the full path where the add-on is installed - /// - /// @return The add-on installation path - /// - inline std::string Presets() { return m_instanceData->props->presets; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_addon_visualization_CB - /// @brief Used to get the full path to the add-on's user profile - /// - /// @note The trailing folder (consisting of the add-on's ID) is not created - /// by default. If it is needed, you must call kodi::vfs::CreateDirectory() - /// to create the folder. - /// - /// @return Path to the user profile - /// - inline std::string Profile() { return m_instanceData->props->profile; } - //-------------------------------------------------------------------------- - //@} - - private: - void SetAddonStruct(KODI_HANDLE instance) - { - if (instance == nullptr) - throw std::logic_error("kodi::addon::CInstanceVisualization: Null pointer instance passed."); - - m_instanceData = static_cast(instance); - m_instanceData->toAddon->addonInstance = this; - m_instanceData->toAddon->start = ADDON_Start; - m_instanceData->toAddon->stop = ADDON_Stop; - m_instanceData->toAddon->audio_data = ADDON_AudioData; - m_instanceData->toAddon->is_dirty = ADDON_IsDirty; - m_instanceData->toAddon->render = ADDON_Render; - m_instanceData->toAddon->get_info = ADDON_GetInfo; - m_instanceData->toAddon->on_action = ADDON_OnAction; - m_instanceData->toAddon->get_presets = ADDON_GetPresets; - m_instanceData->toAddon->get_active_preset = ADDON_GetActivePreset; - m_instanceData->toAddon->is_locked = ADDON_IsLocked; - } - - inline static bool ADDON_Start(const AddonInstance_Visualization* addon, int channels, int samplesPerSec, int bitsPerSample, const char* songName) - { - addon->toAddon->addonInstance->m_renderHelper = kodi::gui::GetRenderHelper(); - return addon->toAddon->addonInstance->Start(channels, samplesPerSec, bitsPerSample, songName); - } - - inline static void ADDON_Stop(const AddonInstance_Visualization* addon) - { - addon->toAddon->addonInstance->Stop(); - addon->toAddon->addonInstance->m_renderHelper = nullptr; - } - - inline static void ADDON_AudioData(const AddonInstance_Visualization* addon, const float* audioData, int audioDataLength, float *freqData, int freqDataLength) - { - addon->toAddon->addonInstance->AudioData(audioData, audioDataLength, freqData, freqDataLength); - } - - inline static bool ADDON_IsDirty(const AddonInstance_Visualization* addon) - { - return addon->toAddon->addonInstance->IsDirty(); - } - - inline static void ADDON_Render(const AddonInstance_Visualization* addon) - { - if (!addon->toAddon->addonInstance->m_renderHelper) - return; - addon->toAddon->addonInstance->m_renderHelper->Begin(); - addon->toAddon->addonInstance->Render(); - addon->toAddon->addonInstance->m_renderHelper->End(); - } - - inline static void ADDON_GetInfo(const AddonInstance_Visualization* addon, VIS_INFO *info) - { - addon->toAddon->addonInstance->GetInfo(info->bWantsFreq, info->iSyncDelay); - } - - inline static bool ADDON_OnAction(const AddonInstance_Visualization* addon, VIS_ACTION action, const void *param) - { - switch (action) - { - case VIS_ACTION_NEXT_PRESET: - return addon->toAddon->addonInstance->NextPreset(); - case VIS_ACTION_PREV_PRESET: - return addon->toAddon->addonInstance->PrevPreset(); - case VIS_ACTION_LOAD_PRESET: - return addon->toAddon->addonInstance->LoadPreset(*static_cast(param)); - case VIS_ACTION_RANDOM_PRESET: - return addon->toAddon->addonInstance->RandomPreset(); - case VIS_ACTION_LOCK_PRESET: - addon->toAddon->addonInstance->m_presetLockedByUser = !addon->toAddon->addonInstance->m_presetLockedByUser; - return addon->toAddon->addonInstance->LockPreset(addon->toAddon->addonInstance->m_presetLockedByUser); - case VIS_ACTION_RATE_PRESET_PLUS: - return addon->toAddon->addonInstance->RatePreset(true); - case VIS_ACTION_RATE_PRESET_MINUS: - return addon->toAddon->addonInstance->RatePreset(false); - case VIS_ACTION_UPDATE_ALBUMART: - return addon->toAddon->addonInstance->UpdateAlbumart(static_cast(param)); - case VIS_ACTION_UPDATE_TRACK: - return addon->toAddon->addonInstance->UpdateTrack(*static_cast(param)); - case VIS_ACTION_NONE: - default: - break; - } - return false; - } - - inline static unsigned int ADDON_GetPresets(const AddonInstance_Visualization* addon) - { - std::vector presets; - if (addon->toAddon->addonInstance->GetPresets(presets)) - { - for (auto it : presets) - addon->toAddon->addonInstance->m_instanceData->toKodi->transfer_preset(addon->toKodi->kodiInstance, it.c_str()); - } - - return static_cast(presets.size()); - } - - inline static int ADDON_GetActivePreset(const AddonInstance_Visualization* addon) - { - return addon->toAddon->addonInstance->GetActivePreset(); - } - - inline static bool ADDON_IsLocked(const AddonInstance_Visualization* addon) - { - return addon->toAddon->addonInstance->IsLocked(); - } - - std::shared_ptr m_renderHelper; - bool m_presetLockedByUser = false; - AddonInstance_Visualization* m_instanceData; - }; - -} /* namespace addon */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/CMakeLists.txt deleted file mode 100644 index 946849e..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -set(HEADERS ChannelGroups.h - Channels.h - EDL.h - EPG.h - General.h - MenuHook.h - Recordings.h - Stream.h - Timers.h) - -if(NOT ENABLE_STATIC_LIBS) - core_add_library(addons_kodi-addon-dev-kit_include_kodi_addon-instance_pvr) -endif() diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/ChannelGroups.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/ChannelGroups.h deleted file mode 100644 index 17995bb..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/ChannelGroups.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../../c-api/addon-instance/pvr.h" - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" Definitions group 3 - PVR channel group -#ifdef __cplusplus - -namespace kodi -{ -namespace addon -{ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup class PVRChannelGroup -/// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup -/// @brief **PVR add-on channel group**\n -/// To define a group for channels, this becomes be asked from -/// @ref kodi::addon::CInstancePVRClient::GetChannelGroups() and used on -/// @ref kodi::addon::CInstancePVRClient::GetChannelGroupMembers() to get his -/// content with @ref cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember "PVRChannelGroupMember". -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup_Help -/// -///@{ -class PVRChannelGroup : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVRChannelGroup() { memset(m_cStructure, 0, sizeof(PVR_CHANNEL_GROUP)); } - PVRChannelGroup(const PVRChannelGroup& channel) : CStructHdl(channel) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup : - /// | Name | Type | Set call | Get call | Usage - /// |------|------|----------|----------|----------- - /// | **Group name** | `std::string` | @ref PVRChannelGroup::SetGroupName "SetGroupName" | @ref PVRChannelGroup::GetGroupName "GetGroupName" | *required to set* - /// | **Is radio** | `bool` | @ref PVRChannelGroup::SetIsRadio "SetIsRadio" | @ref PVRChannelGroup::GetIsRadio "GetIsRadio" | *required to set* - /// | **Position** | `unsigned int` | @ref PVRChannelGroup::SetPosition "SetPosition" | @ref PVRChannelGroup::GetPosition "GetPosition" | *optional* - /// - - /// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup - ///@{ - - /// @brief **required**\n - /// Name of this channel group. - void SetGroupName(const std::string& groupName) - { - strncpy(m_cStructure->strGroupName, groupName.c_str(), sizeof(m_cStructure->strGroupName) - 1); - } - - /// @brief To get with @ref SetGroupName changed values. - std::string GetGroupName() const { return m_cStructure->strGroupName; } - - /// @brief **required**\n - /// **true** If this is a radio channel group, **false** otherwise. - void SetIsRadio(bool isRadio) { m_cStructure->bIsRadio = isRadio; } - - /// @brief To get with @ref SetIsRadio changed values. - bool GetIsRadio() const { return m_cStructure->bIsRadio; } - - /// @brief **optional**\n - /// Sort position of the group (`0` indicates that the backend doesn't - /// support sorting of groups). - void SetPosition(unsigned int position) { m_cStructure->iPosition = position; } - - /// @brief To get with @ref SetPosition changed values. - unsigned int GetPosition() const { return m_cStructure->iPosition; } - - ///@} - -private: - PVRChannelGroup(const PVR_CHANNEL_GROUP* channel) : CStructHdl(channel) {} - PVRChannelGroup(PVR_CHANNEL_GROUP* channel) : CStructHdl(channel) {} -}; -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupsResultSet class PVRChannelGroupsResultSet -/// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup -/// @brief **PVR add-on channel group member transfer class**\n -/// To transfer the content of @ref kodi::addon::CInstancePVRClient::GetChannelGroups(). -/// -///@{ -class PVRChannelGroupsResultSet -{ -public: - /*! \cond PRIVATE */ - PVRChannelGroupsResultSet() = delete; - PVRChannelGroupsResultSet(const AddonInstance_PVR* instance, ADDON_HANDLE handle) - : m_instance(instance), m_handle(handle) - { - } - /*! \endcond */ - - - /// @addtogroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupsResultSet - ///@{ - - /// @brief To add and give content from addon to Kodi on related call. - /// - /// @param[in] tag The to transferred data. - void Add(const kodi::addon::PVRChannelGroup& tag) - { - m_instance->toKodi->TransferChannelGroup(m_instance->toKodi->kodiInstance, m_handle, tag); - } - - ///@} - -private: - const AddonInstance_PVR* m_instance = nullptr; - const ADDON_HANDLE m_handle; -}; -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember class PVRChannelGroupMember -/// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup -/// @brief **PVR add-on channel group member**\n -/// To define the content of @ref kodi::addon::CInstancePVRClient::GetChannelGroups() -/// given groups. -/// -/// This content becomes then requested with @ref kodi::addon::CInstancePVRClient::GetChannelGroupMembers(). -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember_Help -/// -///@{ -class PVRChannelGroupMember : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVRChannelGroupMember() { memset(m_cStructure, 0, sizeof(PVR_CHANNEL_GROUP_MEMBER)); } - PVRChannelGroupMember(const PVRChannelGroupMember& channel) : CStructHdl(channel) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember : - /// | Name | Type | Set call | Get call | Usage - /// |-------|-------|-----------|----------|----------- - /// | **Group name** | `std::string` | @ref PVRChannelGroupMember::SetGroupName "SetGroupName" | @ref PVRChannelGroupMember::GetGroupName "GetGroupName" | *required to set* - /// | **Channel unique id** | `unsigned int` | @ref PVRChannelGroupMember::SetChannelUniqueId "SetChannelUniqueId" | @ref PVRChannelGroupMember::GetChannelUniqueId "GetChannelUniqueId" | *required to set* - /// | **Channel Number** | `unsigned int` | @ref PVRChannelGroupMember::SetChannelNumber "SetChannelNumber" | @ref PVRChannelGroupMember::GetChannelNumber "GetChannelNumber" | *optional* - /// | **Sub channel number** | `unsigned int` | @ref PVRChannelGroupMember::SetSubChannelNumber "SetSubChannelNumber"| @ref PVRChannelGroupMember::GetSubChannelNumber "GetSubChannelNumber" | *optional* - /// | **Order** | `int` | @ref PVRChannel::SetOrder "SetOrder" | @ref PVRChannel::GetOrder "GetOrder" | *optional* - /// - - /// @addtogroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember - ///@{ - - /// @brief **required**\n - /// Name of the channel group to add the channel to. - void SetGroupName(const std::string& groupName) - { - strncpy(m_cStructure->strGroupName, groupName.c_str(), sizeof(m_cStructure->strGroupName) - 1); - } - - /// @brief To get with @ref SetGroupName changed values. - std::string GetGroupName() const { return m_cStructure->strGroupName; } - - /// @brief **required**\n - /// Unique id of the member. - void SetChannelUniqueId(unsigned int channelUniqueId) - { - m_cStructure->iChannelUniqueId = channelUniqueId; - } - - /// @brief To get with @ref SetChannelUniqueId changed values. - unsigned int GetChannelUniqueId() const { return m_cStructure->iChannelUniqueId; } - - /// @brief **optional**\n - /// Channel number within the group. - void SetChannelNumber(unsigned int channelNumber) - { - m_cStructure->iChannelNumber = channelNumber; - } - - /// @brief To get with @ref SetChannelNumber changed values. - unsigned int GetChannelNumber() const { return m_cStructure->iChannelNumber; } - - /// @brief **optional**\n - /// Sub channel number within the group (ATSC). - void SetSubChannelNumber(unsigned int subChannelNumber) - { - m_cStructure->iSubChannelNumber = subChannelNumber; - } - - /// @brief To get with @ref SetSubChannelNumber changed values. - unsigned int GetSubChannelNumber() const { return m_cStructure->iSubChannelNumber; } - - /// @brief **optional**\n - /// The value denoting the order of this channel in the 'All channels' group. - void SetOrder(bool order) { m_cStructure->iOrder = order; } - - /// @brief To get with @ref SetOrder changed values. - bool GetOrder() const { return m_cStructure->iOrder; } - - ///@} - -private: - PVRChannelGroupMember(const PVR_CHANNEL_GROUP_MEMBER* channel) : CStructHdl(channel) {} - PVRChannelGroupMember(PVR_CHANNEL_GROUP_MEMBER* channel) : CStructHdl(channel) {} -}; -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMembersResultSet class PVRChannelGroupMembersResultSet -/// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember -/// @brief **PVR add-on channel group member transfer class**\n -/// To transfer the content of @ref kodi::addon::CInstancePVRClient::GetChannelGroupMembers(). -/// -///@{ -class PVRChannelGroupMembersResultSet -{ -public: - /*! \cond PRIVATE */ - PVRChannelGroupMembersResultSet() = delete; - PVRChannelGroupMembersResultSet(const AddonInstance_PVR* instance, ADDON_HANDLE handle) - : m_instance(instance), m_handle(handle) - { - } - /*! \endcond */ - - /// @addtogroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMembersResultSet - ///@{ - - /// @brief To add and give content from addon to Kodi on related call. - /// - /// @param[in] tag The to transferred data. - void Add(const kodi::addon::PVRChannelGroupMember& tag) - { - m_instance->toKodi->TransferChannelGroupMember(m_instance->toKodi->kodiInstance, m_handle, tag); - } - - ///@} - -private: - const AddonInstance_PVR* m_instance = nullptr; - const ADDON_HANDLE m_handle; -}; -///@} -//------------------------------------------------------------------------------ - -} /* namespace addon */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Channels.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Channels.h deleted file mode 100644 index 9c2f5d2..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Channels.h +++ /dev/null @@ -1,518 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../../c-api/addon-instance/pvr.h" - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" Definitions group 2 - PVR channel -#ifdef __cplusplus - -namespace kodi -{ -namespace addon -{ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannel class PVRChannel -/// @ingroup cpp_kodi_addon_pvr_Defs_Channel -/// @brief **Channel data structure**\n -/// Representation of a TV or radio channel. -/// -/// This is used to store all the necessary TV or radio channel data and can -/// either provide the necessary data from / to Kodi for the associated -/// functions or can also be used in the addon to store its data. -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRChannel_Help -/// -///@{ -class PVRChannel : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVRChannel() { memset(m_cStructure, 0, sizeof(PVR_CHANNEL)); } - PVRChannel(const PVRChannel& channel) : CStructHdl(channel) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannel_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannel - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Channel_PVRChannel : - /// | Name | Type | Set call | Get call | Usage - /// |------|------|----------|----------|----------- - /// | **Unique id** | `unsigned int` | @ref PVRChannel::SetUniqueId "SetUniqueId" | @ref PVRChannel::GetUniqueId "GetUniqueId" | *required to set* - /// | **Is radio** | `bool` | @ref PVRChannel::SetIsRadio "SetIsRadio" | @ref PVRChannel::GetIsRadio "GetIsRadio" | *required to set* - /// | **Channel number** | `unsigned int` | @ref PVRChannel::SetChannelNumber "SetChannelNumber" | @ref PVRChannel::GetChannelNumber "GetChannelNumber" | *optional* - /// | **Sub channel number** | `unsigned int` | @ref PVRChannel::SetSubChannelNumber "SetSubChannelNumber" | @ref PVRChannel::GetSubChannelNumber "GetSubChannelNumber" | *optional* - /// | **Channel name** | `std::string` | @ref PVRChannel::SetChannelName "SetChannelName" | @ref PVRChannel::GetChannelName "GetChannelName" | *optional* - /// | **Mime type** | `std::string` | @ref PVRChannel::SetMimeType "SetMimeType" | @ref PVRChannel::GetMimeType "GetMimeType" | *optional* - /// | **Encryption system** | `unsigned int` | @ref PVRChannel::SetEncryptionSystem "SetEncryptionSystem" | @ref PVRChannel::GetEncryptionSystem "GetEncryptionSystem" | *optional* - /// | **Icon path** | `std::string` | @ref PVRChannel::SetIconPath "SetIconPath" | @ref PVRChannel::GetIconPath "GetIconPath" | *optional* - /// | **Is hidden** | `bool` | @ref PVRChannel::SetIsHidden "SetIsHidden" | @ref PVRChannel::GetIsHidden "GetIsHidden" | *optional* - /// | **Has archive** | `bool` | @ref PVRChannel::SetHasArchive "SetHasArchive" | @ref PVRChannel::GetHasArchive "GetHasArchive" | *optional* - /// | **Order** | `int` | @ref PVRChannel::SetOrder "SetOrder" | @ref PVRChannel::GetOrder "GetOrder" | *optional* - /// - - /// @addtogroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannel - ///@{ - - /// @brief **required**\n - /// Unique identifier for this channel. - void SetUniqueId(unsigned int uniqueId) { m_cStructure->iUniqueId = uniqueId; } - - /// @brief To get with @ref SetUniqueId changed values. - unsigned int GetUniqueId() const { return m_cStructure->iUniqueId; } - - /// @brief **required**\n - /// **true** if this is a radio channel, **false** if it's a TV channel. - void SetIsRadio(bool isRadio) { m_cStructure->bIsRadio = isRadio; } - - /// @brief To get with @ref SetIsRadio changed values. - bool GetIsRadio() const { return m_cStructure->bIsRadio; } - - /// @brief **optional**\n - /// Channel number of this channel on the backend. - void SetChannelNumber(unsigned int channelNumber) - { - m_cStructure->iChannelNumber = channelNumber; - } - - /// @brief To get with @ref SetChannelNumber changed values. - unsigned int GetChannelNumber() const { return m_cStructure->iChannelNumber; } - - /// @brief **optional**\n - /// Sub channel number of this channel on the backend (ATSC). - void SetSubChannelNumber(unsigned int subChannelNumber) - { - m_cStructure->iSubChannelNumber = subChannelNumber; - } - - /// @brief To get with @ref SetSubChannelNumber changed values. - unsigned int GetSubChannelNumber() const { return m_cStructure->iSubChannelNumber; } - - /// @brief **optional**\n - /// Channel name given to this channel. - void SetChannelName(const std::string& channelName) - { - strncpy(m_cStructure->strChannelName, channelName.c_str(), - sizeof(m_cStructure->strChannelName) - 1); - } - - /// @brief To get with @ref SetChannelName changed values. - std::string GetChannelName() const { return m_cStructure->strChannelName; } - - /// @brief **optional**\n - /// Input format mime type. - /// - /// Available types can be found in https://www.iana.org/assignments/media-types/media-types.xhtml - /// on "application" and "video" or leave empty if unknown. - /// - void SetMimeType(const std::string& inputFormat) - { - strncpy(m_cStructure->strMimeType, inputFormat.c_str(), sizeof(m_cStructure->strMimeType) - 1); - } - - /// @brief To get with @ref SetMimeType changed values. - std::string GetMimeType() const { return m_cStructure->strMimeType; } - - /// @brief **optional**\n - /// The encryption ID or CaID of this channel (Conditional access systems). - /// - /// Lists about available ID's: - /// - http://www.dvb.org/index.php?id=174 - /// - http://en.wikipedia.org/wiki/Conditional_access_system - /// - void SetEncryptionSystem(unsigned int encryptionSystem) - { - m_cStructure->iEncryptionSystem = encryptionSystem; - } - - /// @brief To get with @ref SetEncryptionSystem changed values. - unsigned int GetEncryptionSystem() const { return m_cStructure->iEncryptionSystem; } - - /// @brief **optional**\n - /// Path to the channel icon (if present). - void SetIconPath(const std::string& iconPath) - { - strncpy(m_cStructure->strIconPath, iconPath.c_str(), sizeof(m_cStructure->strIconPath) - 1); - } - - /// @brief To get with @ref SetIconPath changed values. - std::string GetIconPath() const { return m_cStructure->strIconPath; } - - /// @brief **optional**\n - /// **true** if this channel is marked as hidden. - void SetIsHidden(bool isHidden) { m_cStructure->bIsHidden = isHidden; } - - /// @brief To get with @ref GetIsRadio changed values. - bool GetIsHidden() const { return m_cStructure->bIsHidden; } - - /// @brief **optional**\n - /// **true** if this channel has a server-side back buffer. - void SetHasArchive(bool hasArchive) { m_cStructure->bHasArchive = hasArchive; } - - /// @brief To get with @ref GetIsRadio changed values. - bool GetHasArchive() const { return m_cStructure->bHasArchive; } - - /// @brief **optional**\n - /// The value denoting the order of this channel in the 'All channels' group. - void SetOrder(bool order) { m_cStructure->iOrder = order; } - - /// @brief To get with @ref SetOrder changed values. - bool GetOrder() const { return m_cStructure->iOrder; } - ///@} - -private: - PVRChannel(const PVR_CHANNEL* channel) : CStructHdl(channel) {} - PVRChannel(PVR_CHANNEL* channel) : CStructHdl(channel) {} -}; -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannelsResultSet class PVRChannelsResultSet -/// @ingroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannel -/// @brief **PVR add-on channel transfer class**\n -/// To transfer the content of @ref kodi::addon::CInstancePVRClient::GetChannels(). -/// -///@{ -class PVRChannelsResultSet -{ -public: - /*! \cond PRIVATE */ - PVRChannelsResultSet() = delete; - PVRChannelsResultSet(const AddonInstance_PVR* instance, ADDON_HANDLE handle) - : m_instance(instance), m_handle(handle) - { - } - /*! \endcond */ - - /// @addtogroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannelsResultSet - ///@{ - - /// @brief To add and give content from addon to Kodi on related call. - /// - /// @param[in] tag The to transferred data. - void Add(const kodi::addon::PVRChannel& tag) - { - m_instance->toKodi->TransferChannelEntry(m_instance->toKodi->kodiInstance, m_handle, tag); - } - - ///@} - -private: - const AddonInstance_PVR* m_instance = nullptr; - const ADDON_HANDLE m_handle; -}; -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus class PVRSignalStatus -/// @ingroup cpp_kodi_addon_pvr_Defs_Channel -/// @brief **PVR Signal status information**\n -/// This class gives current status information from stream to Kodi. -/// -/// Used to get information for user by call of @ref kodi::addon::CInstancePVRClient::GetSignalStatus() -/// to see current quality and source. -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus_Help -/// -///@{ -class PVRSignalStatus : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVRSignalStatus() = default; - PVRSignalStatus(const PVRSignalStatus& type) : CStructHdl(type) {} - /*! \endcond */ - - - /// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus : - /// | Name | Type | Set call | Get call | Usage - /// |------|------|----------|----------|----------- - /// | **Adapter name** | `std::string` | @ref PVRSignalStatus::SetAdapterName "SetAdapterName" | @ref PVRSignalStatus::GetAdapterName "GetAdapterName" | *optional* - /// | **Adapter status** | `std::string` | @ref PVRSignalStatus::SetAdapterStatus "SetAdapterStatus" | @ref PVRSignalStatus::GetAdapterStatus "GetAdapterStatus" | *optional* - /// | **Service name** | `std::string` | @ref PVRSignalStatus::SetServiceName "SetServiceName" | @ref PVRSignalStatus::GetServiceName "GetServiceName" | *optional* - /// | **Provider name** | `std::string` | @ref PVRSignalStatus::SetProviderName "SetProviderName" | @ref PVRSignalStatus::GetProviderName "GetProviderName" | *optional* - /// | **Mux name** | `std::string` | @ref PVRSignalStatus::SetMuxName "SetMuxName" | @ref PVRSignalStatus::GetMuxName "GetMuxName" | *optional* - /// | **Signal/noise ratio** | `int` | @ref PVRSignalStatus::SetSNR "SetSNR" | @ref PVRSignalStatus::GetSNR "GetSNR" | *optional* - /// | **Signal strength** | `int` | @ref PVRSignalStatus::SetSignal "SetSignal" | @ref PVRSignalStatus::GetSignal "GetSignal" | *optional* - /// | **Bit error rate** | `long` | @ref PVRSignalStatus::SetBER "SetBER" | @ref PVRSignalStatus::GetBER "GetBER" | *optional* - /// | **Uncorrected blocks** | `long` | @ref PVRSignalStatus::SetUNC "SetUNC" | @ref PVRSignalStatus::GetUNC "GetUNC" | *optional* - /// - - /// @addtogroup cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus - ///@{ - - /// @brief **optional**\n - /// Name of the adapter that's being used. - void SetAdapterName(const std::string& adapterName) - { - strncpy(m_cStructure->strAdapterName, adapterName.c_str(), - sizeof(m_cStructure->strAdapterName) - 1); - } - - /// @brief To get with @ref SetAdapterName changed values. - std::string GetAdapterName() const { return m_cStructure->strAdapterName; } - - /// @brief **optional**\n - /// Status of the adapter that's being used. - void SetAdapterStatus(const std::string& adapterStatus) - { - strncpy(m_cStructure->strAdapterStatus, adapterStatus.c_str(), - sizeof(m_cStructure->strAdapterStatus) - 1); - } - - /// @brief To get with @ref SetAdapterStatus changed values. - std::string GetAdapterStatus() const { return m_cStructure->strAdapterStatus; } - - /// @brief **optional**\n - /// Name of the current service. - void SetServiceName(const std::string& serviceName) - { - strncpy(m_cStructure->strServiceName, serviceName.c_str(), - sizeof(m_cStructure->strServiceName) - 1); - } - - /// @brief To get with @ref SetServiceName changed values. - std::string GetServiceName() const { return m_cStructure->strServiceName; } - - /// @brief **optional**\n - /// Name of the current service's provider. - void SetProviderName(const std::string& providerName) - { - strncpy(m_cStructure->strProviderName, providerName.c_str(), - sizeof(m_cStructure->strProviderName) - 1); - } - - /// @brief To get with @ref SetProviderName changed values. - std::string GetProviderName() const { return m_cStructure->strProviderName; } - - /// @brief **optional**\n - /// Name of the current mux. - void SetMuxName(const std::string& muxName) - { - strncpy(m_cStructure->strMuxName, muxName.c_str(), sizeof(m_cStructure->strMuxName) - 1); - } - - /// @brief To get with @ref SetMuxName changed values. - std::string GetMuxName() const { return m_cStructure->strMuxName; } - - /// @brief **optional**\n - /// Signal/noise ratio. - /// - /// @note 100% is 0xFFFF 65535 - void SetSNR(int snr) { m_cStructure->iSNR = snr; } - - /// @brief To get with @ref SetSNR changed values. - int GetSNR() const { return m_cStructure->iSNR; } - - /// @brief **optional**\n - /// Signal strength. - /// - /// @note 100% is 0xFFFF 65535 - void SetSignal(int signal) { m_cStructure->iSignal = signal; } - - /// @brief To get with @ref SetSignal changed values. - int GetSignal() const { return m_cStructure->iSignal; } - - /// @brief **optional**\n - /// Bit error rate. - void SetBER(long ber) { m_cStructure->iBER = ber; } - - /// @brief To get with @ref SetBER changed values. - long GetBER() const { return m_cStructure->iBER; } - - /// @brief **optional**\n - /// Uncorrected blocks: - void SetUNC(long unc) { m_cStructure->iUNC = unc; } - - /// @brief To get with @ref SetBER changed values. - long GetUNC() const { return m_cStructure->iUNC; } - ///@} - -private: - PVRSignalStatus(const PVR_SIGNAL_STATUS* type) : CStructHdl(type) {} - PVRSignalStatus(PVR_SIGNAL_STATUS* type) : CStructHdl(type) {} -}; -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo class PVRDescrambleInfo -/// @ingroup cpp_kodi_addon_pvr_Defs_Channel -/// @brief **Data structure for descrample info**\n -/// Information data to give via this to Kodi. -/// -/// As description see also here https://en.wikipedia.org/wiki/Conditional_access. -/// -/// Used on @ref kodi::addon::CInstancePVRClient::GetDescrambleInfo(). -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo_Help -/// -///@{ -class PVRDescrambleInfo : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVRDescrambleInfo() - { - m_cStructure->iPid = PVR_DESCRAMBLE_INFO_NOT_AVAILABLE; - m_cStructure->iCaid = PVR_DESCRAMBLE_INFO_NOT_AVAILABLE; - m_cStructure->iProvid = PVR_DESCRAMBLE_INFO_NOT_AVAILABLE; - m_cStructure->iEcmTime = PVR_DESCRAMBLE_INFO_NOT_AVAILABLE; - m_cStructure->iHops = PVR_DESCRAMBLE_INFO_NOT_AVAILABLE; - } - PVRDescrambleInfo(const PVRDescrambleInfo& type) : CStructHdl(type) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo : - /// | Name | Type | Set call | Get call | Usage - /// |------|------|----------|----------|----------- - /// | **Packet identifier** | `int` | @ref PVRDescrambleInfo::SetPID "SetPID" | @ref PVRDescrambleInfo::GetPID "GetPID" | *optional* - /// | **Conditional access identifier** | `int` | @ref PVRDescrambleInfo::SetCAID "SetCAID" | @ref PVRDescrambleInfo::GetCAID "GetCAID" | *optional* - /// | **Provider-ID** | `int` | @ref PVRDescrambleInfo::SetProviderID "SetProviderID" | @ref PVRDescrambleInfo::GetProviderID "GetProviderID" | *optional* - /// | **ECM time** | `int` | @ref PVRDescrambleInfo::SetECMTime "SetECMTime" | @ref PVRDescrambleInfo::GetECMTime "GetECMTime" | *optional* - /// | **Hops** | `int` | @ref PVRDescrambleInfo::SetHops "SetHops" | @ref PVRDescrambleInfo::GetHops "GetHops" | *optional* - /// | **Descramble card system** | `std::string` | @ref PVRDescrambleInfo::SetHops "SetHops" | @ref PVRDescrambleInfo::GetHops "GetHops" | *optional* - /// | **Reader** | `std::string` | @ref PVRDescrambleInfo::SetReader "SetReader" | @ref PVRDescrambleInfo::GetReader "GetReader" | *optional* - /// | **From** | `std::string` | @ref PVRDescrambleInfo::SetFrom "SetFrom" | @ref PVRDescrambleInfo::GetFrom "GetFrom" | *optional* - /// | **Protocol** | `std::string` | @ref PVRDescrambleInfo::SetProtocol "SetProtocol" | @ref PVRDescrambleInfo::GetProtocol "GetProtocol" | *optional* - /// - - /// @addtogroup cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo - ///@{ - - /// @brief **optional**\n - /// Packet identifier. - /// - /// Each table or elementary stream in a transport stream is identified by - /// a 13-bit packet identifier (PID). - /// - /// Is @ref PVR_DESCRAMBLE_INFO_NOT_AVAILABLE as default, if not available - void SetPID(int pid) { m_cStructure->iPid = pid; } - - /// @brief To get with @ref SetPID changed values - int GetPID() const { return m_cStructure->iPid; } - - /// @brief **optional**\n - /// Conditional access identifier. - /// - /// Conditional access (abbreviated CA) or conditional access system (abbreviated CAS) - /// is the protection of content by requiring certain criteria to be met before granting - /// access to the content. - /// - /// Available CA system ID's listed here https://www.dvbservices.com/identifiers/ca_system_id. - /// - /// @ref PVR_DESCRAMBLE_INFO_NOT_AVAILABLE if not available. - void SetCAID(int iCaid) { m_cStructure->iCaid = iCaid; } - - /// @brief To get with @ref SetCAID changed values. - int GetCAID() const { return m_cStructure->iCaid; } - - /// @brief **optional**\n - /// Provider-ID. - /// - /// Is @ref PVR_DESCRAMBLE_INFO_NOT_AVAILABLE as default, if not available. - void SetProviderID(int provid) { m_cStructure->iProvid = provid; } - - /// @brief To get with @ref SetProviderID changed values - int GetProviderID() const { return m_cStructure->iProvid; } - - /// @brief **optional**\n - /// ECM time. - /// - /// Is @ref PVR_DESCRAMBLE_INFO_NOT_AVAILABLE as default, if not available. - void SetECMTime(int ecmTime) { m_cStructure->iEcmTime = ecmTime; } - - /// @brief To get with @ref SetECMTime changed values. - int GetECMTime() const { return m_cStructure->iEcmTime; } - - /// @brief **optional**\n - /// Hops. - /// - /// Is @ref PVR_DESCRAMBLE_INFO_NOT_AVAILABLE as default, if not available. - void SetHops(int hops) { m_cStructure->iHops = hops; } - - /// @brief To get with @ref SetHops changed values. - int GetHops() const { return m_cStructure->iHops; } - - /// @brief **optional**\n - /// Empty string if not available. - void SetCardSystem(const std::string& cardSystem) - { - strncpy(m_cStructure->strCardSystem, cardSystem.c_str(), - sizeof(m_cStructure->strCardSystem) - 1); - } - - /// @brief To get with @ref SetCardSystem changed values. - std::string GetCardSystem() const { return m_cStructure->strCardSystem; } - - /// @brief **optional**\n - /// Empty string if not available. - void SetReader(const std::string& reader) - { - strncpy(m_cStructure->strReader, reader.c_str(), sizeof(m_cStructure->strReader) - 1); - } - - /// @brief To get with @ref SetReader changed values. - std::string GetReader() const { return m_cStructure->strReader; } - - /// @brief **optional**\n - /// Empty string if not available. - void SetFrom(const std::string& from) - { - strncpy(m_cStructure->strFrom, from.c_str(), sizeof(m_cStructure->strFrom) - 1); - } - - /// @brief To get with @ref SetFrom changed values. - std::string GetFrom() const { return m_cStructure->strFrom; } - - /// @brief **optional**\n - /// Empty string if not available. - void SetProtocol(const std::string& protocol) - { - strncpy(m_cStructure->strProtocol, protocol.c_str(), sizeof(m_cStructure->strProtocol) - 1); - } - - /// @brief To get with @ref SetProtocol changed values. - std::string GetProtocol() const { return m_cStructure->strProtocol; } - ///@} - -private: - PVRDescrambleInfo(const PVR_DESCRAMBLE_INFO* type) : CStructHdl(type) {} - PVRDescrambleInfo(PVR_DESCRAMBLE_INFO* type) : CStructHdl(type) {} -}; -///@} -//------------------------------------------------------------------------------ - -} /* namespace addon */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/EDL.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/EDL.h deleted file mode 100644 index 34c7c41..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/EDL.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../../c-api/addon-instance/pvr/pvr_edl.h" - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" Definitions group 8 - PVR Edit definition list (EDL) -#ifdef __cplusplus - -namespace kodi -{ -namespace addon -{ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry class PVREDLEntry -/// @ingroup cpp_kodi_addon_pvr_Defs_EDLEntry -/// @brief **Edit definition list (EDL) entry**\n -/// Time places and type of related fields. -/// -/// This used within @ref cpp_kodi_addon_pvr_EPGTag "EPG" and -/// @ref cpp_kodi_addon_pvr_Recordings "recordings". -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry_Help -/// -///@{ -class PVREDLEntry : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVREDLEntry() { memset(m_cStructure, 0, sizeof(PVR_EDL_ENTRY)); } - PVREDLEntry(const PVREDLEntry& type) : CStructHdl(type) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry : - /// | Name | Type | Set call | Get call | Usage - /// |------|------|----------|----------|----------- - /// | **Start time** | `int64_t` | @ref PVREDLEntry::SetStart "SetStart" | @ref PVREDLEntry::GetStart "GetStart" | *required to set* - /// | **End time** | `int64_t` | @ref PVREDLEntry::SetEnd "SetEnd" | @ref PVREDLEntry::GetEnd "GetEnd" | *required to set* - /// | **Type** | @ref PVR_EDL_TYPE | @ref PVREDLEntry::SetType "SetType" | @ref PVREDLEntry::GetType "GetType" | *required to set* - /// - - /// @addtogroup cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry - ///@{ - - /// @brief Start time in milliseconds. - void SetStart(int64_t start) { m_cStructure->start = start; } - - /// @brief To get with @ref SetStart() changed values. - int64_t GetStart() const { return m_cStructure->start; } - - /// @brief End time in milliseconds. - void SetEnd(int64_t end) { m_cStructure->end = end; } - - /// @brief To get with @ref SetEnd() changed values. - int64_t GetEnd() const { return m_cStructure->end; } - - /// @brief The with @ref PVR_EDL_TYPE used definition list type. - void SetType(PVR_EDL_TYPE type) { m_cStructure->type = type; } - - /// @brief To get with @ref SetType() changed values. - PVR_EDL_TYPE GetType() const { return m_cStructure->type; } - ///@} - -private: - PVREDLEntry(const PVR_EDL_ENTRY* type) : CStructHdl(type) {} - PVREDLEntry(PVR_EDL_ENTRY* type) : CStructHdl(type) {} -}; -///@} -//------------------------------------------------------------------------------ - -} /* namespace addon */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/EPG.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/EPG.h deleted file mode 100644 index e1fc04f..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/EPG.h +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../../c-api/addon-instance/pvr.h" - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" Definitions group 4 - PVR EPG -#ifdef __cplusplus - -namespace kodi -{ -namespace addon -{ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTag class PVREPGTag -/// @ingroup cpp_kodi_addon_pvr_Defs_epg -/// @brief **PVR add-on EPG data tag**\n -/// Representation of an EPG event. -/// -/// Herewith all EPG related data are saved in one class whereby the data can -/// be exchanged with Kodi, or can also be used on the addon to save there. -/// -/// See @ref cpp_kodi_addon_pvr_EPGTag "EPG methods" about usage. -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_epg_PVREPGTag_Help -/// -///@{ -class PVREPGTag : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVREPGTag() - { - memset(m_cStructure, 0, sizeof(EPG_TAG)); - m_cStructure->iSeriesNumber = EPG_TAG_INVALID_SERIES_EPISODE; - m_cStructure->iEpisodeNumber = EPG_TAG_INVALID_SERIES_EPISODE; - m_cStructure->iEpisodePartNumber = EPG_TAG_INVALID_SERIES_EPISODE; - } - PVREPGTag(const PVREPGTag& epg) : CStructHdl(epg) - { - m_title = epg.m_title; - m_plotOutline = epg.m_plotOutline; - m_plot = epg.m_plot; - m_originalTitle = epg.m_originalTitle; - m_cast = epg.m_cast; - m_director = epg.m_director; - m_writer = epg.m_writer; - m_IMDBNumber = epg.m_IMDBNumber; - m_iconPath = epg.m_iconPath; - m_genreDescription = epg.m_genreDescription; - m_episodeName = epg.m_episodeName; - m_seriesLink = epg.m_seriesLink; - m_firstAired = epg.m_firstAired; - } - /*! \endcond */ - - - /// @defgroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTag_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTag - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag : - /// | Name | Type | Set call | Get call | Usage - /// |------|------|----------|----------|--------- - /// | **Unique broadcast id** | `unsigned int` | @ref PVREPGTag::SetUniqueBroadcastId "SetUniqueBroadcastId" | @ref PVREPGTag::GetUniqueBroadcastId "GetUniqueBroadcastId" | *required to set* - /// | **Unique channel id** | `unsigned int` | @ref PVREPGTag::SetUniqueChannelId "SetUniqueChannelId" | @ref PVREPGTag::GetUniqueChannelId "GetUniqueChannelId" | *required to set* - /// | **Title** | `std::string` | @ref PVREPGTag::SetTitle "SetTitle" | @ref PVREPGTag::GetTitle "GetTitle" | *required to set* - /// | **Start time** | `time_t` | @ref PVREPGTag::SetStartTime "SetStartTime" | @ref PVREPGTag::GetStartTime "GetStartTime" | *required to set* - /// | **End time** | `time_t` | @ref PVREPGTag::SetEndTime "SetEndTime" | @ref PVREPGTag::GetEndTime "GetEndTime" | *required to set* - /// | **Plot outline** | `std::string` | @ref PVREPGTag::SetPlotOutline "SetPlotOutline" | @ref PVREPGTag::GetPlotOutline "GetPlotOutline" | *optional* - /// | **Plot** | `std::string` | @ref PVREPGTag::SetPlot "SetPlot" | @ref PVREPGTag::GetPlot "GetPlot" | *optional* - /// | **Original title** | `std::string` | @ref PVREPGTag::SetOriginalTitle "SetOriginalTitle" | @ref PVREPGTag::GetOriginalTitle "GetOriginalTitle" | *optional* - /// | **Cast** | `std::string` | @ref PVREPGTag::SetCast "SetCast" | @ref PVREPGTag::GetCast "GetCast" | *optional* - /// | **Director** | `std::string` | @ref PVREPGTag::SetDirector "SetDirector" | @ref PVREPGTag::GetDirector "GetDirector" | *optional* - /// | **Writer** | `std::string` | @ref PVREPGTag::SetWriter "SetWriter" | @ref PVREPGTag::GetWriter "GetWriter" | *optional* - /// | **Year** | `int` | @ref PVREPGTag::SetYear "SetYear" | @ref PVREPGTag::GetYear "GetYear" | *optional* - /// | **IMDB number** | `std::string` | @ref PVREPGTag::SetIMDBNumber "SetIMDBNumber" | @ref PVREPGTag::GetIMDBNumber "GetIMDBNumber" | *optional* - /// | **Icon path** | `std::string` | @ref PVREPGTag::SetIconPath "SetIconPath" | @ref PVREPGTag::GetIconPath "GetIconPath" | *optional* - /// | **Genre type** | `int` | @ref PVREPGTag::SetGenreType "SetGenreType" | @ref PVREPGTag::GetGenreType "GetGenreType" | *optional* - /// | **Genre sub type** | `int` | @ref PVREPGTag::SetGenreSubType "SetGenreSubType" | @ref PVREPGTag::GetGenreSubType "GetGenreSubType" | *optional* - /// | **Genre description** | `std::string` | @ref PVREPGTag::SetGenreDescription "SetGenreDescription" | @ref PVREPGTag::GetGenreDescription "GetGenreDescription" | *optional* - /// | **First aired** | `time_t` | @ref PVREPGTag::SetFirstAired "SetFirstAired" | @ref PVREPGTag::GetFirstAired "GetFirstAired" | *optional* - /// | **Parental rating** | `int` | @ref PVREPGTag::SetParentalRating "SetParentalRating" | @ref PVREPGTag::GetParentalRating "GetParentalRating" | *optional* - /// | **Star rating** | `int` | @ref PVREPGTag::SetStarRating "SetStarRating" | @ref PVREPGTag::GetStarRating "GetStarRating" | *optional* - /// | **Series number** | `int` | @ref PVREPGTag::SetSeriesNumber "SetSeriesNumber" | @ref PVREPGTag::GetSeriesNumber "GetSeriesNumber" | *optional* - /// | **Episode number** | `int` | @ref PVREPGTag::SetEpisodeNumber "SetEpisodeNumber" | @ref PVREPGTag::GetEpisodeNumber "GetEpisodeNumber" | *optional* - /// | **Episode part number** | `int` | @ref PVREPGTag::SetEpisodePartNumber "SetEpisodePartNumber" | @ref PVREPGTag::GetEpisodePartNumber "GetEpisodePartNumber" | *optional* - /// | **Episode name** | `std::string` | @ref PVREPGTag::SetEpisodeName "SetEpisodeName" | @ref PVREPGTag::GetEpisodeName "GetEpisodeName" | *optional* - /// | **Flags** | `unsigned int` | @ref PVREPGTag::SetFlags "SetFlags" | @ref PVREPGTag::GetFlags "GetFlags" | *optional* - /// | **Series link** | `std::string` | @ref PVREPGTag::SetSeriesLink "SetSeriesLink" | @ref PVREPGTag::GetSeriesLink "GetSeriesLink" | *optional* - /// - - /// @addtogroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTag - ///@{ - - /// @brief **required**\n - /// Identifier for this event. Event uids must be unique for a channel. Valid uids must be greater than @ref EPG_TAG_INVALID_UID. - void SetUniqueBroadcastId(unsigned int uniqueBroadcastId) - { - m_cStructure->iUniqueBroadcastId = uniqueBroadcastId; - } - - /// @brief To get with @ref SetUniqueBroadcastId changed values. - unsigned int GetUniqueBroadcastId() const { return m_cStructure->iUniqueBroadcastId; } - - /// @brief **required**\n - /// Unique identifier of the channel this event belongs to. - void SetUniqueChannelId(unsigned int uniqueChannelId) - { - m_cStructure->iUniqueChannelId = uniqueChannelId; - } - - /// @brief To get with @ref SetUniqueChannelId changed values - unsigned int GetUniqueChannelId() const { return m_cStructure->iUniqueChannelId; } - - /// @brief **required**\n - /// This event's title. - void SetTitle(const std::string& title) { m_title = title; } - - /// @brief To get with @ref SetTitle changed values. - std::string GetTitle() const { return m_title; } - - /// @brief **required**\n - /// Start time in UTC. - /// - /// Seconds elapsed since 00:00 hours, Jan 1, 1970 UTC. - void SetStartTime(time_t startTime) { m_cStructure->startTime = startTime; } - - /// @brief To get with @ref SetStartTime changed values. - time_t GetStartTime() const { return m_cStructure->startTime; } - - /// @brief **required**\n - /// End time in UTC. - /// - /// Seconds elapsed since 00:00 hours, Jan 1, 1970 UTC. - void SetEndTime(time_t endTime) { m_cStructure->endTime = endTime; } - - /// @brief To get with @ref SetEndTime changed values. - time_t GetEndTime() const { return m_cStructure->endTime; } - - /// @brief **optional**\n - /// Plot outline name. - void SetPlotOutline(const std::string& plotOutline) { m_plotOutline = plotOutline; } - - /// @brief To get with @ref SetPlotOutline changed values. - std::string GetPlotOutline() const { return m_plotOutline; } - - /// @brief **optional**\n - /// Plot name. - void SetPlot(const std::string& plot) { m_plot = plot; } - - /// @brief To get with @ref GetPlot changed values. - std::string GetPlot() const { return m_plot; } - - /// @brief **optional**\n - /// Original title. - void SetOriginalTitle(const std::string& originalTitle) { m_originalTitle = originalTitle; } - - /// @brief To get with @ref SetOriginalTitle changed values - std::string GetOriginalTitle() const { return m_originalTitle; } - - /// @brief **optional**\n - /// Cast name(s). - /// - /// @note Use @ref EPG_STRING_TOKEN_SEPARATOR to separate different persons. - void SetCast(const std::string& cast) { m_cast = cast; } - - /// @brief To get with @ref SetCast changed values - std::string GetCast() const { return m_cast; } - - /// @brief **optional**\n - /// Director name(s). - /// - /// @note Use @ref EPG_STRING_TOKEN_SEPARATOR to separate different persons. - void SetDirector(const std::string& director) { m_director = director; } - - /// @brief To get with @ref SetDirector changed values. - std::string GetDirector() const { return m_director; } - - /// @brief **optional**\n - /// Writer name(s). - /// - /// @note Use @ref EPG_STRING_TOKEN_SEPARATOR to separate different persons. - void SetWriter(const std::string& writer) { m_writer = writer; } - - /// @brief To get with @ref SetDirector changed values - std::string GetWriter() const { return m_writer; } - - /// @brief **optional**\n - /// Year. - void SetYear(int year) { m_cStructure->iYear = year; } - - /// @brief To get with @ref SetYear changed values. - int GetYear() const { return m_cStructure->iYear; } - - /// @brief **optional**\n - /// [IMDB](https://en.wikipedia.org/wiki/IMDb) identification number. - void SetIMDBNumber(const std::string& IMDBNumber) { m_IMDBNumber = IMDBNumber; } - - /// @brief To get with @ref SetIMDBNumber changed values. - std::string GetIMDBNumber() const { return m_IMDBNumber; } - - /// @brief **optional**\n - /// Icon path. - void SetIconPath(const std::string& iconPath) { m_iconPath = iconPath; } - - /// @brief To get with @ref SetIconPath changed values. - std::string GetIconPath() const { return m_iconPath; } - - /// @brief **optional**\n - /// Genre type. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails EPG_EVENT_CONTENTMASK - /// - /// Use @ref EPG_GENRE_USE_STRING if type becomes given by @ref SetGenreDescription. - /// - /// @note If confirmed that backend brings the types in [ETSI EN 300 468](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) - /// conform values, can be @ref EPG_EVENT_CONTENTMASK ignored and to set here - /// with backend value. - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Example 1:** - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVREPGTag tag; - /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MOVIEDRAMA); - /// ~~~~~~~~~~~~~ - /// - /// -------------------------------------------------------------------------- - /// - /// **Example 2** (in case of other, not ETSI EN 300 468 conform genre types): - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVREPGTag tag; - /// tag.SetGenreType(EPG_GENRE_USE_STRING); - /// tag.SetGenreDescription("My special genre name"); // Should use (if possible) kodi::GetLocalizedString(...) to have match user language. - /// ~~~~~~~~~~~~~ - /// - void SetGenreType(int genreType) { m_cStructure->iGenreType = genreType; } - - /// @brief To get with @ref SetGenreType changed values - int GetGenreType() const { return m_cStructure->iGenreType; } - - /// @brief **optional**\n - /// Genre sub type. - /// - /// @copydetails EPG_EVENT_CONTENTMASK - /// - /// Subtypes groups related to set by @ref SetGenreType: - /// | Main genre type | List with available sub genre types - /// |-----------------|----------------------------------------- - /// | @ref EPG_EVENT_CONTENTMASK_UNDEFINED | Nothing, should be 0 - /// | @ref EPG_EVENT_CONTENTMASK_MOVIEDRAMA | @ref EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA - /// | @ref EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS | @ref EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS - /// | @ref EPG_EVENT_CONTENTMASK_SHOW | @ref EPG_EVENT_CONTENTSUBMASK_SHOW - /// | @ref EPG_EVENT_CONTENTMASK_SPORTS | @ref EPG_EVENT_CONTENTSUBMASK_SPORTS - /// | @ref EPG_EVENT_CONTENTMASK_CHILDRENYOUTH | @ref EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH - /// | @ref EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE | @ref EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE - /// | @ref EPG_EVENT_CONTENTMASK_ARTSCULTURE | @ref EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE - /// | @ref EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS | @ref EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS - /// | @ref EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE | @ref EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE - /// | @ref EPG_EVENT_CONTENTMASK_LEISUREHOBBIES | @ref EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES - /// | @ref EPG_EVENT_CONTENTMASK_SPECIAL | @ref EPG_EVENT_CONTENTSUBMASK_SPECIAL - /// | @ref EPG_EVENT_CONTENTMASK_USERDEFINED | Can be defined by you - /// | @ref EPG_GENRE_USE_STRING | **Kodi's own value**, which declares that the type with @ref SetGenreDescription is given. - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVREPGTag tag; - /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE); - /// tag.SetGenreSubType(EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_JAZZ); - /// ~~~~~~~~~~~~~ - /// - void SetGenreSubType(int genreSubType) { m_cStructure->iGenreSubType = genreSubType; } - - /// @brief To get with @ref SetGenreSubType changed values. - int GetGenreSubType() const { return m_cStructure->iGenreSubType; } - - /// @brief **optional**\n genre. Will be used only when genreType == @ref EPG_GENRE_USE_STRING - /// or genreSubType == @ref EPG_GENRE_USE_STRING. - /// - /// Use @ref EPG_STRING_TOKEN_SEPARATOR to separate different genres. - /// - /// In case of other, not [ETSI EN 300 468](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) - /// conform genre types or something special. - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVREPGTag tag; - /// tag.SetGenreType(EPG_GENRE_USE_STRING); - /// tag.SetGenreDescription("Action" + EPG_STRING_TOKEN_SEPARATOR + "Thriller"); - /// ~~~~~~~~~~~~~ - /// - void SetGenreDescription(const std::string& genreDescription) - { - m_genreDescription = genreDescription; - } - - /// @brief To get with @ref SetGenreDescription changed values. - std::string GetGenreDescription() const { return m_genreDescription; } - - /// @brief **optional**\n - /// First aired in UTC. - void SetFirstAired(const std::string& firstAired) { m_firstAired = firstAired; } - - /// @brief To get with @ref SetFirstAired changed values. - std::string GetFirstAired() const { return m_firstAired; } - - /// @brief **optional**\n - /// Parental rating. - void SetParentalRating(int parentalRating) { m_cStructure->iParentalRating = parentalRating; } - - /// @brief To get with @ref SetParentalRatinge changed values. - int GetParentalRating() const { return m_cStructure->iParentalRating; } - - /// @brief **optional**\n - /// Star rating. - void SetStarRating(int starRating) { m_cStructure->iStarRating = starRating; } - - /// @brief To get with @ref SetStarRating changed values. - int GetStarRating() const { return m_cStructure->iStarRating; } - - /// @brief **optional**\n - /// Series number. - void SetSeriesNumber(int seriesNumber) { m_cStructure->iSeriesNumber = seriesNumber; } - - /// @brief To get with @ref SetSeriesNumber changed values. - int GetSeriesNumber() const { return m_cStructure->iSeriesNumber; } - - /// @brief **optional**\n - /// Episode number. - void SetEpisodeNumber(int episodeNumber) { m_cStructure->iEpisodeNumber = episodeNumber; } - - /// @brief To get with @ref SetEpisodeNumber changed values. - int GetEpisodeNumber() const { return m_cStructure->iEpisodeNumber; } - - /// @brief **optional**\n - /// Episode part number. - void SetEpisodePartNumber(int episodePartNumber) - { - m_cStructure->iEpisodePartNumber = episodePartNumber; - } - - /// @brief To get with @ref SetEpisodePartNumber changed values. - int GetEpisodePartNumber() const { return m_cStructure->iEpisodePartNumber; } - - /// @brief **optional**\n - /// Episode name. - void SetEpisodeName(const std::string& episodeName) { m_episodeName = episodeName; } - - /// @brief To get with @ref SetEpisodeName changed values. - std::string GetEpisodeName() const { return m_episodeName; } - - /// @brief **optional**\n - /// Bit field of independent flags associated with the EPG entry. - /// - /// See @ref cpp_kodi_addon_pvr_Defs_epg_EPG_TAG_FLAG for available bit flags. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_epg_EPG_TAG_FLAG - /// - void SetFlags(unsigned int flags) { m_cStructure->iFlags = flags; } - - /// @brief To get with @ref SetFlags changed values. - unsigned int GetFlags() const { return m_cStructure->iFlags; } - - /// @brief **optional**\n - /// Series link for this event. - void SetSeriesLink(const std::string& seriesLink) { m_seriesLink = seriesLink; } - - /// @brief To get with @ref SetSeriesLink changed values. - std::string GetSeriesLink() const { return m_seriesLink; } - - ///@} - - // Internal used, as this have own memory for strings and to translate them to "C" - EPG_TAG* GetTag() const - { - m_cStructure->strTitle = m_title.c_str(); - m_cStructure->strPlotOutline = m_plotOutline.c_str(); - m_cStructure->strPlot = m_plot.c_str(); - m_cStructure->strOriginalTitle = m_originalTitle.c_str(); - m_cStructure->strCast = m_cast.c_str(); - m_cStructure->strDirector = m_director.c_str(); - m_cStructure->strWriter = m_writer.c_str(); - m_cStructure->strIMDBNumber = m_IMDBNumber.c_str(); - m_cStructure->strIconPath = m_iconPath.c_str(); - m_cStructure->strGenreDescription = m_genreDescription.c_str(); - m_cStructure->strEpisodeName = m_episodeName.c_str(); - m_cStructure->strSeriesLink = m_seriesLink.c_str(); - m_cStructure->strFirstAired = m_firstAired.c_str(); - - return m_cStructure; - } - -private: - PVREPGTag(const EPG_TAG* epg) : CStructHdl(epg) { SetData(epg); } - PVREPGTag(EPG_TAG* epg) : CStructHdl(epg) { SetData(epg); } - - const PVREPGTag& operator=(const PVREPGTag& right); - const PVREPGTag& operator=(const EPG_TAG& right); - operator EPG_TAG*(); - - std::string m_title; - std::string m_plotOutline; - std::string m_plot; - std::string m_originalTitle; - std::string m_cast; - std::string m_director; - std::string m_writer; - std::string m_IMDBNumber; - std::string m_episodeName; - std::string m_iconPath; - std::string m_seriesLink; - std::string m_genreDescription; - std::string m_firstAired; - - void SetData(const EPG_TAG* tag) - { - m_title = tag->strTitle == nullptr ? "" : tag->strTitle; - m_plotOutline = tag->strPlotOutline == nullptr ? "" : tag->strPlotOutline; - m_plot = tag->strPlot == nullptr ? "" : tag->strPlot; - m_originalTitle = tag->strOriginalTitle == nullptr ? "" : tag->strOriginalTitle; - m_cast = tag->strCast == nullptr ? "" : tag->strCast; - m_director = tag->strDirector == nullptr ? "" : tag->strDirector; - m_writer = tag->strWriter == nullptr ? "" : tag->strWriter; - m_IMDBNumber = tag->strIMDBNumber == nullptr ? "" : tag->strIMDBNumber; - m_iconPath = tag->strIconPath == nullptr ? "" : tag->strIconPath; - m_genreDescription = tag->strGenreDescription == nullptr ? "" : tag->strGenreDescription; - m_episodeName = tag->strEpisodeName == nullptr ? "" : tag->strEpisodeName; - m_seriesLink = tag->strSeriesLink == nullptr ? "" : tag->strSeriesLink; - m_firstAired = tag->strFirstAired == nullptr ? "" : tag->strFirstAired; - } -}; -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTagsResultSet class PVREPGTagsResultSet -/// @ingroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTag -/// @brief **PVR add-on EPG entry transfer class**\n -/// To transfer the content of @ref kodi::addon::CInstancePVRClient::GetEPGForChannel(). -/// -/// @note This becomes only be used on addon call above, not usable outside on -/// addon itself. -///@{ -class PVREPGTagsResultSet -{ -public: - /*! \cond PRIVATE */ - PVREPGTagsResultSet() = delete; - PVREPGTagsResultSet(const AddonInstance_PVR* instance, ADDON_HANDLE handle) - : m_instance(instance), m_handle(handle) - { - } - /*! \endcond */ - - /// @addtogroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTagsResultSet - ///@{ - - /// @brief To add and give content from addon to Kodi on related call. - /// - /// @param[in] tag The to transferred data. - void Add(const kodi::addon::PVREPGTag& tag) - { - m_instance->toKodi->TransferEpgEntry(m_instance->toKodi->kodiInstance, m_handle, tag.GetTag()); - } - - ///@} - -private: - const AddonInstance_PVR* m_instance = nullptr; - const ADDON_HANDLE m_handle; -}; -///@} -//------------------------------------------------------------------------------ - -} /* namespace addon */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/General.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/General.h deleted file mode 100644 index c7977c2..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/General.h +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../../c-api/addon-instance/pvr/pvr_general.h" - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" Definitions group 1 - General PVR -#ifdef __cplusplus - -namespace kodi -{ -namespace addon -{ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_PVRTypeIntValue class PVRTypeIntValue -/// @ingroup cpp_kodi_addon_pvr_Defs_General -/// @brief **PVR add-on type value**\n -/// Representation of a `` event related value. -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help -/// -///@{ -class PVRTypeIntValue : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVRTypeIntValue(const PVRTypeIntValue& data) : CStructHdl(data) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_PVRTypeIntValue - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue : - /// | Name | Type | Set call | Get call - /// |------|------|----------|---------- - /// | **Value** | `int` | @ref PVRTypeIntValue::SetValue "SetValue" | @ref PVRTypeIntValue::GetValue "GetValue" - /// | **Description** | `std::string` | @ref PVRTypeIntValue::SetDescription "SetDescription" | @ref PVRTypeIntValue::GetDescription "GetDescription" - /// - /// @remark Further can there be used his class constructor to set values. - - /// @addtogroup cpp_kodi_addon_pvr_Defs_PVRTypeIntValue - ///@{ - - /// @brief Default class constructor. - /// - /// @note Values must be set afterwards. - PVRTypeIntValue() = default; - - /// @brief Class constructor with integrated value set. - /// - /// @param[in] value Type identification value - /// @param[in] description Type description text - PVRTypeIntValue(int value, const std::string& description) - { - SetValue(value); - SetDescription(description); - } - - /// @brief To set with the identification value. - void SetValue(int value) { m_cStructure->iValue = value; } - - /// @brief To get with the identification value. - int GetValue() const { return m_cStructure->iValue; } - - /// @brief To set with the description text of the value. - void SetDescription(const std::string& description) - { - strncpy(m_cStructure->strDescription, description.c_str(), - sizeof(m_cStructure->strDescription) - 1); - } - - /// @brief To get with the description text of the value. - std::string GetDescription() const { return m_cStructure->strDescription; } - ///@} - -private: - PVRTypeIntValue(const PVR_ATTRIBUTE_INT_VALUE* data) : CStructHdl(data) {} - PVRTypeIntValue(PVR_ATTRIBUTE_INT_VALUE* data) : CStructHdl(data) {} -}; -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_PVRCapabilities class PVRCapabilities -/// @ingroup cpp_kodi_addon_pvr_Defs_General -/// @brief **PVR add-on capabilities**\n -/// This class is needed to tell Kodi which options are supported on the addon. -/// -/// If a capability is set to **true**, then the corresponding methods from -/// @ref cpp_kodi_addon_pvr "kodi::addon::CInstancePVRClient" need to be -/// implemented. -/// -/// As default them all set to **false**. -/// -/// Used on @ref kodi::addon::CInstancePVRClient::GetCapabilities(). -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_PVRCapabilities_Help -/// -///@{ -class PVRCapabilities -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - explicit PVRCapabilities() = delete; - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_PVRCapabilities_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_PVRCapabilities - /// ---------------------------------------------------------------------------- - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_PVRCapabilities : - /// | Name | Type | Set call | Get call - /// |------|------|----------|---------- - /// | **Supports EPG** | `boolean` | @ref PVRCapabilities::SetSupportsEPG "SetSupportsEPG" | @ref PVRCapabilities::GetSupportsEPG "GetSupportsEPG" - /// | **Supports EPG EDL** | `boolean` | @ref PVRCapabilities::SetSupportsEPGEdl "SetSupportsEPGEdl" | @ref PVRCapabilities::GetSupportsEPGEdl "GetSupportsEPGEdl" - /// | **Supports TV** | `boolean` | @ref PVRCapabilities::SetSupportsTV "SetSupportsTV" | @ref PVRCapabilities::GetSupportsTV "GetSupportsTV" - /// | **Supports radio** | `boolean` | @ref PVRCapabilities::SetSupportsRadio "SetSupportsRadio" | @ref PVRCapabilities::GetSupportsRadio "GetSupportsRadio" - /// | **Supports recordings** | `boolean` | @ref PVRCapabilities::SetSupportsRecordings "SetSupportsRecordings" | @ref PVRCapabilities::GetSupportsRecordings "GetSupportsRecordings" - /// | **Supports recordings undelete** | `boolean` | @ref PVRCapabilities::SetSupportsRecordingsUndelete "SetSupportsRecordingsUndelete" | @ref PVRCapabilities::GetSupportsRecordingsUndelete "SetSupportsRecordingsUndelete" - /// | **Supports timers** | `boolean` | @ref PVRCapabilities::SetSupportsTimers "SetSupportsTimers" | @ref PVRCapabilities::GetSupportsTimers "GetSupportsTimers" - /// | **Supports channel groups** | `boolean` | @ref PVRCapabilities::SetSupportsChannelGroups "SetSupportsChannelGroups" | @ref PVRCapabilities::GetSupportsChannelGroups "GetSupportsChannelGroups" - /// | **Supports channel scan** | `boolean` | @ref PVRCapabilities::SetSupportsChannelScan "SetSupportsChannelScan" | @ref PVRCapabilities::GetSupportsChannelScan "GetSupportsChannelScan" - /// | **Supports channel settings** | `boolean` | @ref PVRCapabilities::SetSupportsChannelSettings "SetSupportsChannelSettings" | @ref PVRCapabilities::GetSupportsChannelSettings "GetSupportsChannelSettings" - /// | **Handles input stream** | `boolean` | @ref PVRCapabilities::SetHandlesInputStream "SetHandlesInputStream" | @ref PVRCapabilities::GetHandlesInputStream "GetHandlesInputStream" - /// | **Handles demuxing** | `boolean` | @ref PVRCapabilities::SetHandlesDemuxing "SetHandlesDemuxing" | @ref PVRCapabilities::GetHandlesDemuxing "GetHandlesDemuxing" - /// | **Supports recording play count** | `boolean` | @ref PVRCapabilities::SetSupportsRecordingPlayCount "SetSupportsRecordingPlayCount" | @ref PVRCapabilities::GetSupportsRecordingPlayCount "GetSupportsRecordingPlayCount" - /// | **Supports last played position** | `boolean` | @ref PVRCapabilities::SetSupportsLastPlayedPosition "SetSupportsLastPlayedPosition" | @ref PVRCapabilities::GetSupportsLastPlayedPosition "GetSupportsLastPlayedPosition" - /// | **Supports recording EDL** | `boolean` | @ref PVRCapabilities::SetSupportsRecordingEdl "SetSupportsRecordingEdl" | @ref PVRCapabilities::GetSupportsRecordingEdl "GetSupportsRecordingEdl" - /// | **Supports recordings rename** | `boolean` | @ref PVRCapabilities::SetSupportsRecordingsRename "SetSupportsRecordingsRename" | @ref PVRCapabilities::GetSupportsRecordingsRename "GetSupportsRecordingsRename" - /// | **Supports recordings lifetime change** | `boolean` | @ref PVRCapabilities::SetSupportsRecordingsLifetimeChange "SetSupportsRecordingsLifetimeChange" | @ref PVRCapabilities::GetSupportsRecordingsLifetimeChange "GetSupportsRecordingsLifetimeChange" - /// | **Supports descramble info** | `boolean` | @ref PVRCapabilities::SetSupportsDescrambleInfo "SetSupportsDescrambleInfo" | @ref PVRCapabilities::GetSupportsDescrambleInfo "GetSupportsDescrambleInfo" - /// | **Supports async EPG transfer** | `boolean` | @ref PVRCapabilities::SetSupportsAsyncEPGTransfer "SetSupportsAsyncEPGTransfer" | @ref PVRCapabilities::GetSupportsAsyncEPGTransfer "GetSupportsAsyncEPGTransfer" - /// | **Supports recording size** | `boolean` | @ref PVRCapabilities::SetSupportsRecordingSize "SetSupportsRecordingSize" | @ref PVRCapabilities::GetSupportsRecordingSize "GetSupportsRecordingSize" - /// | **Recordings lifetime values** | @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue "PVRTypeIntValue" | @ref PVRCapabilities::SetRecordingsLifetimeValues "SetRecordingsLifetimeValues" | @ref PVRCapabilities::GetRecordingsLifetimeValues "GetRecordingsLifetimeValues" - /// - /// @warning This class can not be used outside of @ref kodi::addon::CInstancePVRClient::GetCapabilities() - /// - - /// @addtogroup cpp_kodi_addon_pvr_Defs_PVRCapabilities - ///@{ - - /// @brief Set **true** if the add-on provides EPG information. - void SetSupportsEPG(bool supportsEPG) { m_capabilities->bSupportsEPG = supportsEPG; } - - /// @brief To get with @ref SetSupportsEPG changed values. - bool GetSupportsEPG() const { return m_capabilities->bSupportsEPG; } - - /// @brief Set **true** if the backend supports retrieving an edit decision - /// list for an EPG tag. - void SetSupportsEPGEdl(bool supportsEPGEdl) { m_capabilities->bSupportsEPGEdl = supportsEPGEdl; } - - /// @brief To get with @ref SetSupportsEPGEdl changed values. - bool GetSupportsEPGEdl() const { return m_capabilities->bSupportsEPGEdl; } - - /// @brief Set **true** if this add-on provides TV channels. - void SetSupportsTV(bool supportsTV) { m_capabilities->bSupportsTV = supportsTV; } - - /// @brief To get with @ref SetSupportsTV changed values. - bool GetSupportsTV() const { return m_capabilities->bSupportsTV; } - - /// @brief Set **true** if this add-on provides TV channels. - void SetSupportsRadio(bool supportsRadio) { m_capabilities->bSupportsRadio = supportsRadio; } - - /// @brief To get with @ref SetSupportsRadio changed values. - bool GetSupportsRadio() const { return m_capabilities->bSupportsRadio; } - - /// @brief **true** if this add-on supports playback of recordings stored on - /// the backend. - void SetSupportsRecordings(bool supportsRecordings) - { - m_capabilities->bSupportsRecordings = supportsRecordings; - } - - /// @brief To get with @ref SetSupportsRecordings changed values. - bool GetSupportsRecordings() const { return m_capabilities->bSupportsRecordings; } - - /// @brief Set **true** if this add-on supports undelete of recordings stored - /// on the backend. - void SetSupportsRecordingsUndelete(bool supportsRecordingsUndelete) - { - m_capabilities->bSupportsRecordingsUndelete = supportsRecordingsUndelete; - } - - /// @brief To get with @ref SetSupportsRecordings changed values. - bool GetSupportsRecordingsUndelete() const { return m_capabilities->bSupportsRecordingsUndelete; } - - /// @brief Set **true** if this add-on supports the creation and editing of - /// timers. - void SetSupportsTimers(bool supportsTimers) { m_capabilities->bSupportsTimers = supportsTimers; } - - /// @brief To get with @ref SetSupportsTimers changed values. - bool GetSupportsTimers() const { return m_capabilities->bSupportsTimers; } - - /// @brief Set **true** if this add-on supports channel groups. - /// - /// It use the following functions: - /// - @ref kodi::addon::CInstancePVRClient::GetChannelGroupsAmount() - /// - @ref kodi::addon::CInstancePVRClient::GetChannelGroups() - /// - @ref kodi::addon::CInstancePVRClient::GetChannelGroupMembers() - void SetSupportsChannelGroups(bool supportsChannelGroups) - { - m_capabilities->bSupportsChannelGroups = supportsChannelGroups; - } - - /// @brief To get with @ref SetSupportsChannelGroups changed values. - bool GetSupportsChannelGroups() const { return m_capabilities->bSupportsChannelGroups; } - - /// @brief Set **true** if this add-on support scanning for new channels on - /// the backend. - /// - /// It use the following function: - /// - @ref kodi::addon::CInstancePVRClient::OpenDialogChannelScan() - void SetSupportsChannelScan(bool supportsChannelScan) - { - m_capabilities->bSupportsChannelScan = supportsChannelScan; - } - - /// @brief To get with @ref SetSupportsChannelScan changed values. - bool GetSupportsChannelScan() const { return m_capabilities->bSupportsChannelScan; } - - /// @brief Set **true** if this add-on supports channel edit. - /// - /// It use the following functions: - /// - @ref kodi::addon::CInstancePVRClient::DeleteChannel() - /// - @ref kodi::addon::CInstancePVRClient::RenameChannel() - /// - @ref kodi::addon::CInstancePVRClient::OpenDialogChannelSettings() - /// - @ref kodi::addon::CInstancePVRClient::OpenDialogChannelAdd() - void SetSupportsChannelSettings(bool supportsChannelSettings) - { - m_capabilities->bSupportsChannelSettings = supportsChannelSettings; - } - - /// @brief To get with @ref SetSupportsChannelSettings changed values. - bool GetSupportsChannelSettings() const { return m_capabilities->bSupportsChannelSettings; } - - /// @brief Set **true** if this add-on provides an input stream. false if Kodi - /// handles the stream. - void SetHandlesInputStream(bool handlesInputStream) - { - m_capabilities->bHandlesInputStream = handlesInputStream; - } - - /// @brief To get with @ref SetHandlesInputStream changed values. - bool GetHandlesInputStream() const { return m_capabilities->bHandlesInputStream; } - - /// @brief Set **true** if this add-on demultiplexes packets. - void SetHandlesDemuxing(bool handlesDemuxing) - { - m_capabilities->bHandlesDemuxing = handlesDemuxing; - } - - /// @brief To get with @ref SetHandlesDemuxing changed values. - bool GetHandlesDemuxing() const { return m_capabilities->bHandlesDemuxing; } - - /// @brief Set **true** if the backend supports play count for recordings. - void SetSupportsRecordingPlayCount(bool supportsRecordingPlayCount) - { - m_capabilities->bSupportsRecordingPlayCount = supportsRecordingPlayCount; - } - - /// @brief To get with @ref SetSupportsRecordingPlayCount changed values. - bool GetSupportsRecordingPlayCount() const { return m_capabilities->bSupportsRecordingPlayCount; } - - /// @brief Set **true** if the backend supports store/retrieve of last played - /// position for recordings. - void SetSupportsLastPlayedPosition(bool supportsLastPlayedPosition) - { - m_capabilities->bSupportsLastPlayedPosition = supportsLastPlayedPosition; - } - - /// @brief To get with @ref SetSupportsLastPlayedPosition changed values. - bool GetSupportsLastPlayedPosition() const { return m_capabilities->bSupportsLastPlayedPosition; } - - /// @brief Set **true** if the backend supports retrieving an edit decision - /// list for recordings. - void SetSupportsRecordingEdl(bool supportsRecordingEdl) - { - m_capabilities->bSupportsRecordingEdl = supportsRecordingEdl; - } - - /// @brief To get with @ref SetSupportsRecordingEdl changed values. - bool GetSupportsRecordingEdl() const { return m_capabilities->bSupportsRecordingEdl; } - - /// @brief Set **true** if the backend supports renaming recordings. - void SetSupportsRecordingsRename(bool supportsRecordingsRename) - { - m_capabilities->bSupportsRecordingsRename = supportsRecordingsRename; - } - - /// @brief To get with @ref SetSupportsRecordingsRename changed values. - bool GetSupportsRecordingsRename() const { return m_capabilities->bSupportsRecordingsRename; } - - /// @brief Set **true** if the backend supports changing lifetime for - /// recordings. - void SetSupportsRecordingsLifetimeChange(bool supportsRecordingsLifetimeChange) - { - m_capabilities->bSupportsRecordingsLifetimeChange = supportsRecordingsLifetimeChange; - } - - /// @brief To get with @ref SetSupportsRecordingsLifetimeChange changed - /// values. - bool GetSupportsRecordingsLifetimeChange() const - { - return m_capabilities->bSupportsRecordingsLifetimeChange; - } - - /// @brief Set **true** if the backend supports descramble information for - /// playing channels. - void SetSupportsDescrambleInfo(bool supportsDescrambleInfo) - { - m_capabilities->bSupportsDescrambleInfo = supportsDescrambleInfo; - } - - /// @brief To get with @ref SetSupportsDescrambleInfo changed values. - bool GetSupportsDescrambleInfo() const { return m_capabilities->bSupportsDescrambleInfo; } - - /// @brief Set **true** if this addon-on supports asynchronous transfer of epg - /// events to Kodi using the callback function - /// @ref kodi::addon::CInstancePVRClient::EpgEventStateChange(). - void SetSupportsAsyncEPGTransfer(bool supportsAsyncEPGTransfer) - { - m_capabilities->bSupportsAsyncEPGTransfer = supportsAsyncEPGTransfer; - } - - /// @brief To get with @ref SetSupportsAsyncEPGTransfer changed values. - bool GetSupportsAsyncEPGTransfer() const { return m_capabilities->bSupportsAsyncEPGTransfer; } - - /// @brief Set **true** if this addon-on supports retrieving size of recordings. - void SetSupportsRecordingSize(bool supportsRecordingSize) - { - m_capabilities->bSupportsRecordingSize = supportsRecordingSize; - } - - /// @brief To get with @ref SetSupportsRecordingSize changed values. - bool GetSupportsRecordingSize() const { return m_capabilities->bSupportsRecordingSize; } - - /// @brief **optional**\n - /// Set array containing the possible values for @ref PVRRecording::SetLifetime(). - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help - void SetRecordingsLifetimeValues( - const std::vector& recordingsLifetimeValues) - { - m_capabilities->iRecordingsLifetimesSize = 0; - for (unsigned int i = 0; i < recordingsLifetimeValues.size() && - i < sizeof(m_capabilities->recordingsLifetimeValues); - ++i) - { - m_capabilities->recordingsLifetimeValues[i].iValue = - recordingsLifetimeValues[i].GetCStructure()->iValue; - strncpy(m_capabilities->recordingsLifetimeValues[i].strDescription, - recordingsLifetimeValues[i].GetCStructure()->strDescription, - sizeof(m_capabilities->recordingsLifetimeValues[i].strDescription) - 1); - ++m_capabilities->iRecordingsLifetimesSize; - } - } - - /// @brief To get with @ref SetRecordingsLifetimeValues changed values. - std::vector GetRecordingsLifetimeValues() const - { - std::vector recordingsLifetimeValues; - for (unsigned int i = 0; i < m_capabilities->iRecordingsLifetimesSize; ++i) - recordingsLifetimeValues.emplace_back( - m_capabilities->recordingsLifetimeValues[i].iValue, - m_capabilities->recordingsLifetimeValues[i].strDescription); - return recordingsLifetimeValues; - } - ///@} - -private: - PVRCapabilities(PVR_ADDON_CAPABILITIES* capabilities) : m_capabilities(capabilities) {} - - PVR_ADDON_CAPABILITIES* m_capabilities; -}; -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_General_Inputstream_PVRStreamProperty class PVRStreamProperty -/// @ingroup cpp_kodi_addon_pvr_Defs_General_Inputstream -/// @brief **PVR stream property value handler**\n -/// To set for Kodi wanted stream properties. -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_General_Inputstream_PVRStreamProperty_Help -/// -///--------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// ... -/// -/// PVR_ERROR CMyPVRInstance::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, -/// std::vector& properties) -/// { -/// ... -/// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM, "inputstream.adaptive"); -/// return PVR_ERROR_NO_ERROR; -/// } -/// -/// ... -/// ~~~~~~~~~~~~~ -/// -/// -/// **Example 2:** -/// ~~~~~~~~~~~~~{.cpp} -/// ... -/// -/// PVR_ERROR CMyPVRInstance::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, -/// std::vector& properties) -/// { -/// ... -/// kodi::addon::PVRStreamProperty property; -/// property.SetName(PVR_STREAM_PROPERTY_INPUTSTREAM); -/// property.SetValue("inputstream.adaptive"); -/// properties.emplace_back(property); -/// return PVR_ERROR_NO_ERROR; -/// } -/// -/// ... -/// ~~~~~~~~~~~~~ -/// -///@{ -class PVRStreamProperty : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVRStreamProperty(const PVRStreamProperty& data) : CStructHdl(data) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_General_Inputstream_PVRStreamProperty_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_General_Inputstream_PVRStreamProperty - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_General_Inputstream_PVRStreamProperty : - /// | Name | Type | Set call | Get call - /// |------|------|----------|---------- - /// | **Name** | `int` | @ref PVRStreamProperty::SetValue "SetName" | @ref PVRStreamProperty::GetName "GetName" - /// | **Value** | `std::string` | @ref PVRStreamProperty::SetValue "SetValue" | @ref PVRStreamProperty::GetValue "GetValue" - /// - /// @remark Further can there be used his class constructor to set values. - - /// @addtogroup cpp_kodi_addon_pvr_Defs_General_Inputstream_PVRStreamProperty - ///@{ - - /// @brief Default class constructor. - /// - /// @note Values must be set afterwards. - PVRStreamProperty() = default; - - /// @brief Class constructor with integrated value set. - /// - /// @param[in] name Type identification - /// @param[in] value Type used property value - PVRStreamProperty(const std::string& name, const std::string& value) - { - SetName(name); - SetValue(value); - } - - /// @brief To set with the identification name. - void SetName(const std::string& name) - { - strncpy(m_cStructure->strName, name.c_str(), sizeof(m_cStructure->strName) - 1); - } - - /// @brief To get with the identification name. - std::string GetName() const { return m_cStructure->strName; } - - /// @brief To set with the used property value. - void SetValue(const std::string& value) - { - strncpy(m_cStructure->strValue, value.c_str(), sizeof(m_cStructure->strValue) - 1); - } - - /// @brief To get with the used property value. - std::string GetValue() const { return m_cStructure->strValue; } - ///@} - -private: - PVRStreamProperty(const PVR_NAMED_VALUE* data) : CStructHdl(data) {} - PVRStreamProperty(PVR_NAMED_VALUE* data) : CStructHdl(data) {} -}; -///@} -//------------------------------------------------------------------------------ - -} /* namespace addon */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/MenuHook.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/MenuHook.h deleted file mode 100644 index 053a4d5..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/MenuHook.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../../c-api/addon-instance/pvr/pvr_menu_hook.h" - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" Definitions group 7 - Menu hook -#ifdef __cplusplus - -namespace kodi -{ -namespace addon -{ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook class PVRMenuhook -/// @ingroup cpp_kodi_addon_pvr_Defs_Menuhook -/// @brief **Context menu hook**\n -/// Menu hooks that are available in the context menus while playing a stream via this add-on. -/// And in the Live TV settings dialog. -/// -/// Possible menu's given to Kodi. -/// -/// This can be becomes used on this, if @ref kodi::addon::CInstancePVRClient::AddMenuHook() -/// was set to related type: -/// - @ref kodi::addon::CInstancePVRClient::CallSettingsMenuHook() -/// - @ref kodi::addon::CInstancePVRClient::CallChannelMenuHook() -/// - @ref kodi::addon::CInstancePVRClient::CallEPGMenuHook() -/// - @ref kodi::addon::CInstancePVRClient::CallRecordingMenuHook() -/// - @ref kodi::addon::CInstancePVRClient::CallTimerMenuHook() -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help -/// -///@{ -class PVRMenuhook : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /// @addtogroup cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook - /// @brief Optional class constructor with value set. - /// - /// @param[in] hookId This hook's identifier - /// @param[in] localizedStringId Localized string identifier - /// @param[in] category Category of menu hook, defined with @ref PVR_MENUHOOK_CAT - /// - /// - /// -------------------------------------------------------------------------- - /// - /// Example: - /// ~~~~~~~~~~~~~{.cpp} - /// AddMenuHook(kodi::addon::PVRMenuhook(1, 30001, PVR_MENUHOOK_CHANNEL)); - /// ~~~~~~~~~~~~~ - /// - PVRMenuhook(unsigned int hookId, unsigned int localizedStringId, PVR_MENUHOOK_CAT category) - { - m_cStructure->iHookId = hookId; - m_cStructure->iLocalizedStringId = localizedStringId; - m_cStructure->category = category; - } - - /*! \cond PRIVATE */ - PVRMenuhook() - { - m_cStructure->iHookId = 0; - m_cStructure->iLocalizedStringId = 0; - m_cStructure->category = PVR_MENUHOOK_UNKNOWN; - } - PVRMenuhook(const PVRMenuhook& data) : CStructHdl(data) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook : - /// | Name | Type | Set call | Get call | Usage - /// |------|------|----------|----------|----------- - /// | **This hook's identifier** | `unsigned int` | @ref PVRMenuhook::SetHookId "SetHookId" | @ref PVRMenuhook::GetHookId "GetHookId" | *required to set* - /// | **Localized string Identifier** | `unsigned int` | @ref PVRMenuhook::SetLocalizedStringId "SetLocalizedStringId" | @ref PVRMenuhook::GetLocalizedStringId "GetLocalizedStringId" | *required to set* - /// | **Category of menu hook** | @ref PVR_MENUHOOK_CAT | @ref PVRMenuhook::SetCategory "SetCategory" | @ref PVRMenuhook::GetCategory "GetCategory" | *required to set* - - /// @addtogroup cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook - ///@{ - - /// @brief **required**\n - /// This hook's identifier. - void SetHookId(unsigned int hookId) { m_cStructure->iHookId = hookId; } - - /// @brief To get with @ref SetHookId() changed values. - unsigned int GetHookId() const { return m_cStructure->iHookId; } - - /// @brief **required**\n - /// The id of the label for this hook in @ref kodi::GetLocalizedString(). - void SetLocalizedStringId(unsigned int localizedStringId) - { - m_cStructure->iLocalizedStringId = localizedStringId; - } - - /// @brief To get with @ref SetLocalizedStringId() changed values. - unsigned int GetLocalizedStringId() const { return m_cStructure->iLocalizedStringId; } - - /// @brief **required**\n - /// Category of menu hook. - void SetCategory(PVR_MENUHOOK_CAT category) { m_cStructure->category = category; } - - /// @brief To get with @ref SetCategory() changed values. - PVR_MENUHOOK_CAT GetCategory() const { return m_cStructure->category; } - ///@} - -private: - PVRMenuhook(const PVR_MENUHOOK* data) : CStructHdl(data) {} - PVRMenuhook(PVR_MENUHOOK* data) : CStructHdl(data) {} -}; -///@} -//------------------------------------------------------------------------------ - -} /* namespace addon */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Recordings.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Recordings.h deleted file mode 100644 index 24ecf11..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Recordings.h +++ /dev/null @@ -1,520 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../../c-api/addon-instance/pvr.h" - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" Definitions group 5 - PVR recordings -#ifdef __cplusplus - -namespace kodi -{ -namespace addon -{ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording class PVRRecording -/// @ingroup cpp_kodi_addon_pvr_Defs_Recording -/// @brief **Data structure with available recordings data**\n -/// With this, recordings related data are transferred between addon and Kodi -/// and can also be used by the addon itself. -/// -/// The related values here are automatically initiated to defaults and need -/// only be set if supported and used. -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_Recording_PVRRecording_Help -/// -///@{ -class PVRRecording : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVRRecording() - { - m_cStructure->iSeriesNumber = PVR_RECORDING_INVALID_SERIES_EPISODE; - m_cStructure->iEpisodeNumber = PVR_RECORDING_INVALID_SERIES_EPISODE; - m_cStructure->recordingTime = 0; - m_cStructure->iDuration = PVR_RECORDING_VALUE_NOT_AVAILABLE; - m_cStructure->iPriority = PVR_RECORDING_VALUE_NOT_AVAILABLE; - m_cStructure->iLifetime = PVR_RECORDING_VALUE_NOT_AVAILABLE; - m_cStructure->iGenreType = PVR_RECORDING_VALUE_NOT_AVAILABLE; - m_cStructure->iGenreSubType = PVR_RECORDING_VALUE_NOT_AVAILABLE; - m_cStructure->iPlayCount = PVR_RECORDING_VALUE_NOT_AVAILABLE; - m_cStructure->iLastPlayedPosition = PVR_RECORDING_VALUE_NOT_AVAILABLE; - m_cStructure->bIsDeleted = false; - m_cStructure->iEpgEventId = 0; - m_cStructure->iChannelUid = PVR_RECORDING_VALUE_NOT_AVAILABLE; - m_cStructure->channelType = PVR_RECORDING_CHANNEL_TYPE_UNKNOWN; - m_cStructure->iFlags = 0; - m_cStructure->sizeInBytes = PVR_RECORDING_VALUE_NOT_AVAILABLE; - } - PVRRecording(const PVRRecording& recording) : CStructHdl(recording) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording : - /// | Name | Type | Set call | Get call | Usage - /// |------|------|----------|----------|----------- - /// | **Recording id** | `std::string` | @ref PVRRecording::SetRecordingId "SetRecordingId" | @ref PVRRecording::GetRecordingId "GetRecordingId" | *required to set* - /// | **Title** | `std::string` | @ref PVRRecording::SetTitle "SetTitle" | @ref PVRRecording::GetTitle "GetTitle" | *required to set* - /// | **Episode name** | `std::string` | @ref PVRRecording::SetEpisodeName "SetEpisodeName" | @ref PVRRecording::GetEpisodeName "GetEpisodeName" | *optional* - /// | **Series number** | `int` | @ref PVRRecording::SetSeriesNumber "SetSeriesNumber" | @ref PVRRecording::GetSeriesNumber "GetSeriesNumber" | *optional* - /// | **Episode number** | `int` | @ref PVRRecording::SetEpisodeNumber "SetEpisodeNumber" | @ref PVRRecording::GetEpisodeNumber "GetEpisodeNumber" | *optional* - /// | **Year** | `int` | @ref PVRRecording::SetYear "SetYear" | @ref PVRRecording::GetYear "GetYear" | *optional* - /// | **Directory** | `std::string` | @ref PVRRecording::SetDirectory "SetDirectory" | @ref PVRRecording::GetDirectory "GetDirectory" | *optional* - /// | **Plot outline** | `std::string` | @ref PVRRecording::SetPlotOutline "SetPlotOutline" | @ref PVRRecording::GetPlotOutline "GetPlotOutline" | *optional* - /// | **Plot** | `std::string` | @ref PVRRecording::SetPlot "SetPlot" | @ref PVRRecording::GetPlot "GetPlot" | *optional* - /// | **Genre description** | `std::string` | @ref PVRRecording::SetGenreDescription "SetGenreDescription" | @ref PVRRecording::GetGenreDescription "GetGenreDescription" | *optional* - /// | **Channel name** | `std::string` | @ref PVRRecording::SetChannelName "SetChannelName" | @ref PVRRecording::GetChannelName "GetChannelName" | *optional* - /// | **Icon path** | `std::string` | @ref PVRRecording::SetIconPath "SetIconPath" | @ref PVRRecording::GetIconPath "GetIconPath" | *optional* - /// | **Thumbnail path** | `std::string` | @ref PVRRecording::SetThumbnailPath "SetThumbnailPath" | @ref PVRRecording::GetThumbnailPath "GetThumbnailPath" | *optional* - /// | **Fanart path** | `std::string` | @ref PVRRecording::SetFanartPath "SetFanartPath" | @ref PVRRecording::GetFanartPath "GetFanartPath" | *optional* - /// | **Recording time** | `time_t` | @ref PVRRecording::SetRecordingTime "SetRecordingTime" | @ref PVRRecording::GetRecordingTime "GetRecordingTime" | *optional* - /// | **Duration** | `int` | @ref PVRRecording::SetDuration "SetDuration" | @ref PVRRecording::GetDuration "GetDuration" | *optional* - /// | **Priority** | `int` | @ref PVRRecording::SetPriority "SetPriority" | @ref PVRRecording::GetPriority "GetPriority" | *optional* - /// | **Lifetime** | `int` | @ref PVRRecording::SetLifetime "SetLifetime" | @ref PVRRecording::GetLifetime "GetLifetime" | *optional* - /// | **Genre type** | `int` | @ref PVRRecording::SetGenreType "SetGenreType" | @ref PVRRecording::GetGenreType "GetGenreType" | *optional* - /// | **Genre sub type** | `int` | @ref PVRRecording::SetGenreSubType "SetGenreSubType" | @ref PVRRecording::GetGenreSubType "GetGenreSubType" | *optional* - /// | **Play count** | `int` | @ref PVRRecording::SetPlayCount "SetPlayCount" | @ref PVRRecording::GetPlayCount "GetPlayCount" | *optional* - /// | **Last played position** | `int` | @ref PVRRecording::SetLastPlayedPosition "SetLastPlayedPosition" | @ref PVRRecording::GetLastPlayedPosition "GetLastPlayedPosition" | *optional* - /// | **Is deleted** | `bool` | @ref PVRRecording::SetIsDeleted "SetIsDeleted" | @ref PVRRecording::GetIsDeleted "GetIsDeleted" | *optional* - /// | **EPG event id** | `unsigned int` | @ref PVRRecording::SetEPGEventId "SetEPGEventId" | @ref PVRRecording::GetEPGEventId "GetEPGEventId" | *optional* - /// | **Channel unique id** | `int` | @ref PVRRecording::SetChannelUid "SetChannelUid" | @ref PVRRecording::GetChannelUid "GetChannelUid" | *optional* - /// | **Channel type** | @ref PVR_RECORDING_CHANNEL_TYPE | @ref PVRRecording::SetChannelType "SetChannelType" | @ref PVRRecording::GetChannelType "GetChannelType" | *optional* - /// | **First aired** | `std::string` | @ref PVRRecording::SetFirstAired "SetFirstAired" | @ref PVRRecording::GetFirstAired "GetFirstAired" | *optional* - /// | **Flags** | `std::string` | @ref PVRRecording::SetFlags "SetFlags" | @ref PVRRecording::GetFlags "GetFlags" | *optional* - /// | **Size in bytes** | `std::string` | @ref PVRRecording::SetSizeInBytes "SetSizeInBytes" | @ref PVRRecording::GetSizeInBytes "GetSizeInBytes" | *optional* - - /// @addtogroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording - ///@{ - - /// @brief **required**\n - /// Unique identifier of the recording on the client. - void SetRecordingId(const std::string& recordingId) - { - strncpy(m_cStructure->strRecordingId, recordingId.c_str(), - sizeof(m_cStructure->strRecordingId) - 1); - } - - /// @brief To get with @ref SetRecordingId changed values. - std::string GetRecordingId() const { return m_cStructure->strRecordingId; } - - /// @brief **required**\n - /// The title of this recording. - void SetTitle(const std::string& title) - { - strncpy(m_cStructure->strTitle, title.c_str(), sizeof(m_cStructure->strTitle) - 1); - } - - /// @brief To get with @ref SetTitle changed values. - std::string GetTitle() const { return m_cStructure->strTitle; } - - /// @brief **optional**\n - /// Episode name (also known as subtitle). - void SetEpisodeName(const std::string& episodeName) - { - strncpy(m_cStructure->strEpisodeName, episodeName.c_str(), - sizeof(m_cStructure->strEpisodeName) - 1); - } - - /// @brief To get with @ref SetEpisodeName changed values. - std::string GetEpisodeName() const { return m_cStructure->strEpisodeName; } - - /// @brief **optional**\n - /// Series number (usually called season). - /// - /// Set to "0" for specials/pilot. For 'invalid' see @ref SetEpisodeNumber or set to -1. - void SetSeriesNumber(int seriesNumber) { m_cStructure->iSeriesNumber = seriesNumber; } - - /// @brief To get with @ref SetSeriesNumber changed values. - int GetSeriesNumber() const { return m_cStructure->iSeriesNumber; } - - /// @brief **optional**\n - /// Eepisode number within the "iSeriesNumber" season. - /// - /// For 'invalid' set to -1 or seriesNumber=episodeNumber=0 to show both are invalid. - void SetEpisodeNumber(int episodeNumber) { m_cStructure->iEpisodeNumber = episodeNumber; } - - /// @brief To get with @ref SetEpisodeNumber changed values. - int GetEpisodeNumber() const { return m_cStructure->iEpisodeNumber; } - - /// @brief **optional**\n - /// Year of first release (use to identify a specific movie re-make) / first - /// airing for TV shows. - /// - /// Set to '0' for invalid. - void SetYear(int year) { m_cStructure->iYear = year; } - - /// @brief To get with @ref SetYear changed values. - int GetYear() const { return m_cStructure->iYear; } - - /// @brief **optional**\n - /// - /// Directory of this recording on the client. - void SetDirectory(const std::string& directory) - { - strncpy(m_cStructure->strDirectory, directory.c_str(), sizeof(m_cStructure->strDirectory) - 1); - } - - /// @brief To get with @ref SetDirectory changed values. - std::string GetDirectory() const { return m_cStructure->strDirectory; } - - /// @brief **optional**\n - /// Plot outline name. - void SetPlotOutline(const std::string& plotOutline) - { - strncpy(m_cStructure->strPlotOutline, plotOutline.c_str(), - sizeof(m_cStructure->strPlotOutline) - 1); - } - - /// @brief To get with @ref SetPlotOutline changed values. - std::string GetPlotOutline() const { return m_cStructure->strPlotOutline; } - - /// @brief **optional**\n - /// Plot name. - void SetPlot(const std::string& plot) - { - strncpy(m_cStructure->strPlot, plot.c_str(), sizeof(m_cStructure->strPlot) - 1); - } - - /// @brief To get with @ref SetPlot changed values. - std::string GetPlot() const { return m_cStructure->strPlot; } - - /// @brief **optional**\n - /// Channel name. - void SetChannelName(const std::string& channelName) - { - strncpy(m_cStructure->strChannelName, channelName.c_str(), - sizeof(m_cStructure->strChannelName) - 1); - } - - /// @brief To get with @ref SetChannelName changed values. - std::string GetChannelName() const { return m_cStructure->strChannelName; } - - /// @brief **optional**\n - /// Channel logo (icon) path. - void SetIconPath(const std::string& iconPath) - { - strncpy(m_cStructure->strIconPath, iconPath.c_str(), sizeof(m_cStructure->strIconPath) - 1); - } - - /// @brief To get with @ref SetIconPath changed values. - std::string GetIconPath() const { return m_cStructure->strIconPath; } - - /// @brief **optional**\n - /// Thumbnail path. - void SetThumbnailPath(const std::string& thumbnailPath) - { - strncpy(m_cStructure->strThumbnailPath, thumbnailPath.c_str(), - sizeof(m_cStructure->strThumbnailPath) - 1); - } - - /// @brief To get with @ref SetThumbnailPath changed values. - std::string GetThumbnailPath() const { return m_cStructure->strThumbnailPath; } - - /// @brief **optional**\n - /// Fanart path. - void SetFanartPath(const std::string& fanartPath) - { - strncpy(m_cStructure->strFanartPath, fanartPath.c_str(), - sizeof(m_cStructure->strFanartPath) - 1); - } - - /// @brief To get with @ref SetFanartPath changed values. - std::string GetFanartPath() const { return m_cStructure->strFanartPath; } - - /// @brief **optional**\n - /// Start time of the recording. - void SetRecordingTime(time_t recordingTime) { m_cStructure->recordingTime = recordingTime; } - - /// @brief To get with @ref SetRecordingTime changed values. - time_t GetRecordingTime() const { return m_cStructure->recordingTime; } - - /// @brief **optional**\n - /// Duration of the recording in seconds. - void SetDuration(int duration) { m_cStructure->iDuration = duration; } - - /// @brief To get with @ref SetDuration changed values. - int GetDuration() const { return m_cStructure->iDuration; } - - /// @brief **optional**\n - /// Priority of this recording (from 0 - 100). - void SetPriority(int priority) { m_cStructure->iPriority = priority; } - - /// @brief To get with @ref SetPriority changed values. - int GetPriority() const { return m_cStructure->iPriority; } - - /// @brief **optional**\n - /// Life time in days of this recording. - void SetLifetime(int lifetime) { m_cStructure->iLifetime = lifetime; } - - /// @brief To get with @ref SetLifetime changed values. - int GetLifetime() const { return m_cStructure->iLifetime; } - - /// @brief **optional**\n - /// Genre type. - /// - /// Use @ref EPG_GENRE_USE_STRING if type becomes given by @ref SetGenreDescription. - /// - /// @note If confirmed that backend brings the types in [ETSI EN 300 468](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) - /// conform values, can be @ref EPG_EVENT_CONTENTMASK ignored and to set here - /// with backend value. - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Example 1:** - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVRRecording tag; - /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MOVIEDRAMA); - /// ~~~~~~~~~~~~~ - /// - /// -------------------------------------------------------------------------- - /// - /// **Example 2** (in case of other, not ETSI EN 300 468 conform genre types): - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVRRecording tag; - /// tag.SetGenreType(EPG_GENRE_USE_STRING); - /// tag.SetGenreDescription("My special genre name"); // Should use (if possible) kodi::GetLocalizedString(...) to have match user language. - /// ~~~~~~~~~~~~~ - /// - void SetGenreType(int genreType) { m_cStructure->iGenreType = genreType; } - - /// @brief To get with @ref SetGenreType changed values. - int GetGenreType() const { return m_cStructure->iGenreType; } - - /// @brief **optional**\n - /// Genre sub type. - /// - /// Subtypes groups related to set by @ref SetGenreType: - /// | Main genre type | List with available sub genre types - /// |-----------------|----------------------------------------- - /// | @ref EPG_EVENT_CONTENTMASK_UNDEFINED | Nothing, should be 0 - /// | @ref EPG_EVENT_CONTENTMASK_MOVIEDRAMA | @ref EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA - /// | @ref EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS | @ref EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS - /// | @ref EPG_EVENT_CONTENTMASK_SHOW | @ref EPG_EVENT_CONTENTSUBMASK_SHOW - /// | @ref EPG_EVENT_CONTENTMASK_SPORTS | @ref EPG_EVENT_CONTENTSUBMASK_SPORTS - /// | @ref EPG_EVENT_CONTENTMASK_CHILDRENYOUTH | @ref EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH - /// | @ref EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE | @ref EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE - /// | @ref EPG_EVENT_CONTENTMASK_ARTSCULTURE | @ref EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE - /// | @ref EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS | @ref EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS - /// | @ref EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE | @ref EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE - /// | @ref EPG_EVENT_CONTENTMASK_LEISUREHOBBIES | @ref EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES - /// | @ref EPG_EVENT_CONTENTMASK_SPECIAL | @ref EPG_EVENT_CONTENTSUBMASK_SPECIAL - /// | @ref EPG_EVENT_CONTENTMASK_USERDEFINED | Can be defined by you - /// | @ref EPG_GENRE_USE_STRING | **Kodi's own value**, which declares that the type with @ref SetGenreDescription is given. - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVRRecording tag; - /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE); - /// tag.SetGenreSubType(EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_JAZZ); - /// ~~~~~~~~~~~~~ - /// - void SetGenreSubType(int genreSubType) { m_cStructure->iGenreSubType = genreSubType; } - - /// @brief To get with @ref SetGenreSubType changed values. - int GetGenreSubType() const { return m_cStructure->iGenreSubType; } - - /// @brief **optional**\n - /// To set own genre description name. - /// - /// Will be used only when genreType == @ref EPG_GENRE_USE_STRING or - /// genreSubType == @ref EPG_GENRE_USE_STRING. - /// - /// Use @ref EPG_STRING_TOKEN_SEPARATOR to separate different genres. - /// - /// In case of other, not [ETSI EN 300 468](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) - /// conform genre types or something special. - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVRRecording tag; - /// tag.SetGenreType(EPG_GENRE_USE_STRING); - /// tag.SetGenreDescription("Action" + EPG_STRING_TOKEN_SEPARATOR + "Thriller"); - /// ~~~~~~~~~~~~~ - /// - void SetGenreDescription(const std::string& genreDescription) - { - strncpy(m_cStructure->strGenreDescription, genreDescription.c_str(), - sizeof(m_cStructure->strGenreDescription) - 1); - } - - /// @brief To get with @ref SetGenreDescription changed values. - std::string GetGenreDescription() const { return m_cStructure->strGenreDescription; } - - /// @brief **optional**\n - /// Play count of this recording on the client. - void SetPlayCount(int playCount) { m_cStructure->iPlayCount = playCount; } - - /// @brief To get with @ref SetPlayCount changed values. - int GetPlayCount() const { return m_cStructure->iPlayCount; } - - /// @brief **optional**\n - /// Last played position of this recording on the client. - void SetLastPlayedPosition(int lastPlayedPosition) - { - m_cStructure->iLastPlayedPosition = lastPlayedPosition; - } - - /// @brief To get with @ref SetLastPlayedPosition changed values. - int GetLastPlayedPosition() const { return m_cStructure->iLastPlayedPosition; } - - /// @brief **optional**\n - /// Shows this recording is deleted and can be undelete. - void SetIsDeleted(int isDeleted) { m_cStructure->bIsDeleted = isDeleted; } - - /// @brief To get with @ref SetIsDeleted changed values. - int GetIsDeleted() const { return m_cStructure->bIsDeleted; } - - /// @brief **optional**\n - /// EPG event id associated with this recording. Valid ids must be greater than @ref EPG_TAG_INVALID_UID. - void SetEPGEventId(unsigned int epgEventId) { m_cStructure->iEpgEventId = epgEventId; } - - /// @brief To get with @ref SetEPGEventId changed values. - unsigned int GetEPGEventId() const { return m_cStructure->iEpgEventId; } - - /// @brief **optional**\n - /// Unique identifier of the channel for this recording. @ref PVR_CHANNEL_INVALID_UID - /// denotes that channel uid is not available. - void SetChannelUid(int channelUid) { m_cStructure->iChannelUid = channelUid; } - - /// @brief To get with @ref SetChannelUid changed values - int GetChannelUid() const { return m_cStructure->iChannelUid; } - - /// @brief **optional**\n - /// Channel type. - /// - /// Set to @ref PVR_RECORDING_CHANNEL_TYPE_UNKNOWN if the type cannot be - /// determined. - /// - /// -------------------------------------------------------------------------- - /// - /// Example: - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVRRecording tag; - /// tag.SetChannelType(PVR_RECORDING_CHANNEL_TYPE_TV); - /// ~~~~~~~~~~~~~ - /// - void SetChannelType(PVR_RECORDING_CHANNEL_TYPE channelType) - { - m_cStructure->channelType = channelType; - } - - /// @brief To get with @ref SetChannelType changed values - PVR_RECORDING_CHANNEL_TYPE GetChannelType() const { return m_cStructure->channelType; } - - /// @brief **optional**\n - /// First aired date of this recording. - /// - /// Used only for display purposes. Specify in W3C date format "YYYY-MM-DD". - /// - /// -------------------------------------------------------------------------- - /// - /// Example: - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVRRecording tag; - /// tag.SetFirstAired(1982-10-22); - /// ~~~~~~~~~~~~~ - /// - void SetFirstAired(const std::string& firstAired) - { - strncpy(m_cStructure->strFirstAired, firstAired.c_str(), - sizeof(m_cStructure->strFirstAired) - 1); - } - - /// @brief To get with @ref SetFirstAired changed values - std::string GetFirstAired() const { return m_cStructure->strFirstAired; } - - /// @brief **optional**\n - /// Bit field of independent flags associated with the recording. - /// - /// See @ref cpp_kodi_addon_pvr_Defs_Recording_PVR_RECORDING_FLAG for - /// available bit flags. - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_Recording_PVR_RECORDING_FLAG - /// - void SetFlags(unsigned int flags) { m_cStructure->iFlags = flags; } - - /// @brief To get with @ref SetFlags changed values. - unsigned int GetFlags() const { return m_cStructure->iFlags; } - - /// @brief **optional**\n - /// Size of the recording in bytes. - void SetSizeInBytes(int64_t sizeInBytes) { m_cStructure->sizeInBytes = sizeInBytes; } - - /// @brief To get with @ref SetSizeInBytes changed values. - int64_t GetSizeInBytes() const { return m_cStructure->sizeInBytes; } - ///@} - -private: - PVRRecording(const PVR_RECORDING* recording) : CStructHdl(recording) {} - PVRRecording(PVR_RECORDING* recording) : CStructHdl(recording) {} -}; -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecordingsResultSet class PVRRecordingsResultSet -/// @ingroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording -/// @brief **PVR add-on recording transfer class**\n -/// To transfer the content of @ref kodi::addon::CInstancePVRClient::GetRecordings(). -/// -/// @note This becomes only be used on addon call above, not usable outside on -/// addon itself. -///@{ -class PVRRecordingsResultSet -{ -public: - /*! \cond PRIVATE */ - PVRRecordingsResultSet() = delete; - PVRRecordingsResultSet(const AddonInstance_PVR* instance, ADDON_HANDLE handle) - : m_instance(instance), m_handle(handle) - { - } - /*! \endcond */ - - /// @addtogroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecordingsResultSet - ///@{ - - /// @brief To add and give content from addon to Kodi on related call. - /// - /// @param[in] tag The to transferred data. - void Add(const kodi::addon::PVRRecording& tag) - { - m_instance->toKodi->TransferRecordingEntry(m_instance->toKodi->kodiInstance, m_handle, tag); - } - - ///@} - -private: - const AddonInstance_PVR* m_instance = nullptr; - const ADDON_HANDLE m_handle; -}; -///@} -//------------------------------------------------------------------------------ - -} /* namespace addon */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Stream.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Stream.h deleted file mode 100644 index 5613947..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Stream.h +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../../c-api/addon-instance/pvr/pvr_stream.h" - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" Definitions group 9 - PVR stream definitions (NOTE: Becomes replaced -// in future by inputstream addon instance way) - -#ifdef __cplusplus - -namespace kodi -{ -namespace addon -{ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVRCodec class PVRCodec -/// @ingroup cpp_kodi_addon_pvr_Defs_Stream -/// @brief **PVR codec identifier**\n -/// Used to exchange the desired codec type between Kodi and addon. -/// -/// @ref kodi::addon::CInstancePVRClient::GetCodecByName is used to get this data. -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_Stream_PVRCodec_Help -/// -///@{ -class PVRCodec : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVRCodec() - { - m_cStructure->codec_type = PVR_CODEC_TYPE_UNKNOWN; - m_cStructure->codec_id = PVR_INVALID_CODEC_ID; - } - PVRCodec(const PVRCodec& type) : CStructHdl(type) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVRCodec_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_Stream_PVRCodec - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Stream_PVRCodec : - /// | Name | Type | Set call | Get call - /// |------|------|----------|---------- - /// | **Codec type** | @ref PVR_CODEC_TYPE | @ref PVRCodec::SetCodecType "SetCodecType" | @ref PVRCodec::GetCodecType "GetCodecType" - /// | **Codec identifier** | `unsigned int` | @ref PVRCodec::SetCodecId "SetCodecId" | @ref PVRCodec::GetCodecId "GetCodecId" - /// - - /// @addtogroup cpp_kodi_addon_pvr_Defs_Stream_PVRCodec - ///@{ - - /// @brief Codec type. - void SetCodecType(PVR_CODEC_TYPE codecType) { m_cStructure->codec_type = codecType; } - - /// @brief To get with @ref SetCodecType() changed values. - PVR_CODEC_TYPE GetCodecType() const { return m_cStructure->codec_type; } - - /// @brief Codec id. - /// - /// Related codec identifier, normally match the ffmpeg id's. - void SetCodecId(unsigned int codecId) { m_cStructure->codec_id = codecId; } - - /// @brief To get with @ref SetCodecId() changed values. - unsigned int GetCodecId() const { return m_cStructure->codec_id; } - ///@} - -private: - PVRCodec(const PVR_CODEC& type) : CStructHdl(&type) {} - PVRCodec(const PVR_CODEC* type) : CStructHdl(type) {} - PVRCodec(PVR_CODEC* type) : CStructHdl(type) {} -}; -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties class PVRStreamProperties -/// @ingroup cpp_kodi_addon_pvr_Defs_Stream -/// @brief **PVR stream properties**\n -/// All information about a respective stream is stored in this, so that Kodi -/// can process the data given by the addon after demux. -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties_Help -/// -///@{ -class PVRStreamProperties - : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVRStreamProperties() { memset(m_cStructure, 0, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); } - PVRStreamProperties(const PVRStreamProperties& type) : CStructHdl(type) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties - /// ---------------------------------------------------------------------------- - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties : - /// | Name | Type | Set call | Get call - /// |------|------|----------|---------- - /// | **PID** | `unsigned int` | @ref PVRStreamProperties::SetPID "SetPID" | @ref PVRStreamProperties::GetPID "GetPID" - /// | **Codec type** | @ref PVR_CODEC_TYPE | @ref PVRStreamProperties::SetCodecType "SetCodecType" | @ref PVRStreamProperties::GetCodecType "GetCodecType" - /// | **Codec identifier** | `unsigned int` | @ref PVRStreamProperties::SetCodecId "SetCodecId" | @ref PVRStreamProperties::GetCodecId "GetCodecId" - /// | **Language** | `std::string` | @ref PVRStreamProperties::SetLanguage "SetLanguage" | @ref PVRStreamProperties::GetLanguage "GetLanguage" - /// | **Subtitle info** | `int` | @ref PVRStreamProperties::SetSubtitleInfo "SetSubtitleInfo" | @ref PVRStreamProperties::GetSubtitleInfo "GetSubtitleInfo" - /// | **FPS scale** | `int` | @ref PVRStreamProperties::SetFPSScale "SetFPSScale" | @ref PVRStreamProperties::GetFPSScale "GetFPSScale" - /// | **FPS rate** | `int` | @ref PVRStreamProperties::SetFPSRate "SetFPSRate" | @ref PVRStreamProperties::GetFPSRate "GetFPSRate" - /// | **Height** | `int` | @ref PVRStreamProperties::SetHeight "SetHeight" | @ref PVRStreamProperties::GetHeight "GetHeight" - /// | **Width** | `int` | @ref PVRStreamProperties::SetWidth "SetWidth" | @ref PVRStreamProperties::GetWidth "GetWidth" - /// | **Aspect ratio** | `float` | @ref PVRStreamProperties::SetAspect "SetAspect" | @ref PVRStreamProperties::GetAspect "GetAspect" - /// | **Channels** | `int` | @ref PVRStreamProperties::SetChannels "SetChannels" | @ref PVRStreamProperties::GetChannels "GetChannels" - /// | **Samplerate** | `int` | @ref PVRStreamProperties::SetSampleRate "SetSampleRate" | @ref PVRStreamProperties::GetSampleRate "GetSampleRate" - /// | **Block align** | `int` | @ref PVRStreamProperties::SetBlockAlign "SetBlockAlign" | @ref PVRStreamProperties::GetBlockAlign "GetBlockAlign" - /// | **Bit rate** | `int` | @ref PVRStreamProperties::SetBitRate "SetBitRate" | @ref PVRStreamProperties::GetBitRate "GetBitRate" - /// | **Bits per sample** | `int` | @ref PVRStreamProperties::SetBitsPerSample "SetBitsPerSample" | @ref PVRStreamProperties::GetBitsPerSample "GetBitsPerSample" - /// - - /// @addtogroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties - ///@{ - - /// @brief PID. - void SetPID(unsigned int pid) { m_cStructure->iPID = pid; } - - /// @brief To get with @ref SetPID() changed values. - unsigned int GetPID() const { return m_cStructure->iPID; } - - /// @brief Codec type this stream. - void SetCodecType(PVR_CODEC_TYPE codecType) { m_cStructure->iCodecType = codecType; } - - /// @brief To get with @ref SetCodecType() changed values. - PVR_CODEC_TYPE GetCodecType() const { return m_cStructure->iCodecType; } - - /// @brief Codec id of this stream. - void SetCodecId(unsigned int codecId) { m_cStructure->iCodecId = codecId; } - - /// @brief To get with @ref SetCodecId() changed values. - unsigned int GetCodecId() const { return m_cStructure->iCodecId; } - - /// @brief 3 letter language id. - void SetLanguage(const std::string& language) - { - if (language.size() > 3) - { - kodi::Log(ADDON_LOG_ERROR, - "PVRStreamProperties::%s: Language string size '%li' higher as needed 3", __func__, - language.size()); - return; - } - m_cStructure->strLanguage[0] = language[0]; - m_cStructure->strLanguage[1] = language[1]; - m_cStructure->strLanguage[2] = language[2]; - m_cStructure->strLanguage[2] = 0; - } - - /// @brief To get with @ref SetLanguage() changed values. - std::string GetLanguage() const { return m_cStructure->strLanguage; } - - /// @brief Subtitle Info - void SetSubtitleInfo(int subtitleInfo) { m_cStructure->iSubtitleInfo = subtitleInfo; } - - /// @brief To get with @ref SetSubtitleInfo() changed values. - int GetSubtitleInfo() const { return m_cStructure->iSubtitleInfo; } - - /// @brief To set scale of 1000 and a rate of 29970 will result in 29.97 fps. - void SetFPSScale(int fpsScale) { m_cStructure->iFPSScale = fpsScale; } - - /// @brief To get with @ref SetFPSScale() changed values. - int GetFPSScale() const { return m_cStructure->iFPSScale; } - - /// @brief FPS rate - void SetFPSRate(int fpsRate) { m_cStructure->iFPSRate = fpsRate; } - - /// @brief To get with @ref SetFPSRate() changed values. - int GetFPSRate() const { return m_cStructure->iFPSRate; } - - /// @brief Height of the stream reported by the demuxer - void SetHeight(int height) { m_cStructure->iHeight = height; } - - /// @brief To get with @ref SetHeight() changed values. - int GetHeight() const { return m_cStructure->iHeight; } - - /// @brief Width of the stream reported by the demuxer. - void SetWidth(int width) { m_cStructure->iWidth = width; } - - /// @brief To get with @ref SetWidth() changed values. - int GetWidth() const { return m_cStructure->iWidth; } - - /// @brief Display aspect ratio of the stream. - void SetAspect(float aspect) { m_cStructure->fAspect = aspect; } - - /// @brief To get with @ref SetAspect() changed values. - float GetAspect() const { return m_cStructure->fAspect; } - - /// @brief Amount of channels. - void SetChannels(int channels) { m_cStructure->iChannels = channels; } - - /// @brief To get with @ref SetChannels() changed values. - int GetChannels() const { return m_cStructure->iChannels; } - - /// @brief Sample rate. - void SetSampleRate(int sampleRate) { m_cStructure->iSampleRate = sampleRate; } - - /// @brief To get with @ref SetSampleRate() changed values. - int GetSampleRate() const { return m_cStructure->iSampleRate; } - - /// @brief Block alignment - void SetBlockAlign(int blockAlign) { m_cStructure->iBlockAlign = blockAlign; } - - /// @brief To get with @ref SetBlockAlign() changed values. - int GetBlockAlign() const { return m_cStructure->iBlockAlign; } - - /// @brief Bit rate. - void SetBitRate(int bitRate) { m_cStructure->iBitRate = bitRate; } - - /// @brief To get with @ref SetBitRate() changed values. - int GetBitRate() const { return m_cStructure->iBitRate; } - - /// @brief Bits per sample. - void SetBitsPerSample(int bitsPerSample) { m_cStructure->iBitsPerSample = bitsPerSample; } - - /// @brief To get with @ref SetBitsPerSample() changed values. - int GetBitsPerSample() const { return m_cStructure->iBitsPerSample; } - ///@} - -private: - PVRStreamProperties(const PVR_STREAM_PROPERTIES::PVR_STREAM* type) : CStructHdl(type) {} - PVRStreamProperties(PVR_STREAM_PROPERTIES::PVR_STREAM* type) : CStructHdl(type) {} -}; -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes class PVRStreamTimes -/// @ingroup cpp_kodi_addon_pvr_Defs_Stream -/// @brief **Times of playing stream (Live TV and recordings)**\n -/// This class is used to transfer the necessary data when -/// @ref kodi::addon::PVRStreamProperties::GetStreamTimes is called. -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes_Help -/// -///@{ -class PVRStreamTimes : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVRStreamTimes() { memset(m_cStructure, 0, sizeof(PVR_STREAM_TIMES)); } - PVRStreamTimes(const PVRStreamTimes& type) : CStructHdl(type) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes - /// ---------------------------------------------------------------------------- - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes : - /// | Name | Type | Set call | Get call - /// |------|------|----------|---------- - /// | **Start time** | `time_t` | @ref PVRStreamTimes::SetStartTime "SetStartTime" | @ref PVRStreamTimes::GetStartTime "GetStartTime" - /// | **PTS start** | `int64_t` | @ref PVRStreamTimes::SetPTSStart "SetPTSStart" | @ref PVRStreamTimes::GetPTSStart "GetPTSStart" - /// | **PTS begin** | `int64_t` | @ref PVRStreamTimes::SetPTSBegin "SetPTSBegin" | @ref PVRStreamTimes::GetPTSBegin "GetPTSBegin" - /// | **PTS end** | `int64_t` | @ref PVRStreamTimes::SetPTSEnd "SetPTSEnd" | @ref PVRStreamTimes::GetPTSEnd "GetPTSEnd" - /// - - /// @addtogroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes - ///@{ - - /// @brief For recordings, this must be zero. For Live TV, this is a reference - /// time in units of time_t (UTC) from which time elapsed starts. Ideally start - /// of tv show, but can be any other value. - void SetStartTime(time_t startTime) { m_cStructure->startTime = startTime; } - - /// @brief To get with @ref SetStartTime() changed values. - time_t GetStartTime() const { return m_cStructure->startTime; } - - /// @brief The pts of startTime. - void SetPTSStart(int64_t ptsStart) { m_cStructure->ptsStart = ptsStart; } - - /// @brief To get with @ref SetPTSStart() changed values. - int64_t GetPTSStart() const { return m_cStructure->ptsStart; } - - /// @brief Earliest pts player can seek back. Value is in micro seconds, - /// relative to PTS start. For recordings, this must be zero. For Live TV, this - /// must be zero if not timeshifting and must point to begin of the timeshift - /// buffer, otherwise. - void SetPTSBegin(int64_t ptsBegin) { m_cStructure->ptsBegin = ptsBegin; } - - /// @brief To get with @ref SetPTSBegin() changed values. - int64_t GetPTSBegin() const { return m_cStructure->ptsBegin; } - - /// @brief Latest pts player can seek forward. Value is in micro seconds, - /// relative to PTS start. For recordings, this must be the total length. For - /// Live TV, this must be zero if not timeshifting and must point to end of - /// the timeshift buffer, otherwise. - void SetPTSEnd(int64_t ptsEnd) { m_cStructure->ptsEnd = ptsEnd; } - - /// @brief To get with @ref SetPTSEnd() changed values. - int64_t GetPTSEnd() const { return m_cStructure->ptsEnd; } - ///@} - -private: - PVRStreamTimes(const PVR_STREAM_TIMES* type) : CStructHdl(type) {} - PVRStreamTimes(PVR_STREAM_TIMES* type) : CStructHdl(type) {} -}; -///@} -//------------------------------------------------------------------------------ - -} /* namespace addon */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Timers.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Timers.h deleted file mode 100644 index 6e05e55..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/pvr/Timers.h +++ /dev/null @@ -1,896 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "General.h" -#include "../../AddonBase.h" -#include "../../c-api/addon-instance/pvr.h" - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C++" Definitions group 6 - PVR timers -#ifdef __cplusplus - -namespace kodi -{ -namespace addon -{ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimer class PVRTimer -/// @ingroup cpp_kodi_addon_pvr_Defs_Timer -/// @brief **PVR add-on timer type**\n -/// Representation of a timer event. -/// -/// The related values here are automatically initiated to defaults and need -/// only be set if supported and used. -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_Timer_PVRTimer_Help -/// -///@{ -class PVRTimer : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVRTimer() - { - m_cStructure->iClientIndex = 0; - m_cStructure->state = PVR_TIMER_STATE_NEW; - m_cStructure->iTimerType = PVR_TIMER_TYPE_NONE; - m_cStructure->iParentClientIndex = 0; - m_cStructure->iClientChannelUid = PVR_TIMER_VALUE_NOT_AVAILABLE; - m_cStructure->startTime = 0; - m_cStructure->endTime = 0; - m_cStructure->bStartAnyTime = false; - m_cStructure->bEndAnyTime = false; - m_cStructure->bFullTextEpgSearch = false; - m_cStructure->iPriority = PVR_TIMER_VALUE_NOT_AVAILABLE; - m_cStructure->iLifetime = PVR_TIMER_VALUE_NOT_AVAILABLE; - m_cStructure->iMaxRecordings = PVR_TIMER_VALUE_NOT_AVAILABLE; - m_cStructure->iRecordingGroup = 0; - m_cStructure->firstDay = 0; - m_cStructure->iWeekdays = PVR_WEEKDAY_NONE; - m_cStructure->iPreventDuplicateEpisodes = 0; - m_cStructure->iEpgUid = 0; - m_cStructure->iMarginStart = 0; - m_cStructure->iMarginEnd = 0; - m_cStructure->iGenreType = PVR_TIMER_VALUE_NOT_AVAILABLE; - m_cStructure->iGenreSubType = PVR_TIMER_VALUE_NOT_AVAILABLE; - } - PVRTimer(const PVRTimer& data) : CStructHdl(data) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimer_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimer - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimer : - /// | Name | Type | Set call | Get call | Usage - /// |------|------|----------|----------|----------- - /// | **Client index** | `unsigned int` | @ref PVRTimer::SetClientIndex "SetClientIndex" | @ref PVRTimer::GetClientIndex "GetClientIndex" | *required to set* - /// | **State** | @ref PVR_TIMER_STATE | @ref PVRTimer::SetState "SetState" | @ref PVRTimer::GetState "GetState" | *required to set* - /// | **Type** | `unsigned int` | @ref PVRTimer::SetTimerType "SetTimerType" | @ref PVRTimer::GetTimerType "GetTimerType" | *required to set* - /// | **Title** | `std::string` | @ref PVRTimer::SetTitle "SetTitle" | @ref PVRTimer::GetTitle "GetTitle" | *required to set* - /// | **Parent client index** | `unsigned int` | @ref PVRTimer::SetParentClientIndex "SetParentClientIndex" | @ref PVRTimer::GetParentClientIndex "GetParentClientIndex" | *optional* - /// | **Client channel unique identifier** | `int` | @ref PVRTimer::SetClientChannelUid "SetClientChannelUid" | @ref PVRTimer::GetClientChannelUid "GetClientChannelUid" | *optional* - /// | **Start time** | `time_t` | @ref PVRTimer::SetStartTime "SetStartTime" | @ref PVRTimer::GetStartTime "GetStartTime" | *optional* - /// | **End time** | `time_t` | @ref PVRTimer::SetEndTime "SetEndTime" | @ref PVRTimer::GetEndTime "GetEndTime" | *optional* - /// | **Start any time** | `bool` | @ref PVRTimer::SetStartAnyTime "SetStartAnyTime" | @ref PVRTimer::GetStartAnyTime "GetStartAnyTime" | *optional* - /// | **End any time** | `bool` | @ref PVRTimer::SetEndAnyTime "SetEndAnyTime" | @ref PVRTimer::GetEndAnyTime "GetEndAnyTime" | *optional* - /// | **EPG search string** | `std::string` | @ref PVRTimer::SetEPGSearchString "SetEPGSearchString" | @ref PVRTimer::GetEPGSearchString "GetEPGSearchString" | *optional* - /// | **Full text EPG search** | `bool` | @ref PVRTimer::SetFullTextEpgSearch "SetFullTextEpgSearch" | @ref PVRTimer::GetFullTextEpgSearch "GetFullTextEpgSearch" | *optional* - /// | **Recording store directory** | `std::string` | @ref PVRTimer::SetDirectory "SetDirectory" | @ref PVRTimer::GetDirectory "GetDirectory" | *optional* - /// | **Timer priority** | `int` | @ref PVRTimer::SetPriority "SetPriority" | @ref PVRTimer::GetPriority "GetPriority" | *optional* - /// | **Timer lifetime** | `int` | @ref PVRTimer::SetLifetime "SetLifetime" | @ref PVRTimer::GetLifetime "GetLifetime" | *optional* - /// | **Max recordings** | `int` | @ref PVRTimer::SetMaxRecordings "SetMaxRecordings" | @ref PVRTimer::GetMaxRecordings "GetMaxRecordings" | *optional* - /// | **Recording group** | `unsigned int` | @ref PVRTimer::SetRecordingGroup "SetRecordingGroup" | @ref PVRTimer::GetRecordingGroup "GetRecordingGroup" | *optional* - /// | **First start day** | `time_t` | @ref PVRTimer::SetFirstDay "SetFirstDay" | @ref PVRTimer::GetFirstDay "GetFirstDay" | *optional* - /// | **Used timer weekdays** | `unsigned int` | @ref PVRTimer::SetWeekdays "SetWeekdays" | @ref PVRTimer::GetWeekdays "GetWeekdays" | *optional* - /// | **Prevent duplicate episodes** | `unsigned int` | @ref PVRTimer::SetPreventDuplicateEpisodes "SetPreventDuplicateEpisodes" | @ref PVRTimer::GetPreventDuplicateEpisodes "GetPreventDuplicateEpisodes" | *optional* - /// | **EPG unique identifier** | `unsigned int` | @ref PVRTimer::SetEPGUid "SetEPGUid" | @ref PVRTimer::GetEPGUid "GetEPGUid" | *optional* - /// | **Margin start** | `unsigned int` | @ref PVRTimer::SetMarginStart "SetMarginStart" | @ref PVRTimer::GetMarginStart "GetMarginStart" | *optional* - /// | **Margin end** | `unsigned int` | @ref PVRTimer::SetMarginEnd "SetMarginEnd" | @ref PVRTimer::GetMarginEnd "GetMarginEnd" | *optional* - /// | **Genre type** | `int` | @ref PVRTimer::SetGenreType "SetGenreType" | @ref PVRTimer::GetGenreType "GetGenreType" | *optional* - /// | **Genre sub type** | `int` | @ref PVRTimer::SetGenreSubType "SetGenreSubType" | @ref PVRTimer::GetGenreSubType "GetGenreSubType" | *optional* - /// | **Series link** | `std::string` | @ref PVRTimer::SetSeriesLink "SetSeriesLink" | @ref PVRTimer::GetSeriesLink "GetSeriesLink" | *optional* - - /// @addtogroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimer - ///@{ - - /// @brief **required**\n - /// The index of this timer given by the client. - /// - /// @ref PVR_TIMER_NO_CLIENT_INDEX indicates that the index was not yet set - /// by the client, for example for new timers created by Kodi and passed the - /// first time to the client. A valid index must be greater than - /// @ref PVR_TIMER_NO_CLIENT_INDEX. - /// - void SetClientIndex(unsigned int clientIndex) { m_cStructure->iClientIndex = clientIndex; } - - /// @brief To get with @ref SetClientIndex changed values. - unsigned int GetClientIndex() const { return m_cStructure->iClientIndex; } - - /// @brief **required**\n - /// The state of this timer. - /// - /// @note @ref PVR_TIMER_STATE_NEW is default. - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVRTimer tag; - /// tag.SetState(PVR_TIMER_STATE_RECORDING); - /// ~~~~~~~~~~~~~ - /// - void SetState(PVR_TIMER_STATE state) { m_cStructure->state = state; } - - /// @brief To get with @ref SetState changed values. - PVR_TIMER_STATE GetState() const { return m_cStructure->state; } - - /// @brief **required**\n - /// The type of this timer. - /// - /// It is private to the addon and can be freely defined by the addon. - /// The value must be greater than @ref PVR_TIMER_TYPE_NONE. - /// - /// Kodi does not interpret this value (except for checking for @ref PVR_TIMER_TYPE_NONE), - /// but will pass the right id to the addon with every @ref PVRTimer instance, - /// thus the addon easily can determine the timer type. - /// - /// @note @ref PVR_TIMER_TYPE_NONE is default. - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVRTimer tag; - /// tag.SetTimerType(123); - /// ~~~~~~~~~~~~~ - /// - void SetTimerType(unsigned int timerType) { m_cStructure->iTimerType = timerType; } - - /// @brief To get with @ref SetTimerType changed values. - unsigned int GetTimerType() const { return m_cStructure->iTimerType; } - - /// @brief **required**\n - /// A title for this timer. - void SetTitle(const std::string& title) - { - strncpy(m_cStructure->strTitle, title.c_str(), sizeof(m_cStructure->strTitle) - 1); - } - - /// @brief To get with @ref SetTitle changed values. - std::string GetTitle() const { return m_cStructure->strTitle; } - - /// @brief **optional**\n - /// For timers scheduled by a repeating timer. - /// - /// The index of the repeating timer that scheduled this timer (it's - /// @ref clientIndex value). Use @ref PVR_TIMER_NO_PARENT to indicate that - /// this timer was no scheduled by a repeating timer. - void SetParentClientIndex(unsigned int parentClientIndex) - { - m_cStructure->iParentClientIndex = parentClientIndex; - } - - /// @brief To get with @ref SetParentClientIndex changed values. - unsigned int GetParentClientIndex() const { return m_cStructure->iParentClientIndex; } - - /// @brief **optional**\n - /// Unique identifier of the channel to record on. - /// - /// @ref PVR_TIMER_ANY_CHANNEL will denote "any channel", not a specific one. - /// @ref PVR_CHANNEL_INVALID_UID denotes that channel uid is not available. - void SetClientChannelUid(int clientChannelUid) - { - m_cStructure->iClientChannelUid = clientChannelUid; - } - - /// @brief To get with @ref SetClientChannelUid changed values - int GetClientChannelUid() const { return m_cStructure->iClientChannelUid; } - - /// @brief **optional**\n - /// Start time of the recording in UTC. - /// - /// Instant timers that are sent to the add-on by Kodi will have this value - /// set to 0. - void SetStartTime(time_t startTime) { m_cStructure->startTime = startTime; } - - /// @brief To get with @ref SetStartTime changed values. - time_t GetStartTime() const { return m_cStructure->startTime; } - - /// @brief **optional**\n - /// End time of the recording in UTC. - void SetEndTime(time_t endTime) { m_cStructure->endTime = endTime; } - - /// @brief To get with @ref SetEndTime changed values. - time_t GetEndTime() const { return m_cStructure->endTime; } - - /// @brief **optional**\n - /// For EPG based (not Manual) timers indicates startTime does not apply. - /// - /// Default = false. - void SetStartAnyTime(bool startAnyTime) { m_cStructure->bStartAnyTime = startAnyTime; } - - /// @brief To get with @ref SetStartAnyTime changed values. - bool GetStartAnyTime() const { return m_cStructure->bStartAnyTime; } - - /// @brief **optional**\n - /// For EPG based (not Manual) timers indicates endTime does not apply. - /// - /// Default = false - void SetEndAnyTime(bool endAnyTime) { m_cStructure->bEndAnyTime = endAnyTime; } - - /// @brief To get with @ref SetEndAnyTime changed values. - bool GetEndAnyTime() const { return m_cStructure->bEndAnyTime; } - - /// @brief **optional**\n - /// A string used to search epg data for repeating epg-based timers. - /// - /// Format is backend-dependent, for example regexp. - void SetEPGSearchString(const std::string& epgSearchString) - { - strncpy(m_cStructure->strEpgSearchString, epgSearchString.c_str(), - sizeof(m_cStructure->strEpgSearchString) - 1); - } - - /// @brief To get with @ref SetEPGSearchString changed values - std::string GetEPGSearchString() const { return m_cStructure->strEpgSearchString; } - - /// @brief **optional**\n - /// Indicates, whether @ref SetEPGSearchString() is to match against the epg - /// episode title only or also against "other" epg data (backend-dependent). - void SetFullTextEpgSearch(bool fullTextEpgSearch) - { - m_cStructure->bFullTextEpgSearch = fullTextEpgSearch; - } - - /// @brief To get with @ref SetFullTextEpgSearch changed values. - bool GetFullTextEpgSearch() const { return m_cStructure->bFullTextEpgSearch; } - - /// @brief **optional**\n - /// The (relative) directory where the recording will be stored in. - void SetDirectory(const std::string& directory) - { - strncpy(m_cStructure->strDirectory, directory.c_str(), sizeof(m_cStructure->strDirectory) - 1); - } - - /// @brief To get with @ref SetDirectory changed values. - std::string GetDirectory() const { return m_cStructure->strDirectory; } - - /// @brief **optional**\n - /// The summary for this timer. - void SetSummary(const std::string& summary) - { - strncpy(m_cStructure->strSummary, summary.c_str(), sizeof(m_cStructure->strSummary) - 1); - } - - /// @brief To get with @ref SetDirectory changed values. - std::string GetSummary() const { return m_cStructure->strSummary; } - - /// @brief **optional**\n - /// The priority of this timer. - void SetPriority(int priority) { m_cStructure->iPriority = priority; } - - /// @brief To get with @ref SetPriority changed values. - int GetPriority() const { return m_cStructure->iPriority; } - - /// @brief **optional**\n - /// Lifetime of recordings created by this timer. - /// - /// Value > 0 days after which recordings will be deleted by the backend, < 0 - /// addon defined integer list reference, == 0 disabled. - void SetLifetime(int priority) { m_cStructure->iLifetime = priority; } - - /// @brief To get with @ref SetLifetime changed values. - int GetLifetime() const { return m_cStructure->iLifetime; } - - /// @brief **optional**\n - /// Maximum number of recordings this timer shall create. - /// - /// Value > 0 number of recordings, < 0 addon defined integer list reference, == 0 disabled. - void SetMaxRecordings(int maxRecordings) { m_cStructure->iMaxRecordings = maxRecordings; } - - /// @brief To get with @ref SetMaxRecordings changed values. - int GetMaxRecordings() const { return m_cStructure->iMaxRecordings; } - - /// @brief **optional**\n - /// Integer ref to addon/backend defined list of recording groups. - void SetRecordingGroup(unsigned int recordingGroup) - { - m_cStructure->iRecordingGroup = recordingGroup; - } - - /// @brief To get with @ref SetRecordingGroup changed values. - unsigned int GetRecordingGroup() const { return m_cStructure->iRecordingGroup; } - - /// @brief **optional**\n - /// The first day this timer is active, for repeating timers. - void SetFirstDay(time_t firstDay) { m_cStructure->firstDay = firstDay; } - - /// @brief To get with @ref SetFirstDay changed values. - time_t GetFirstDay() const { return m_cStructure->firstDay; } - - /// @brief **optional**\n - /// Week days, for repeating timers (see - /// @ref cpp_kodi_addon_pvr_Defs_Timer_PVR_WEEKDAY "PVR_WEEKDAY_*" constant values) - /// - /// @note @ref PVR_WEEKDAY_NONE is default. - /// - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// kodi::addon::PVRTimer tag; - /// tag.SetWeekdays(PVR_WEEKDAY_MONDAY | PVR_WEEKDAY_SATURDAY); - /// ... - /// ~~~~~~~~~~~~~ - void SetWeekdays(unsigned int weekdays) { m_cStructure->iWeekdays = weekdays; } - - /// @brief To get with @ref SetFirstDay changed values. - unsigned int GetWeekdays() const { return m_cStructure->iWeekdays; } - - /// @brief **optional**\n - /// Prevent duplicate episodes. - /// - /// Should 1 if backend should only record new episodes in case of a repeating - /// epg-based timer, 0 if all episodes shall be recorded (no duplicate detection). - /// - /// Actual algorithm for duplicate detection is defined by the backend. - /// Addons may define own values for different duplicate detection - /// algorithms, thus this is not just a bool. - void SetPreventDuplicateEpisodes(unsigned int preventDuplicateEpisodes) - { - m_cStructure->iPreventDuplicateEpisodes = preventDuplicateEpisodes; - } - - /// @brief To get with @ref SetPreventDuplicateEpisodes changed values. - unsigned int GetPreventDuplicateEpisodes() const - { - return m_cStructure->iPreventDuplicateEpisodes; - } - - /// @brief **optional**\n - /// EPG event id associated with this timer. Event ids must be unique for a - /// channel. - /// - /// Valid ids must be greater than @ref EPG_TAG_INVALID_UID. - void SetEPGUid(unsigned int epgUid) { m_cStructure->iEpgUid = epgUid; } - - /// @brief To get with @ref SetEPGUid changed values. - unsigned int GetEPGUid() const { return m_cStructure->iEpgUid; } - - /// @brief **optional**\n - /// If set, the backend starts the recording selected minutes before - /// @ref SetStartTime. - void SetMarginStart(unsigned int marginStart) { m_cStructure->iMarginStart = marginStart; } - - /// @brief To get with @ref SetMarginStart changed values. - unsigned int GetMarginStart() const { return m_cStructure->iMarginStart; } - - /// @brief **optional**\n - /// If set, the backend ends the recording selected minutes after - /// @ref SetEndTime. - void SetMarginEnd(unsigned int marginEnd) { m_cStructure->iMarginEnd = marginEnd; } - - /// @brief To get with @ref SetMarginEnd changed values. - unsigned int GetMarginEnd() const { return m_cStructure->iMarginEnd; } - - /// @brief **optional**\n - /// Genre type. - /// - /// @copydetails EPG_EVENT_CONTENTMASK - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// kodi::addon::PVRTimer tag; - /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MOVIEDRAMA); - /// ... - /// ~~~~~~~~~~~~~ - /// - /// @note If confirmed that backend brings the types in [ETSI EN 300 468](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) - /// conform values, can be @ref EPG_EVENT_CONTENTMASK ignored and to set here - /// with backend value. - /// - void SetGenreType(int genreType) { m_cStructure->iGenreType = genreType; } - - /// @brief To get with @ref SetGenreType changed values. - int GetGenreType() const { return m_cStructure->iGenreType; } - - /// @brief **optional**\n - /// Genre sub type. - /// - /// @copydetails EPG_EVENT_CONTENTMASK - /// - /// Subtypes groups related to set by @ref SetGenreType: - /// | Main genre type | List with available sub genre types - /// |-----------------|----------------------------------------- - /// | @ref EPG_EVENT_CONTENTMASK_UNDEFINED | Nothing, should be 0 - /// | @ref EPG_EVENT_CONTENTMASK_MOVIEDRAMA | @ref EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA - /// | @ref EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS | @ref EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS - /// | @ref EPG_EVENT_CONTENTMASK_SHOW | @ref EPG_EVENT_CONTENTSUBMASK_SHOW - /// | @ref EPG_EVENT_CONTENTMASK_SPORTS | @ref EPG_EVENT_CONTENTSUBMASK_SPORTS - /// | @ref EPG_EVENT_CONTENTMASK_CHILDRENYOUTH | @ref EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH - /// | @ref EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE | @ref EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE - /// | @ref EPG_EVENT_CONTENTMASK_ARTSCULTURE | @ref EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE - /// | @ref EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS | @ref EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS - /// | @ref EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE | @ref EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE - /// | @ref EPG_EVENT_CONTENTMASK_LEISUREHOBBIES | @ref EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES - /// | @ref EPG_EVENT_CONTENTMASK_SPECIAL | @ref EPG_EVENT_CONTENTSUBMASK_SPECIAL - /// | @ref EPG_EVENT_CONTENTMASK_USERDEFINED | Can be defined by you - /// - /// -------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// kodi::addon::PVRTimer tag; - /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE); - /// tag.SetGenreSubType(EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_JAZZ); - /// ... - /// ~~~~~~~~~~~~~ - /// - void SetGenreSubType(int genreSubType) { m_cStructure->iGenreSubType = genreSubType; } - - /// @brief To get with @ref SetGenreType changed values. - int GetGenreSubType() const { return m_cStructure->iGenreSubType; } - - /// @brief **optional**\n - /// Series link for this timer. - /// - /// If set for an epg-based timer rule, matching events will be found by - /// checking with here, instead of @ref SetTitle() (and @ref SetFullTextEpgSearch()). - void SetSeriesLink(const std::string& seriesLink) - { - strncpy(m_cStructure->strSeriesLink, seriesLink.c_str(), - sizeof(m_cStructure->strSeriesLink) - 1); - } - - /// @brief To get with @ref SetSeriesLink changed values. - std::string GetSeriesLink() const { return m_cStructure->strSeriesLink; } - ///@} - -private: - PVRTimer(const PVR_TIMER* data) : CStructHdl(data) {} - PVRTimer(PVR_TIMER* data) : CStructHdl(data) {} -}; - -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimersResultSet class PVRTimersResultSet -/// @ingroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimer -/// @brief **PVR add-on timer transfer class**\n -/// To transfer the content of @ref kodi::addon::CInstancePVRClient::GetTimers(). -/// -/// @note This becomes only be used on addon call above, not usable outside on -/// addon itself. -///@{ -class PVRTimersResultSet -{ -public: - /*! \cond PRIVATE */ - PVRTimersResultSet() = delete; - PVRTimersResultSet(const AddonInstance_PVR* instance, ADDON_HANDLE handle) - : m_instance(instance), m_handle(handle) - { - } - /*! \endcond */ - - /// @addtogroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimersResultSet - ///@{ - - /// @brief To add and give content from addon to Kodi on related call. - /// - /// @param[in] tag The to transferred data. - void Add(const kodi::addon::PVRTimer& tag) - { - m_instance->toKodi->TransferTimerEntry(m_instance->toKodi->kodiInstance, m_handle, tag); - } - - ///@} - -private: - const AddonInstance_PVR* m_instance = nullptr; - const ADDON_HANDLE m_handle; -}; -///@} -//------------------------------------------------------------------------------ - -//============================================================================== -/// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType class PVRTimerType -/// @ingroup cpp_kodi_addon_pvr_Defs_Timer -/// @brief **PVR add-on timer type**\n -/// To define the content of @ref kodi::addon::CInstancePVRClient::GetTimerTypes() -/// given groups. -/// -/// ---------------------------------------------------------------------------- -/// -/// @copydetails cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType_Help -/// -///@{ -class PVRTimerType : public CStructHdl -{ - friend class CInstancePVRClient; - -public: - /*! \cond PRIVATE */ - PVRTimerType() - { - memset(m_cStructure, 0, sizeof(PVR_TIMER_TYPE)); - m_cStructure->iPrioritiesDefault = -1; - m_cStructure->iLifetimesDefault = -1; - m_cStructure->iPreventDuplicateEpisodesDefault = -1; - m_cStructure->iRecordingGroupDefault = -1; - m_cStructure->iMaxRecordingsDefault = -1; - } - PVRTimerType(const PVRTimerType& type) : CStructHdl(type) {} - /*! \endcond */ - - /// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType_Help Value Help - /// @ingroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType - /// ---------------------------------------------------------------------------- - /// - /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType : - /// | Name | Type | Set call | Get call | Usage - /// |------|------|----------|----------|----------- - /// | **Identifier** | `unsigned int` | @ref PVRTimerType::SetId "SetId" | @ref PVRTimerType::GetId "GetId" | *required to set* - /// | **Attributes** | `unsigned int` | @ref PVRTimerType::SetAttributes "SetAttributes" | @ref PVRTimerType::GetAttributes "GetAttributes" | *required to set* - /// | **Description** | `std::string` | @ref PVRTimerType::SetDescription "SetDescription" | @ref PVRTimerType::GetDescription "GetDescription" | *optional* - /// | | | | | | - /// | **Priority selection** | @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue "PVRTypeIntValue" | @ref PVRTimerType::SetPriorities "SetPriorities" | @ref PVRTimerType::GetPriorities "GetPriorities" | *optional* - /// | **Priority default selection** | `int`| @ref PVRTimerType::SetPrioritiesDefault "SetPrioritiesDefault" | @ref PVRTimerType::GetPrioritiesDefault "GetPrioritiesDefault" | *optional* - /// | | | | | | - /// | **Lifetime selection** | @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue "PVRTypeIntValue" | @ref PVRTimerType::SetLifetimes "SetLifetimes" | @ref PVRTimerType::GetLifetimes "GetLifetimes" | *optional* - /// | **Lifetime default selection** | `int`| @ref PVRTimerType::SetLifetimesDefault "SetLifetimesDefault" | @ref PVRTimerType::GetLifetimesDefault "GetLifetimesDefault" | *optional* - /// | | | | | | - /// | **Prevent duplicate episodes selection** | @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue "PVRTypeIntValue" | @ref PVRTimerType::SetPreventDuplicateEpisodes "SetPreventDuplicateEpisodes" | @ref PVRTimerType::GetPreventDuplicateEpisodes "GetPreventDuplicateEpisodes" | *optional* - /// | **Prevent duplicate episodes default** | `int`| @ref PVRTimerType::SetPreventDuplicateEpisodesDefault "SetPreventDuplicateEpisodesDefault" | @ref PVRTimerType::GetPreventDuplicateEpisodesDefault "GetPreventDuplicateEpisodesDefault" | *optional* - /// | | | | | | - /// | **Recording group selection**| @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue "PVRTypeIntValue" | @ref PVRTimerType::SetRecordingGroups "SetRecordingGroups" | @ref PVRTimerType::GetRecordingGroups "GetRecordingGroups" | *optional* - /// | **Recording group default** | `int`| @ref PVRTimerType::SetRecordingGroupDefault "SetRecordingGroupDefault" | @ref PVRTimerType::GetRecordingGroupDefault "GetRecordingGroupDefault" | *optional* - /// | | | | | | - /// | **Max recordings selection** | @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue "PVRTypeIntValue" | @ref PVRTimerType::SetMaxRecordings "SetMaxRecordings" | @ref PVRTimerType::GetMaxRecordings "GetMaxRecordings" | *optional* - /// | **Max recordings default** | `int`| @ref PVRTimerType::SetMaxRecordingsDefault "SetMaxRecordingsDefault" | @ref PVRTimerType::GetMaxRecordingsDefault "GetMaxRecordingsDefault" | *optional* - /// - - /// @addtogroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType - ///@{ - - /// @brief **required**\n - /// This type's identifier. Ids must be > @ref PVR_TIMER_TYPE_NONE. - void SetId(unsigned int id) { m_cStructure->iId = id; } - - /// @brief To get with @ref SetAttributes changed values. - unsigned int GetId() const { return m_cStructure->iId; } - - /// @brief **required**\n - /// Defines the attributes for this type (@ref cpp_kodi_addon_pvr_Defs_Timer_PVR_TIMER_TYPE "PVR_TIMER_TYPE_*" constants). - /// - /// To defines the attributes for a type. These values are bit fields that can be - /// used together. - /// - ///-------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVRTimerType tag; - /// tag.SetAttributes(PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_IS_REPEATING); - /// ~~~~~~~~~~~~~ - /// - void SetAttributes(uint64_t attributes) { m_cStructure->iAttributes = attributes; } - - /// @brief To get with @ref SetAttributes changed values. - uint64_t GetAttributes() const { return m_cStructure->iAttributes; } - - /// @brief **optional**\n - /// A short localized string describing the purpose of the type. (e.g. - /// "Any time at this channel if title matches"). - /// - /// If left blank, Kodi will generate a description based on the attributes - /// REPEATING and MANUAL. (e.g. "Repeating EPG-based.") - void SetDescription(const std::string& description) - { - strncpy(m_cStructure->strDescription, description.c_str(), - sizeof(m_cStructure->strDescription) - 1); - } - - /// @brief To get with @ref SetDescription changed values. - std::string GetDescription() const { return m_cStructure->strDescription; } - - //---------------------------------------------------------------------------- - - /// @brief **optional**\n - /// Priority value definitions. - /// - /// Array containing the possible values for @ref PVRTimer::SetPriority(). - /// - /// @param[in] priorities List of priority values - /// @param[in] prioritiesDefault [opt] The default value in list, can also be - /// set by @ref SetPrioritiesDefault() - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help - void SetPriorities(const std::vector& priorities, int prioritiesDefault = -1) - { - m_cStructure->iPrioritiesSize = static_cast(priorities.size()); - for (unsigned int i = 0; - i < m_cStructure->iPrioritiesSize && i < sizeof(m_cStructure->priorities); ++i) - { - m_cStructure->priorities[i].iValue = priorities[i].GetCStructure()->iValue; - strncpy(m_cStructure->priorities[i].strDescription, - priorities[i].GetCStructure()->strDescription, - sizeof(m_cStructure->priorities[i].strDescription) - 1); - } - if (prioritiesDefault != -1) - m_cStructure->iPrioritiesDefault = prioritiesDefault; - } - - /// @brief To get with @ref SetPriorities changed values. - std::vector GetPriorities() const - { - std::vector ret; - for (unsigned int i = 0; i < m_cStructure->iPrioritiesSize; ++i) - ret.emplace_back(m_cStructure->priorities[i].iValue, - m_cStructure->priorities[i].strDescription); - return ret; - } - - /// @brief **optional**\n - /// The default value for @ref PVRTimer::SetPriority(). - /// - /// @note Must be filled if @ref SetPriorities contain values and not - /// defined there on second function value. - void SetPrioritiesDefault(int prioritiesDefault) - { - m_cStructure->iPrioritiesDefault = prioritiesDefault; - } - - /// @brief To get with @ref SetPrioritiesDefault changed values. - int GetPrioritiesDefault() const { return m_cStructure->iPrioritiesDefault; } - - //---------------------------------------------------------------------------- - - /// @brief **optional**\n - /// Lifetime value definitions. - /// - /// Array containing the possible values for @ref PVRTimer::SetLifetime(). - /// - /// @param[in] lifetimes List of lifetimes values - /// @param[in] lifetimesDefault [opt] The default value in list, can also be - /// set by @ref SetLifetimesDefault() - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help - void SetLifetimes(const std::vector& lifetimes, int lifetimesDefault = -1) - { - m_cStructure->iLifetimesSize = static_cast(lifetimes.size()); - for (unsigned int i = 0; - i < m_cStructure->iLifetimesSize && i < sizeof(m_cStructure->lifetimes); ++i) - { - m_cStructure->lifetimes[i].iValue = lifetimes[i].GetCStructure()->iValue; - strncpy(m_cStructure->lifetimes[i].strDescription, - lifetimes[i].GetCStructure()->strDescription, - sizeof(m_cStructure->lifetimes[i].strDescription) - 1); - } - if (lifetimesDefault != -1) - m_cStructure->iLifetimesDefault = lifetimesDefault; - } - - /// @brief To get with @ref SetLifetimes changed values. - std::vector GetLifetimes() const - { - std::vector ret; - for (unsigned int i = 0; i < m_cStructure->iLifetimesSize; ++i) - ret.emplace_back(m_cStructure->lifetimes[i].iValue, - m_cStructure->lifetimes[i].strDescription); - return ret; - } - - /// @brief **optional**\n - /// The default value for @ref SetLifetimes(). - /// - /// @note Must be filled if @ref SetLifetimes contain values and not - /// defined there on second function value. - void SetLifetimesDefault(int lifetimesDefault) - { - m_cStructure->iLifetimesDefault = lifetimesDefault; - } - - /// @brief To get with @ref SetLifetimesDefault changed values. - int GetLifetimesDefault() const { return m_cStructure->iLifetimesDefault; } - - //---------------------------------------------------------------------------- - - /// @brief **optional**\n - /// Prevent duplicate episodes value definitions. - /// - /// Array containing the possible values for @ref PVRTimer::SetPreventDuplicateEpisodes(). - /// - /// @note Must be filled if @ref PVRTimer::SetPreventDuplicateEpisodes() is not empty. - /// - /// @param[in] preventDuplicateEpisodes List of duplicate episodes values - /// @param[in] preventDuplicateEpisodesDefault [opt] The default value in list, can also be - /// set by @ref SetPreventDuplicateEpisodesDefault() - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help - void SetPreventDuplicateEpisodes( - const std::vector& preventDuplicateEpisodes, - int preventDuplicateEpisodesDefault = -1) - { - m_cStructure->iPreventDuplicateEpisodesSize = - static_cast(preventDuplicateEpisodes.size()); - for (unsigned int i = 0; i < m_cStructure->iPreventDuplicateEpisodesSize && - i < sizeof(m_cStructure->preventDuplicateEpisodes); - ++i) - { - m_cStructure->preventDuplicateEpisodes[i].iValue = - preventDuplicateEpisodes[i].GetCStructure()->iValue; - strncpy(m_cStructure->preventDuplicateEpisodes[i].strDescription, - preventDuplicateEpisodes[i].GetCStructure()->strDescription, - sizeof(m_cStructure->preventDuplicateEpisodes[i].strDescription) - 1); - } - if (preventDuplicateEpisodesDefault != -1) - m_cStructure->iPreventDuplicateEpisodesDefault = preventDuplicateEpisodesDefault; - } - - /// @brief To get with @ref SetPreventDuplicateEpisodes changed values. - std::vector GetPreventDuplicateEpisodes() const - { - std::vector ret; - for (unsigned int i = 0; i < m_cStructure->iPreventDuplicateEpisodesSize; ++i) - ret.emplace_back(m_cStructure->preventDuplicateEpisodes[i].iValue, - m_cStructure->preventDuplicateEpisodes[i].strDescription); - return ret; - } - - /// @brief **optional**\n - /// The default value for @ref PVRTimer::SetPreventDuplicateEpisodes(). - /// - /// @note Must be filled if @ref SetPreventDuplicateEpisodes contain values and not - /// defined there on second function value. - void SetPreventDuplicateEpisodesDefault(int preventDuplicateEpisodesDefault) - { - m_cStructure->iPreventDuplicateEpisodesDefault = preventDuplicateEpisodesDefault; - } - - /// @brief To get with @ref SetPreventDuplicateEpisodesDefault changed values. - int GetPreventDuplicateEpisodesDefault() const - { - return m_cStructure->iPreventDuplicateEpisodesDefault; - } - - //---------------------------------------------------------------------------- - - /// @brief **optional**\n - /// Array containing the possible values of @ref PVRTimer::SetRecordingGroup() - /// - /// @param[in] recordingGroup List of recording group values - /// @param[in] recordingGroupDefault [opt] The default value in list, can also be - /// set by @ref SetRecordingGroupDefault() - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help - void SetRecordingGroups(const std::vector& recordingGroup, - int recordingGroupDefault = -1) - { - m_cStructure->iRecordingGroupSize = static_cast(recordingGroup.size()); - for (unsigned int i = 0; - i < m_cStructure->iRecordingGroupSize && i < sizeof(m_cStructure->recordingGroup); ++i) - { - m_cStructure->recordingGroup[i].iValue = recordingGroup[i].GetCStructure()->iValue; - strncpy(m_cStructure->recordingGroup[i].strDescription, - recordingGroup[i].GetCStructure()->strDescription, - sizeof(m_cStructure->recordingGroup[i].strDescription) - 1); - } - if (recordingGroupDefault != -1) - m_cStructure->iRecordingGroupDefault = recordingGroupDefault; - } - - /// @brief To get with @ref SetRecordingGroups changed values - std::vector GetRecordingGroups() const - { - std::vector ret; - for (unsigned int i = 0; i < m_cStructure->iRecordingGroupSize; ++i) - ret.emplace_back(m_cStructure->recordingGroup[i].iValue, - m_cStructure->recordingGroup[i].strDescription); - return ret; - } - - /// @brief **optional**\n - /// The default value for @ref PVRTimer::SetRecordingGroup(). - /// - /// @note Must be filled if @ref SetRecordingGroups contain values and not - /// defined there on second function value. - void SetRecordingGroupDefault(int recordingGroupDefault) - { - m_cStructure->iRecordingGroupDefault = recordingGroupDefault; - } - - /// @brief To get with @ref SetRecordingGroupDefault changed values - int GetRecordingGroupDefault() const { return m_cStructure->iRecordingGroupDefault; } - - //---------------------------------------------------------------------------- - - /// @brief **optional**\n - /// Array containing the possible values of @ref PVRTimer::SetMaxRecordings(). - /// - /// @param[in] maxRecordings List of lifetimes values - /// @param[in] maxRecordingsDefault [opt] The default value in list, can also be - /// set by @ref SetMaxRecordingsDefault() - /// - /// -------------------------------------------------------------------------- - /// - /// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help - void SetMaxRecordings(const std::vector& maxRecordings, - int maxRecordingsDefault = -1) - { - m_cStructure->iMaxRecordingsSize = static_cast(maxRecordings.size()); - for (unsigned int i = 0; - i < m_cStructure->iMaxRecordingsSize && i < sizeof(m_cStructure->maxRecordings); ++i) - { - m_cStructure->maxRecordings[i].iValue = maxRecordings[i].GetCStructure()->iValue; - strncpy(m_cStructure->maxRecordings[i].strDescription, - maxRecordings[i].GetCStructure()->strDescription, - sizeof(m_cStructure->maxRecordings[i].strDescription) - 1); - } - if (maxRecordingsDefault != -1) - m_cStructure->iMaxRecordingsDefault = maxRecordingsDefault; - } - - /// @brief To get with @ref SetMaxRecordings changed values - std::vector GetMaxRecordings() const - { - std::vector ret; - for (unsigned int i = 0; i < m_cStructure->iMaxRecordingsSize; ++i) - ret.emplace_back(m_cStructure->maxRecordings[i].iValue, - m_cStructure->maxRecordings[i].strDescription); - return ret; - } - - /// @brief **optional**\n - /// The default value for @ref SetMaxRecordings(). - /// - /// Can be set with here if on @ref SetMaxRecordings not given as second value. - void SetMaxRecordingsDefault(int maxRecordingsDefault) - { - m_cStructure->iMaxRecordingsDefault = maxRecordingsDefault; - } - - /// @brief To get with @ref SetMaxRecordingsDefault changed values - int GetMaxRecordingsDefault() const { return m_cStructure->iMaxRecordingsDefault; } - ///@} - -private: - PVRTimerType(const PVR_TIMER_TYPE* type) : CStructHdl(type) {} - PVRTimerType(PVR_TIMER_TYPE* type) : CStructHdl(type) {} -}; -///@} -//------------------------------------------------------------------------------ - -} /* namespace addon */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/CMakeLists.txt deleted file mode 100644 index d7b2269..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -set(HEADERS addon_base.h - audio_engine.h - filesystem.h - general.h - network.h) - -if(NOT ENABLE_STATIC_LIBS) - core_add_library(addons_kodi-addon-dev-kit_include_kodi_c-api) -endif() diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/CMakeLists.txt deleted file mode 100644 index dfcfe66..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -set(HEADERS image_decoder.h - pvr.h) - -if(NOT ENABLE_STATIC_LIBS) - core_add_library(addons_kodi-addon-dev-kit_include_kodi_c-api_addon-instance) -endif() diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/image_decoder.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/image_decoder.h deleted file mode 100644 index 595a5dc..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/image_decoder.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../addon_base.h" - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //============================================================================ - /// @ingroup cpp_kodi_addon_imagedecoder_Defs - /// @brief **Image format types**\n - /// Used to define wanted target format where image decoder should give to - /// Kodi. - /// - typedef enum ImageFormat - { - /// @brief A 32-bit ARGB pixel format, with alpha, that uses 8 bits per - /// channel, ARGBARGB... - ADDON_IMG_FMT_A8R8G8B8 = 1, - - /// @brief A 8, alpha only, 8bpp, AAA... - ADDON_IMG_FMT_A8 = 2, - - /// @brief RGBA 8:8:8:8, with alpha, 32bpp, RGBARGBA... - ADDON_IMG_FMT_RGBA8 = 3, - - /// @brief RGB 8:8:8, with alpha, 24bpp, RGBRGB... - ADDON_IMG_FMT_RGB8 = 4 - } ImageFormat; - //---------------------------------------------------------------------------- - - typedef struct AddonProps_ImageDecoder - { - const char* mimetype; - } AddonProps_ImageDecoder; - - typedef struct AddonToKodiFuncTable_ImageDecoder - { - KODI_HANDLE kodi_instance; - } AddonToKodiFuncTable_ImageDecoder; - - struct AddonInstance_ImageDecoder; - typedef struct KodiToAddonFuncTable_ImageDecoder - { - KODI_HANDLE addonInstance; - bool(__cdecl* load_image_from_memory)(const struct AddonInstance_ImageDecoder* instance, - unsigned char* buffer, - unsigned int buf_size, - unsigned int* width, - unsigned int* height); - - bool(__cdecl* decode)(const struct AddonInstance_ImageDecoder* instance, - unsigned char* pixels, - unsigned int width, - unsigned int height, - unsigned int pitch, - enum ImageFormat format); - } KodiToAddonFuncTable_ImageDecoder; - - typedef struct AddonInstance_ImageDecoder - { - struct AddonProps_ImageDecoder* props; - struct AddonToKodiFuncTable_ImageDecoder* toKodi; - struct KodiToAddonFuncTable_ImageDecoder* toAddon; - } AddonInstance_ImageDecoder; - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr.h deleted file mode 100644 index 2d255ad..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "pvr/pvr_channel_groups.h" -#include "pvr/pvr_channels.h" -#include "pvr/pvr_defines.h" -#include "pvr/pvr_edl.h" -#include "pvr/pvr_epg.h" -#include "pvr/pvr_general.h" -#include "pvr/pvr_menu_hook.h" -#include "pvr/pvr_recordings.h" -#include "pvr/pvr_stream.h" -#include "pvr/pvr_timers.h" - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C" main interface function tables between Kodi and addon -// -// Values related to all parts and not used direct on addon, are to define here. -// -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - /*! - * @internal - * @brief PVR "C" basis API interface - * - * This field contains things that are exchanged between Kodi and Addon - * and is the basis of the PVR-side "C" API. - * - * @warning Care should be taken when making changes in this fields!\n - * Changes can destroy API in addons that have already been created. If a - * necessary change or new feature is added, the version of the PVR - * at @ref ADDON_INSTANCE_VERSION_PVR_MIN must be increased too.\n - * \n - * Conditional changes can be made in some places, without min PVR version - * increase. The add-on should then use CreateInstanceEx and add partial tests - * for this in the C++ header. - * - * Have by add of new parts a look about **Doxygen** `\\ingroup`, so that - * added parts included in documentation. - * - * If you add addon side related documentation, where his dev need know, - * use `///`. For parts only for Kodi make it like here. - * - * @endinternal - */ - - struct AddonInstance_PVR; - - /*! - * @brief Structure to define typical standard values - */ - typedef struct AddonProperties_PVR - { - const char* strUserPath; - const char* strClientPath; - int iEpgMaxDays; - } AddonProperties_PVR; - - /*! - * @brief Structure to transfer the methods from Kodi to addon - */ - typedef struct AddonToKodiFuncTable_PVR - { - // Pointer inside Kodi where used from him to find his class - KODI_HANDLE kodiInstance; - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // General callback functions - void (*AddMenuHook)(void* kodiInstance, const struct PVR_MENUHOOK* hook); - void (*RecordingNotification)(void* kodiInstance, - const char* name, - const char* fileName, - bool on); - void (*ConnectionStateChange)(void* kodiInstance, - const char* strConnectionString, - enum PVR_CONNECTION_STATE newState, - const char* strMessage); - void (*EpgEventStateChange)(void* kodiInstance, - struct EPG_TAG* tag, - enum EPG_EVENT_STATE newState); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // Transfer functions where give data back to Kodi, e.g. GetChannels calls TransferChannelEntry - void (*TransferChannelEntry)(void* kodiInstance, - const ADDON_HANDLE handle, - const struct PVR_CHANNEL* chan); - void (*TransferChannelGroup)(void* kodiInstance, - const ADDON_HANDLE handle, - const struct PVR_CHANNEL_GROUP* group); - void (*TransferChannelGroupMember)(void* kodiInstance, - const ADDON_HANDLE handle, - const struct PVR_CHANNEL_GROUP_MEMBER* member); - void (*TransferEpgEntry)(void* kodiInstance, - const ADDON_HANDLE handle, - const struct EPG_TAG* epgentry); - void (*TransferRecordingEntry)(void* kodiInstance, - const ADDON_HANDLE handle, - const struct PVR_RECORDING* recording); - void (*TransferTimerEntry)(void* kodiInstance, - const ADDON_HANDLE handle, - const struct PVR_TIMER* timer); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // Kodi inform interface functions - void (*TriggerChannelUpdate)(void* kodiInstance); - void (*TriggerChannelGroupsUpdate)(void* kodiInstance); - void (*TriggerEpgUpdate)(void* kodiInstance, unsigned int iChannelUid); - void (*TriggerRecordingUpdate)(void* kodiInstance); - void (*TriggerTimerUpdate)(void* kodiInstance); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // Stream demux interface functions - void (*FreeDemuxPacket)(void* kodiInstance, struct DemuxPacket* pPacket); - struct DemuxPacket* (*AllocateDemuxPacket)(void* kodiInstance, int iDataSize); - struct PVR_CODEC (*GetCodecByName)(const void* kodiInstance, const char* strCodecName); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // New functions becomes added below and can be on another API change (where - // breaks min API version) moved up. - } AddonToKodiFuncTable_PVR; - - /*! - * @brief Structure to transfer the methods from addon to Kodi - */ - typedef struct KodiToAddonFuncTable_PVR - { - // Pointer inside addon where used on them to find his instance class (currently unused!) - KODI_HANDLE addonInstance; - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // General interface functions - enum PVR_ERROR(__cdecl* GetCapabilities)(const struct AddonInstance_PVR*, - struct PVR_ADDON_CAPABILITIES*); - enum PVR_ERROR(__cdecl* GetBackendName)(const struct AddonInstance_PVR*, char*, int); - enum PVR_ERROR(__cdecl* GetBackendVersion)(const struct AddonInstance_PVR*, char*, int); - enum PVR_ERROR(__cdecl* GetBackendHostname)(const struct AddonInstance_PVR*, char*, int); - enum PVR_ERROR(__cdecl* GetConnectionString)(const struct AddonInstance_PVR*, char*, int); - enum PVR_ERROR(__cdecl* GetDriveSpace)(const struct AddonInstance_PVR*, uint64_t*, uint64_t*); - enum PVR_ERROR(__cdecl* CallSettingsMenuHook)(const struct AddonInstance_PVR*, - const struct PVR_MENUHOOK*); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // Channel interface functions - - enum PVR_ERROR(__cdecl* GetChannelsAmount)(const struct AddonInstance_PVR*, int*); - enum PVR_ERROR(__cdecl* GetChannels)(const struct AddonInstance_PVR*, ADDON_HANDLE, bool); - enum PVR_ERROR(__cdecl* GetChannelStreamProperties)(const struct AddonInstance_PVR*, - const struct PVR_CHANNEL*, - struct PVR_NAMED_VALUE*, - unsigned int*); - enum PVR_ERROR(__cdecl* GetSignalStatus)(const struct AddonInstance_PVR*, - int, - struct PVR_SIGNAL_STATUS*); - enum PVR_ERROR(__cdecl* GetDescrambleInfo)(const struct AddonInstance_PVR*, - int, - struct PVR_DESCRAMBLE_INFO*); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // Channel group interface functions - enum PVR_ERROR(__cdecl* GetChannelGroupsAmount)(const struct AddonInstance_PVR*, int*); - enum PVR_ERROR(__cdecl* GetChannelGroups)(const struct AddonInstance_PVR*, ADDON_HANDLE, bool); - enum PVR_ERROR(__cdecl* GetChannelGroupMembers)(const struct AddonInstance_PVR*, - ADDON_HANDLE, - const struct PVR_CHANNEL_GROUP*); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // Channel edit interface functions - enum PVR_ERROR(__cdecl* DeleteChannel)(const struct AddonInstance_PVR*, - const struct PVR_CHANNEL*); - enum PVR_ERROR(__cdecl* RenameChannel)(const struct AddonInstance_PVR*, - const struct PVR_CHANNEL*); - enum PVR_ERROR(__cdecl* OpenDialogChannelSettings)(const struct AddonInstance_PVR*, - const struct PVR_CHANNEL*); - enum PVR_ERROR(__cdecl* OpenDialogChannelAdd)(const struct AddonInstance_PVR*, - const struct PVR_CHANNEL*); - enum PVR_ERROR(__cdecl* OpenDialogChannelScan)(const struct AddonInstance_PVR*); - enum PVR_ERROR(__cdecl* CallChannelMenuHook)(const struct AddonInstance_PVR*, - const PVR_MENUHOOK*, - const PVR_CHANNEL*); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // EPG interface functions - enum PVR_ERROR(__cdecl* GetEPGForChannel)( - const struct AddonInstance_PVR*, ADDON_HANDLE, int, time_t, time_t); - enum PVR_ERROR(__cdecl* IsEPGTagRecordable)(const struct AddonInstance_PVR*, - const struct EPG_TAG*, - bool*); - enum PVR_ERROR(__cdecl* IsEPGTagPlayable)(const struct AddonInstance_PVR*, - const struct EPG_TAG*, - bool*); - enum PVR_ERROR(__cdecl* GetEPGTagEdl)(const struct AddonInstance_PVR*, - const struct EPG_TAG*, - struct PVR_EDL_ENTRY[], - int*); - enum PVR_ERROR(__cdecl* GetEPGTagStreamProperties)(const struct AddonInstance_PVR*, - const struct EPG_TAG*, - struct PVR_NAMED_VALUE*, - unsigned int*); - enum PVR_ERROR(__cdecl* SetEPGTimeFrame)(const struct AddonInstance_PVR*, int); - enum PVR_ERROR(__cdecl* CallEPGMenuHook)(const struct AddonInstance_PVR*, - const struct PVR_MENUHOOK*, - const struct EPG_TAG*); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // Recording interface functions - enum PVR_ERROR(__cdecl* GetRecordingsAmount)(const struct AddonInstance_PVR*, bool, int*); - enum PVR_ERROR(__cdecl* GetRecordings)(const struct AddonInstance_PVR*, ADDON_HANDLE, bool); - enum PVR_ERROR(__cdecl* DeleteRecording)(const struct AddonInstance_PVR*, - const struct PVR_RECORDING*); - enum PVR_ERROR(__cdecl* UndeleteRecording)(const struct AddonInstance_PVR*, - const struct PVR_RECORDING*); - enum PVR_ERROR(__cdecl* DeleteAllRecordingsFromTrash)(const struct AddonInstance_PVR*); - enum PVR_ERROR(__cdecl* RenameRecording)(const struct AddonInstance_PVR*, - const struct PVR_RECORDING*); - enum PVR_ERROR(__cdecl* SetRecordingLifetime)(const struct AddonInstance_PVR*, - const struct PVR_RECORDING*); - enum PVR_ERROR(__cdecl* SetRecordingPlayCount)(const struct AddonInstance_PVR*, - const struct PVR_RECORDING*, - int); - enum PVR_ERROR(__cdecl* SetRecordingLastPlayedPosition)(const struct AddonInstance_PVR*, - const struct PVR_RECORDING*, - int); - enum PVR_ERROR(__cdecl* GetRecordingLastPlayedPosition)(const struct AddonInstance_PVR*, - const struct PVR_RECORDING*, - int*); - enum PVR_ERROR(__cdecl* GetRecordingEdl)(const struct AddonInstance_PVR*, - const struct PVR_RECORDING*, - struct PVR_EDL_ENTRY[], - int*); - enum PVR_ERROR(__cdecl* GetRecordingSize)(const struct AddonInstance_PVR*, - const PVR_RECORDING*, - int64_t*); - enum PVR_ERROR(__cdecl* GetRecordingStreamProperties)(const struct AddonInstance_PVR*, - const struct PVR_RECORDING*, - struct PVR_NAMED_VALUE*, - unsigned int*); - enum PVR_ERROR(__cdecl* CallRecordingMenuHook)(const struct AddonInstance_PVR*, - const struct PVR_MENUHOOK*, - const struct PVR_RECORDING*); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // Timer interface functions - enum PVR_ERROR(__cdecl* GetTimerTypes)(const struct AddonInstance_PVR*, - struct PVR_TIMER_TYPE[], - int*); - enum PVR_ERROR(__cdecl* GetTimersAmount)(const struct AddonInstance_PVR*, int*); - enum PVR_ERROR(__cdecl* GetTimers)(const struct AddonInstance_PVR*, ADDON_HANDLE); - enum PVR_ERROR(__cdecl* AddTimer)(const struct AddonInstance_PVR*, const struct PVR_TIMER*); - enum PVR_ERROR(__cdecl* DeleteTimer)(const struct AddonInstance_PVR*, - const struct PVR_TIMER*, - bool); - enum PVR_ERROR(__cdecl* UpdateTimer)(const struct AddonInstance_PVR*, const struct PVR_TIMER*); - enum PVR_ERROR(__cdecl* CallTimerMenuHook)(const struct AddonInstance_PVR*, - const struct PVR_MENUHOOK*, - const struct PVR_TIMER*); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // Powersaving interface functions - enum PVR_ERROR(__cdecl* OnSystemSleep)(const struct AddonInstance_PVR*); - enum PVR_ERROR(__cdecl* OnSystemWake)(const struct AddonInstance_PVR*); - enum PVR_ERROR(__cdecl* OnPowerSavingActivated)(const struct AddonInstance_PVR*); - enum PVR_ERROR(__cdecl* OnPowerSavingDeactivated)(const struct AddonInstance_PVR*); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // Live stream read interface functions - bool(__cdecl* OpenLiveStream)(const struct AddonInstance_PVR*, const struct PVR_CHANNEL*); - void(__cdecl* CloseLiveStream)(const struct AddonInstance_PVR*); - int(__cdecl* ReadLiveStream)(const struct AddonInstance_PVR*, unsigned char*, unsigned int); - int64_t(__cdecl* SeekLiveStream)(const struct AddonInstance_PVR*, int64_t, int); - int64_t(__cdecl* LengthLiveStream)(const struct AddonInstance_PVR*); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // Recording stream read interface functions - bool(__cdecl* OpenRecordedStream)(const struct AddonInstance_PVR*, const struct PVR_RECORDING*); - void(__cdecl* CloseRecordedStream)(const struct AddonInstance_PVR*); - int(__cdecl* ReadRecordedStream)(const struct AddonInstance_PVR*, unsigned char*, unsigned int); - int64_t(__cdecl* SeekRecordedStream)(const struct AddonInstance_PVR*, int64_t, int); - int64_t(__cdecl* LengthRecordedStream)(const struct AddonInstance_PVR*); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // Stream demux interface functions - enum PVR_ERROR(__cdecl* GetStreamProperties)(const struct AddonInstance_PVR*, - struct PVR_STREAM_PROPERTIES*); - struct DemuxPacket*(__cdecl* DemuxRead)(const struct AddonInstance_PVR*); - void(__cdecl* DemuxReset)(const struct AddonInstance_PVR*); - void(__cdecl* DemuxAbort)(const struct AddonInstance_PVR*); - void(__cdecl* DemuxFlush)(const struct AddonInstance_PVR*); - void(__cdecl* SetSpeed)(const struct AddonInstance_PVR*, int); - void(__cdecl* FillBuffer)(const struct AddonInstance_PVR*, bool); - bool(__cdecl* SeekTime)(const struct AddonInstance_PVR*, double, bool, double*); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // General stream interface functions - bool(__cdecl* CanPauseStream)(const struct AddonInstance_PVR*); - void(__cdecl* PauseStream)(const struct AddonInstance_PVR*, bool); - bool(__cdecl* CanSeekStream)(const struct AddonInstance_PVR*); - bool(__cdecl* IsRealTimeStream)(const struct AddonInstance_PVR*); - enum PVR_ERROR(__cdecl* GetStreamTimes)(const struct AddonInstance_PVR*, - struct PVR_STREAM_TIMES*); - enum PVR_ERROR(__cdecl* GetStreamReadChunkSize)(const struct AddonInstance_PVR*, int*); - - //--==----==----==----==----==----==----==----==----==----==----==----==----== - // New functions becomes added below and can be on another API change (where - // breaks min API version) moved up. - } KodiToAddonFuncTable_PVR; - - typedef struct AddonInstance_PVR - { - struct AddonProperties_PVR* props; - struct AddonToKodiFuncTable_PVR* toKodi; - struct KodiToAddonFuncTable_PVR* toAddon; - } AddonInstance_PVR; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/CMakeLists.txt deleted file mode 100644 index 6617084..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -set(HEADERS pvr_channel_groups.h - pvr_channels.h - pvr_defines.h - pvr_edl.h - pvr_epg.h - pvr_general.h - pvr_menu_hook.h - pvr_recordings.h - pvr_stream.h - pvr_timers.h) - -if(NOT ENABLE_STATIC_LIBS) - core_add_library(addons_kodi-addon-dev-kit_include_kodi_c-api_addon-instance_pvr) -endif() diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channel_groups.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channel_groups.h deleted file mode 100644 index 36f9ed6..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channel_groups.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "pvr_defines.h" - -#include - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C" Definitions group 3 - PVR channel group -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - /*! - * @brief "C" PVR add-on channel group. - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref kodi::addon::PVRChannelGroup for description of values. - */ - typedef struct PVR_CHANNEL_GROUP - { - char strGroupName[PVR_ADDON_NAME_STRING_LENGTH]; - bool bIsRadio; - unsigned int iPosition; - } PVR_CHANNEL_GROUP; - - /*! - * @brief "C" PVR add-on channel group member. - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref kodi::addon::PVRChannelGroupMember for description of values. - */ - typedef struct PVR_CHANNEL_GROUP_MEMBER - { - char strGroupName[PVR_ADDON_NAME_STRING_LENGTH]; - unsigned int iChannelUniqueId; - unsigned int iChannelNumber; - unsigned int iSubChannelNumber; - int iOrder; - } PVR_CHANNEL_GROUP_MEMBER; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channels.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channels.h deleted file mode 100644 index a2ce591..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channels.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "pvr_defines.h" - -#include - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C" Definitions group 2 - PVR channel -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_Channel - /// @brief Denotes that no channel uid is available. - /// - /// Special @ref kodi::addon::PVRTimer::SetClientChannelUid() and - /// @ref kodi::addon::PVRRecording::SetChannelUid() value to indicate that no - /// channel uid is available. - #define PVR_CHANNEL_INVALID_UID -1 - //---------------------------------------------------------------------------- - - /*! - * @brief "C" PVR add-on channel. - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref kodi::addon::PVRChannel for description of values. - */ - typedef struct PVR_CHANNEL - { - unsigned int iUniqueId; - bool bIsRadio; - unsigned int iChannelNumber; - unsigned int iSubChannelNumber; - char strChannelName[PVR_ADDON_NAME_STRING_LENGTH]; - char strMimeType[PVR_ADDON_INPUT_FORMAT_STRING_LENGTH]; - unsigned int iEncryptionSystem; - char strIconPath[PVR_ADDON_URL_STRING_LENGTH]; - bool bIsHidden; - bool bHasArchive; - int iOrder; - } PVR_CHANNEL; - - /*! - * @brief "C" PVR add-on signal status information. - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref kodi::addon::PVRSignalStatus for description of values. - */ - typedef struct PVR_SIGNAL_STATUS - { - char strAdapterName[PVR_ADDON_NAME_STRING_LENGTH]; - char strAdapterStatus[PVR_ADDON_NAME_STRING_LENGTH]; - char strServiceName[PVR_ADDON_NAME_STRING_LENGTH]; - char strProviderName[PVR_ADDON_NAME_STRING_LENGTH]; - char strMuxName[PVR_ADDON_NAME_STRING_LENGTH]; - int iSNR; - int iSignal; - long iBER; - long iUNC; - } PVR_SIGNAL_STATUS; - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo - /// @brief Special @ref cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo - /// value to indicate that a struct member's value is not available - /// - #define PVR_DESCRAMBLE_INFO_NOT_AVAILABLE -1 - //---------------------------------------------------------------------------- - - /*! - * @brief "C" PVR add-on descramble information. - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref kodi::addon::PVRDescrambleInfo for description of values. - */ - typedef struct PVR_DESCRAMBLE_INFO - { - int iPid; - int iCaid; - int iProvid; - int iEcmTime; - int iHops; - char strCardSystem[PVR_ADDON_DESCRAMBLE_INFO_STRING_LENGTH]; - char strReader[PVR_ADDON_DESCRAMBLE_INFO_STRING_LENGTH]; - char strFrom[PVR_ADDON_DESCRAMBLE_INFO_STRING_LENGTH]; - char strProtocol[PVR_ADDON_DESCRAMBLE_INFO_STRING_LENGTH]; - } PVR_DESCRAMBLE_INFO; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_defines.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_defines.h deleted file mode 100644 index af1daae..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_defines.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C" Standard PVR definitions -// -// Values related to all parts and not used direct on addon, are to define here. -// -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - /*! - * @brief API array sizes which are used for data exchange between - * Kodi and addon. - */ - ///@{ - #define PVR_ADDON_NAME_STRING_LENGTH 1024 - #define PVR_ADDON_URL_STRING_LENGTH 1024 - #define PVR_ADDON_DESC_STRING_LENGTH 1024 - #define PVR_ADDON_INPUT_FORMAT_STRING_LENGTH 32 - #define PVR_ADDON_EDL_LENGTH 32 - #define PVR_ADDON_TIMERTYPE_ARRAY_SIZE 32 - #define PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE 512 - #define PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE_SMALL 128 - #define PVR_ADDON_TIMERTYPE_STRING_LENGTH 128 - #define PVR_ADDON_ATTRIBUTE_DESC_LENGTH 128 - #define PVR_ADDON_ATTRIBUTE_VALUES_ARRAY_SIZE 512 - #define PVR_ADDON_DESCRAMBLE_INFO_STRING_LENGTH 64 - #define PVR_ADDON_DATE_STRING_LENGTH 32 - ///@} - - /*! - * @brief "C" Representation of a general attribute integer value. - */ - typedef struct PVR_ATTRIBUTE_INT_VALUE - { - int iValue; - char strDescription[PVR_ADDON_ATTRIBUTE_DESC_LENGTH]; - } PVR_ATTRIBUTE_INT_VALUE; - - /*! - * @brief "C" Representation of a named value. - */ - typedef struct PVR_NAMED_VALUE - { - char strName[PVR_ADDON_NAME_STRING_LENGTH]; - char strValue[PVR_ADDON_NAME_STRING_LENGTH]; - } PVR_NAMED_VALUE; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_edl.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_edl.h deleted file mode 100644 index 8378eaf..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_edl.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "pvr_defines.h" - -#include - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C" Definitions group 8 - PVR Edit definition list (EDL) -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_EDLEntry_PVR_EDL_TYPE enum PVR_EDL_TYPE - /// @ingroup cpp_kodi_addon_pvr_Defs_EDLEntry - /// @brief **Edit definition list types**\n - /// Possible type values for @ref cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry. - /// - ///@{ - typedef enum PVR_EDL_TYPE - { - /// @brief __0__ : cut (completely remove content) - PVR_EDL_TYPE_CUT = 0, - - /// @brief __1__ : mute audio - PVR_EDL_TYPE_MUTE = 1, - - /// @brief __2__ : scene markers (chapter seeking) - PVR_EDL_TYPE_SCENE = 2, - - /// @brief __3__ : commercial breaks - PVR_EDL_TYPE_COMBREAK = 3 - } PVR_EDL_TYPE; - ///@} - //---------------------------------------------------------------------------- - - /*! - * @brief "C" Edit definition list entry. - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref kodi::addon::PVREDLEntry for description of values. - */ - typedef struct PVR_EDL_ENTRY - { - int64_t start; - int64_t end; - enum PVR_EDL_TYPE type; - } PVR_EDL_ENTRY; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_epg.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_epg.h deleted file mode 100644 index 57c603f..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_epg.h +++ /dev/null @@ -1,653 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "pvr_defines.h" - -#include - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C" Definitions group 4 - PVR EPG -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT enum EPG_EVENT_CONTENTMASK (and sub types) - /// @ingroup cpp_kodi_addon_pvr_Defs_epg - /// @brief **EPG entry content event types.**\n - /// These ID's come from the DVB-SI EIT table "content descriptor" - /// Also known under the name "E-book genre assignments". - /// - /// See [ETSI EN 300 468 V1.14.1 (2014-05)](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) - /// about. - /// - /// Values used by this functions: - /// - @ref kodi::addon::PVREPGTag::SetGenreType() - /// - @ref kodi::addon::PVREPGTag::SetGenreSubType() - /// - @ref kodi::addon::PVRRecording::SetGenreType() - /// - @ref kodi::addon::PVRRecording::SetGenreSubType() - /// - /// Following types are listed here: - /// | emum Type | Description - /// |-----------|-------------------- - /// | @ref EPG_EVENT_CONTENTMASK | EPG entry main content to use. - /// | @ref EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_MOVIEDRAMA event types for sub type of "Movie/Drama". - /// | @ref EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS event types for sub type of "News/Current affairs". - /// | @ref EPG_EVENT_CONTENTSUBMASK_SHOW | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SHOW event types for sub type of "Show/Game show". - /// | @ref EPG_EVENT_CONTENTSUBMASK_SPORTS | @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SPORTS event types for sub type of "Sports". - /// | @ref EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_CHILDRENYOUTH event types for sub type of "Children's/Youth programmes". - /// | @ref EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE event types for sub type of "Music/Ballet/Dance". - /// | @ref EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_ARTSCULTURE event types for sub type of "Arts/Culture (without music)". - /// | @ref EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS event types for sub type of "Social/Political issues/Economics". - /// | @ref EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE event types for sub type of "Education/Science/Factual topics". - /// | @ref EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_LEISUREHOBBIES event types for sub type of "Leisure hobbies". - /// | @ref EPG_EVENT_CONTENTSUBMASK_SPECIAL | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SPECIAL event types for sub type of "Special characteristics". - ///@{ - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT - /// @brief EPG entry main content to use. - /// - ///@{ - typedef enum EPG_EVENT_CONTENTMASK - { - /// @brief __0x00__ : Undefined content mask entry. - EPG_EVENT_CONTENTMASK_UNDEFINED = 0x00, - - /// @brief __0x10__ : Movie/Drama.\n - /// \n - /// See @ref EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA about related sub types. - EPG_EVENT_CONTENTMASK_MOVIEDRAMA = 0x10, - - /// @brief __0x20__ : News/Current affairs.\n - /// \n - /// See @ref EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS about related sub types. - EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS = 0x20, - - /// @brief __0x30__ : Show/Game show.\n - /// \n - /// See @ref EPG_EVENT_CONTENTSUBMASK_SHOW about related sub types. - EPG_EVENT_CONTENTMASK_SHOW = 0x30, - - /// @brief __0x40__ : Sports.\n - /// \n - /// See @ref EPG_EVENT_CONTENTSUBMASK_SPORTS about related sub types. - EPG_EVENT_CONTENTMASK_SPORTS = 0x40, - - /// @brief __0x50__ : Children's/Youth programmes.\n - /// \n - /// See @ref EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH about related sub types. - EPG_EVENT_CONTENTMASK_CHILDRENYOUTH = 0x50, - - /// @brief __0x60__ : Music/Ballet/Dance.\n - /// \n - /// See @ref EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE about related sub types. - EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE = 0x60, - - /// @brief __0x70__ : Arts/Culture (without music).\n - /// \n - /// See @ref EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE about related sub types. - EPG_EVENT_CONTENTMASK_ARTSCULTURE = 0x70, - - /// @brief __0x80__ : Social/Political issues/Economics.\n - /// \n - /// See @ref EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS about related sub types. - EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS = 0x80, - - /// @brief __0x90__ : Education/Science/Factual topics.\n - /// \n - /// See @ref EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE about related sub types. - EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE = 0x90, - - /// @brief __0xA0__ : Leisure hobbies.\n - /// \n - /// See @ref EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES about related sub types. - EPG_EVENT_CONTENTMASK_LEISUREHOBBIES = 0xA0, - - /// @brief __0xB0__ : Special characteristics.\n - /// \n - /// See @ref EPG_EVENT_CONTENTSUBMASK_SPECIAL about related sub types. - EPG_EVENT_CONTENTMASK_SPECIAL = 0xB0, - - /// @brief __0xF0__ User defined. - EPG_EVENT_CONTENTMASK_USERDEFINED = 0xF0, - - /// @brief Used to override standard genre types with a own name about.\n - /// \n - /// Set to this value @ref EPG_GENRE_USE_STRING on following places: - /// - @ref kodi::addon::PVREPGTag::SetGenreType() - /// - @ref kodi::addon::PVREPGTag::SetGenreSubType() - /// - @ref kodi::addon::PVRRecording::SetGenreType() - /// - @ref kodi::addon::PVRRecording::SetGenreSubType() - /// - /// @warning Value here is not a [ETSI EN 300 468 V1.14.1 (2014-05)](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) - /// conform. - /// - /// @note This is a own Kodi definition to set that genre is given by own - /// string. Used on @ref kodi::addon::PVREPGTag::SetGenreDescription() and - /// @ref kodi::addon::PVRRecording::SetGenreDescription() - EPG_GENRE_USE_STRING = 0x100 - } EPG_EVENT_CONTENTMASK; - ///@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT - /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_MOVIEDRAMA event - /// types for sub type of "Movie/Drama". - /// - ///@{ - typedef enum EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA - { - /// @brief __0x0__ : Movie/drama (general). - EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_GENERAL = 0x0, - - /// @brief __0x1__ : Detective/thriller. - EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_DETECTIVE_THRILLER = 0x1, - - /// @brief __0x2__ : Adventure/western/war. - EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_ADVENTURE_WESTERN_WAR = 0x2, - - /// @brief __0x3__ : Science fiction/fantasy/horror. - EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_SCIENCEFICTION_FANTASY_HORROR = 0x3, - - /// @brief __0x4__ : Comedy. - EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_COMEDY = 0x4, - - /// @brief __0x5__ : Soap/melodrama/folkloric. - EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_SOAP_MELODRAMA_FOLKLORIC = 0x5, - - /// @brief __0x6__ : Romance. - EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_ROMANCE = 0x6, - - /// @brief __0x7__ : Serious/classical/religious/historical movie/drama. - EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_SERIOUS_CLASSICAL_RELIGIOUS_HISTORICAL = 0x7, - - /// @brief __0x8__ : Adult movie/drama. - EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_ADULT = 0x8, - - /// @brief __0xF__ : User defined. - EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_USERDEFINED = 0xF - } EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA; - ///@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT - /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS event - /// types for sub type of "News/Current affairs". - /// - typedef enum EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS - { - /// @brief __0x0__ : News/current affairs (general). - EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS_GENERAL = 0x0, - - /// @brief __0x1__ : News/weather report. - EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS_WEATHER = 0x1, - - /// @brief __0x2__ : News magazine. - EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS_MAGAZINE = 0x2, - - /// @brief __0x3__ : Documentary. - EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS_DOCUMENTARY = 0x3, - - /// @brief __0x4__ : Discussion/interview/debate - EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS_DISCUSSION_INTERVIEW_DEBATE = 0x4, - - /// @brief __0xF__ : User defined. - EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS_USERDEFINED = 0xF - } EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT - /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SHOW event - /// types for sub type of "Show/Game show". - /// - typedef enum EPG_EVENT_CONTENTSUBMASK_SHOW - { - /// @brief __0x0__ : Show/game show (general). - EPG_EVENT_CONTENTSUBMASK_SHOW_GENERAL = 0x0, - - /// @brief __0x1__ : Game show/quiz/contest. - EPG_EVENT_CONTENTSUBMASK_SHOW_GAMESHOW_QUIZ_CONTEST = 0x1, - - /// @brief __0x2__ : Variety show. - EPG_EVENT_CONTENTSUBMASK_SHOW_VARIETY_SHOW = 0x2, - - /// @brief __0x3__ : Talk show. - EPG_EVENT_CONTENTSUBMASK_SHOW_TALK_SHOW = 0x3, - - /// @brief __0xF__ : User defined. - EPG_EVENT_CONTENTSUBMASK_SHOW_USERDEFINED = 0xF - } EPG_EVENT_CONTENTSUBMASK_SHOW; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT - /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SPORTS event - /// types for sub type of "Sports". - /// - typedef enum EPG_EVENT_CONTENTSUBMASK_SPORTS - { - /// @brief __0x0__ : Sports (general). - EPG_EVENT_CONTENTSUBMASK_SPORTS_GENERAL = 0x0, - - /// @brief __0x1__ : Special events (Olympic Games, World Cup, etc.). - EPG_EVENT_CONTENTSUBMASK_SPORTS_OLYMPICGAMES_WORLDCUP = 0x1, - - /// @brief __0x2__ : Sports magazines. - EPG_EVENT_CONTENTSUBMASK_SPORTS_SPORTS_MAGAZINES = 0x2, - - /// @brief __0x3__ : Football/soccer. - EPG_EVENT_CONTENTSUBMASK_SPORTS_FOOTBALL_SOCCER = 0x3, - - /// @brief __0x4__ : Tennis/squash. - EPG_EVENT_CONTENTSUBMASK_SPORTS_TENNIS_SQUASH = 0x4, - - /// @brief __0x5__ : Team sports (excluding football). - EPG_EVENT_CONTENTSUBMASK_SPORTS_TEAMSPORTS = 0x5, - - /// @brief __0x6__ : Athletics. - EPG_EVENT_CONTENTSUBMASK_SPORTS_ATHLETICS = 0x6, - - /// @brief __0x7__ : Motor sport. - EPG_EVENT_CONTENTSUBMASK_SPORTS_MOTORSPORT = 0x7, - - /// @brief __0x8__ : Water sport. - EPG_EVENT_CONTENTSUBMASK_SPORTS_WATERSPORT = 0x8, - - /// @brief __0x9__ : Winter sports. - EPG_EVENT_CONTENTSUBMASK_SPORTS_WINTERSPORTS = 0x9, - - /// @brief __0xA__ : Equestrian. - EPG_EVENT_CONTENTSUBMASK_SPORTS_EQUESTRIAN = 0xA, - - /// @brief __0xB__ : Martial sports. - EPG_EVENT_CONTENTSUBMASK_SPORTS_MARTIALSPORTS = 0xB, - - /// @brief __0xF__ : User defined. - EPG_EVENT_CONTENTSUBMASK_SPORTS_USERDEFINED = 0xF - } EPG_EVENT_CONTENTSUBMASK_SPORTS; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT - /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_CHILDRENYOUTH event - /// types for sub type of "Children's/Youth programmes". - /// - typedef enum EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH - { - /// @brief __0x0__ : Children's/youth programmes (general). - EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_GENERAL = 0x0, - - /// @brief __0x1__ : Pre-school children's programmes. - EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_PRESCHOOL_CHILDREN = 0x1, - - /// @brief __0x2__ : Entertainment programmes for 6 to 14. - EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_ENTERTAIN_6TO14 = 0x2, - - /// @brief __0x3__ : Entertainment programmes for 10 to 16. - EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_ENTERTAIN_10TO16 = 0x3, - - /// @brief __0x4__ : Informational/educational/school programmes. - EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_INFORMATIONAL_EDUCATIONAL_SCHOOL = 0x4, - - /// @brief __0x5__ : Cartoons/puppets. - EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_CARTOONS_PUPPETS = 0x5, - - /// @brief __0xF__ : User defined. - EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_USERDEFINED = 0xF - } EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT - /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE event - /// types for sub type of "Music/Ballet/Dance". - /// - typedef enum EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE - { - /// @brief __0x0__ : Music/ballet/dance (general). - EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_GENERAL = 0x0, - - /// @brief __0x1__ : Rock/pop. - EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_ROCKPOP = 0x1, - - /// @brief __0x2__ : Serious music/classical music. - EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_SERIOUSMUSIC_CLASSICALMUSIC = 0x2, - - /// @brief __0x3__ : Folk/traditional music. - EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_FOLK_TRADITIONAL_MUSIC = 0x3, - - /// @brief __0x4__ : Jazz. - EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_JAZZ = 0x4, - - /// @brief __0x5__ : Musical/opera. - EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_MUSICAL_OPERA = 0x5, - - /// @brief __0x6__ : Ballet. - EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_BALLET = 0x6, - - /// @brief __0xF__ : User defined. - EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_USERDEFINED = 0xF - } EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT - /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_ARTSCULTURE event - /// types for sub type of "Arts/Culture (without music)". - /// - typedef enum EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE - { - /// @brief __0x0__ : Arts/culture (without music, general). - EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_GENERAL = 0x0, - - /// @brief __0x1__ : Performing arts. - EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_PERFORMINGARTS = 0x1, - - /// @brief __0x2__ : Fine arts. - EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_FINEARTS = 0x2, - - /// @brief __0x3__ : Religion. - EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_RELIGION = 0x3, - - /// @brief __0x4__ : Popular culture/traditional arts. - EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_POPULARCULTURE_TRADITIONALARTS = 0x4, - - /// @brief __0x5__ : Literature. - EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_LITERATURE = 0x5, - - /// @brief __0x6__ : Film/cinema. - EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_FILM_CINEMA = 0x6, - - /// @brief __0x7__ : Experimental film/video. - EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_EXPERIMENTALFILM_VIDEO = 0x7, - - /// @brief __0x8__ : Broadcasting/press. - EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_BROADCASTING_PRESS = 0x8, - - /// @brief __0x9__ : New media. - EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_NEWMEDIA = 0x9, - - /// @brief __0xA__ : Arts/culture magazines. - EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_ARTS_CULTUREMAGAZINES = 0xA, - - /// @brief __0xB__ : Fashion. - EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_FASHION = 0xB, - - /// @brief __0xF__ : User defined. - EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_USERDEFINED = 0xF - } EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT - /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS event - /// types for sub type of "Social/Political issues/Economics". - /// - typedef enum EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS - { - /// @brief __0x0__ : Social/political issues/economics (general). - EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS_GENERAL = 0x0, - - /// @brief __0x1__ : Magazines/reports/documentary. - EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS_MAGAZINES_REPORTS_DOCUMENTARY = 0x1, - - /// @brief __0x2__ : Economics/social advisory. - EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS_ECONOMICS_SOCIALADVISORY = 0x2, - - /// @brief __0x3__ : Remarkable people. - EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS_REMARKABLEPEOPLE = 0x3, - - /// @brief __0xF__ : User defined. - EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS_USERDEFINED = 0xF - } EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT - /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE event - /// types for sub type of "Education/Science/Factual topics". - /// - typedef enum EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE - { - /// @brief __0x0__ : Education/science/factual topics (general). - EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_GENERAL = 0x0, - - /// @brief __0x1__ : Nature/animals/environment. - EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_NATURE_ANIMALS_ENVIRONMENT = 0x1, - - /// @brief __0x2__ : Technology/natural sciences. - EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_TECHNOLOGY_NATURALSCIENCES = 0x2, - - /// @brief __0x3__ : Medicine/physiology/psychology. - EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_MEDICINE_PHYSIOLOGY_PSYCHOLOGY = 0x3, - - /// @brief __0x4__ : Foreign countries/expeditions. - EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_FOREIGNCOUNTRIES_EXPEDITIONS = 0x4, - - /// @brief __0x5__ : Social/spiritual sciences. - EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_SOCIAL_SPIRITUALSCIENCES = 0x5, - - /// @brief __0x6__ : Further education. - EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_FURTHEREDUCATION = 0x6, - - /// @brief __0x7__ : Languages. - EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_LANGUAGES = 0x7, - - /// @brief __0xF__ : User defined. - EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_USERDEFINED = 0xF - } EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT - /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_LEISUREHOBBIES event - /// types for sub type of "Leisure hobbies". - /// - typedef enum EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES - { - /// @brief __0x0__ : Leisure hobbies (general) . - EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_GENERAL = 0x0, - - /// @brief __0x1__ : Tourism/travel. - EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_TOURISM_TRAVEL = 0x1, - - /// @brief __0x2__ : Handicraft. - EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_HANDICRAFT = 0x2, - - /// @brief __0x3__ : Motoring. - EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_MOTORING = 0x3, - - /// @brief __0x4__ : Fitness and health. - EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_FITNESSANDHEALTH = 0x4, - - /// @brief __0x5__ : Cooking. - EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_COOKING = 0x5, - - /// @brief __0x6__ : Advertisement/shopping. - EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_ADVERTISEMENT_SHOPPING = 0x6, - - /// @brief __0x7__ : Gardening. - EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_GARDENING = 0x7, - - /// @brief __0xF__ : User defined. - EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_USERDEFINED = 0xF - } EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT - /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SPECIAL event - /// types for sub type of "Special characteristics". - /// - typedef enum EPG_EVENT_CONTENTSUBMASK_SPECIAL - { - /// @brief __0x0__ : Special characteristics / Original language (general). - EPG_EVENT_CONTENTSUBMASK_SPECIAL_GENERAL = 0x0, - - /// @brief __0x1__ : Black and white. - EPG_EVENT_CONTENTSUBMASK_SPECIAL_BLACKANDWHITE = 0x1, - - /// @brief __0x2__ : Unpublished. - EPG_EVENT_CONTENTSUBMASK_SPECIAL_UNPUBLISHED = 0x2, - - /// @brief __0x3__ : Live broadcast. - EPG_EVENT_CONTENTSUBMASK_SPECIAL_LIVEBROADCAST = 0x3, - - /// @brief __0x4__ : Plano-stereoscopic. - EPG_EVENT_CONTENTSUBMASK_SPECIAL_PLANOSTEREOSCOPIC = 0x4, - - /// @brief __0x5__ : Local or regional. - EPG_EVENT_CONTENTSUBMASK_SPECIAL_LOCALORREGIONAL = 0x5, - - /// @brief __0xF__ : User defined. - EPG_EVENT_CONTENTSUBMASK_SPECIAL_USERDEFINED = 0xF - } EPG_EVENT_CONTENTSUBMASK_SPECIAL; - //---------------------------------------------------------------------------- - - ///@} - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg - /// @brief Separator to use in strings containing different tokens, for example - /// writers, directors, actors of an event. - /// - #define EPG_STRING_TOKEN_SEPARATOR "," - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_epg_EPG_TAG_FLAG enum EPG_TAG_FLAG - /// @ingroup cpp_kodi_addon_pvr_Defs_epg - /// @brief Bit field of independent flags associated with the EPG entry.\n - /// Values used by @ref kodi::addon::PVREPGTag::SetFlags(). - /// - /// Here's example about the use of this: - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVREPGTag tag; - /// tag.SetFlags(EPG_TAG_FLAG_IS_SERIES | EPG_TAG_FLAG_IS_NEW); - /// ~~~~~~~~~~~~~ - /// - ///@{ - typedef enum EPG_TAG_FLAG - { - /// @brief __0000 0000__ : Nothing special to say about this entry. - EPG_TAG_FLAG_UNDEFINED = 0, - - /// @brief __0000 0001__ : This EPG entry is part of a series. - EPG_TAG_FLAG_IS_SERIES = (1 << 0), - - /// @brief __0000 0010__ : This EPG entry will be flagged as new. - EPG_TAG_FLAG_IS_NEW = (1 << 1), - - /// @brief __0000 0100__ : This EPG entry will be flagged as a premiere. - EPG_TAG_FLAG_IS_PREMIERE = (1 << 2), - - /// @brief __0000 1000__ : This EPG entry will be flagged as a finale. - EPG_TAG_FLAG_IS_FINALE = (1 << 3), - - /// @brief __0001 0000__ : This EPG entry will be flagged as live. - EPG_TAG_FLAG_IS_LIVE = (1 << 4), - } EPG_TAG_FLAG; - ///@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg - /// @brief Special PVREPGTag::SetUniqueBroadcastId value - /// - /// Special @ref kodi::addon::PVREPGTag::SetUniqueBroadcastId() value to - /// indicate that a tag has not a valid EPG event uid. - /// - #define EPG_TAG_INVALID_UID 0 - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg - /// @brief Special @ref kodi::addon::PVREPGTag::SetSeriesNumber(), @ref kodi::addon::PVREPGTag::SetEpisodeNumber() - /// and @ref kodi::addon::PVREPGTag::SetEpisodePartNumber() value to indicate - /// it is not to be used. - /// - #define EPG_TAG_INVALID_SERIES_EPISODE -1 - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_epg - /// @brief Timeframe value for use with @ref kodi::addon::CInstancePVRClient::SetEPGTimeFrame() - /// function to indicate "no timeframe". - /// - #define EPG_TIMEFRAME_UNLIMITED -1 - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT_STATE enum EPG_EVENT_STATE - /// @ingroup cpp_kodi_addon_pvr_Defs_epg - /// @brief **EPG event states.**\n - /// Used with @ref kodi::addon::CInstancePVRClient::EpgEventStateChange() - /// callback. - /// - ///@{ - typedef enum EPG_EVENT_STATE - { - /// @brief __0__ : Event created. - EPG_EVENT_CREATED = 0, - - /// @brief __1__ : Event updated. - EPG_EVENT_UPDATED = 1, - - /// @brief __2__ : Event deleted. - EPG_EVENT_DELETED = 2, - } EPG_EVENT_STATE; - ///@} - //---------------------------------------------------------------------------- - - /*! - * @brief "C" PVR add-on channel group member. - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref kodi::addon::PVREPGTag for description of values. - */ - typedef struct EPG_TAG - { - unsigned int iUniqueBroadcastId; - unsigned int iUniqueChannelId; - const char* strTitle; - time_t startTime; - time_t endTime; - const char* strPlotOutline; - const char* strPlot; - const char* strOriginalTitle; - const char* strCast; - const char* strDirector; - const char* strWriter; - int iYear; - const char* strIMDBNumber; - const char* strIconPath; - int iGenreType; - int iGenreSubType; - const char* strGenreDescription; - const char* strFirstAired; - int iParentalRating; - int iStarRating; - int iSeriesNumber; - int iEpisodeNumber; - int iEpisodePartNumber; - const char* strEpisodeName; - unsigned int iFlags; - const char* strSeriesLink; - } EPG_TAG; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_general.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_general.h deleted file mode 100644 index 52787b0..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_general.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "pvr_defines.h" - -#ifdef BUILD_KODI_ADDON -#include "../../../InputStreamConstants.h" -#else -#include "cores/VideoPlayer/Interface/Addon/InputStreamConstants.h" -#endif - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C" Definitions group 1 - General PVR -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_General_PVR_ERROR enum PVR_ERROR - /// @ingroup cpp_kodi_addon_pvr_Defs_General - /// @brief **PVR add-on error codes**\n - /// Used as return values on most PVR related functions. - /// - /// In this way, a PVR instance signals errors in its processing and, under - /// certain conditions, allows Kodi to make corrections. - /// - ///@{ - typedef enum PVR_ERROR - { - /// @brief __0__ : No error occurred. - PVR_ERROR_NO_ERROR = 0, - - /// @brief __-1__ : An unknown error occurred. - PVR_ERROR_UNKNOWN = -1, - - /// @brief __-2__ : The method that Kodi called is not implemented by the add-on. - PVR_ERROR_NOT_IMPLEMENTED = -2, - - /// @brief __-3__ : The backend reported an error, or the add-on isn't connected. - PVR_ERROR_SERVER_ERROR = -3, - - /// @brief __-4__ : The command was sent to the backend, but the response timed out. - PVR_ERROR_SERVER_TIMEOUT = -4, - - /// @brief __-5__ : The command was rejected by the backend. - PVR_ERROR_REJECTED = -5, - - /// @brief __-6__ : The requested item can not be added, because it's already present. - PVR_ERROR_ALREADY_PRESENT = -6, - - /// @brief __-7__ : The parameters of the method that was called are invalid for this - /// operation. - PVR_ERROR_INVALID_PARAMETERS = -7, - - /// @brief __-8__ : A recording is running, so the timer can't be deleted without - /// doing a forced delete. - PVR_ERROR_RECORDING_RUNNING = -8, - - /// @brief __-9__ : The command failed. - PVR_ERROR_FAILED = -9, - } PVR_ERROR; - ///@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_General_PVR_CONNECTION_STATE enum PVR_CONNECTION_STATE - /// @ingroup cpp_kodi_addon_pvr_Defs_General - /// @brief **PVR backend connection states**\n - /// Used with @ref kodi::addon::CInstancePVRClient::ConnectionStateChange() callback. - /// - /// With this, a PVR instance signals that Kodi should perform special - /// operations. - /// - ///@{ - typedef enum PVR_CONNECTION_STATE - { - /// @brief __0__ : Unknown state (e.g. not yet tried to connect). - PVR_CONNECTION_STATE_UNKNOWN = 0, - - /// @brief __1__ : Backend server is not reachable (e.g. server not existing or - /// network down). - PVR_CONNECTION_STATE_SERVER_UNREACHABLE = 1, - - /// @brief __2__ : Backend server is reachable, but there is not the expected type of - /// server running (e.g. HTSP required, but FTP running at given server:port). - PVR_CONNECTION_STATE_SERVER_MISMATCH = 2, - - /// @brief __3__ : Backend server is reachable, but server version does not match - /// client requirements. - PVR_CONNECTION_STATE_VERSION_MISMATCH = 3, - - /// @brief __4__ : Backend server is reachable, but denies client access (e.g. due - /// to wrong credentials). - PVR_CONNECTION_STATE_ACCESS_DENIED = 4, - - /// @brief __5__ : Connection to backend server is established. - PVR_CONNECTION_STATE_CONNECTED = 5, - - /// @brief __6__ : No connection to backend server (e.g. due to network errors or - /// client initiated disconnect). - PVR_CONNECTION_STATE_DISCONNECTED = 6, - - /// @brief __7__ : Connecting to backend. - PVR_CONNECTION_STATE_CONNECTING = 7, - } PVR_CONNECTION_STATE; - ///@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_General_PVR_STREAM_PROPERTY definition PVR_STREAM_PROPERTY - /// @ingroup cpp_kodi_addon_pvr_Defs_General_Inputstream - /// @brief **PVR related stream property values**\n - /// This is used to pass additional data to Kodi on a given PVR stream. - /// - /// Then transferred to livestream, recordings or EPG Tag stream using the - /// properties. - /// - /// This defines are used by: - /// - @ref kodi::addon::CInstancePVRClient::GetChannelStreamProperties() - /// - @ref kodi::addon::CInstancePVRClient::GetEPGTagStreamProperties() - /// - @ref kodi::addon::CInstancePVRClient::GetRecordingStreamProperties() - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// - /// PVR_ERROR CMyPVRInstance::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, - /// std::vector& properties) - /// { - /// ... - /// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM, "inputstream.adaptive"); - /// properties.emplace_back("inputstream.adaptive.manifest_type", "mpd"); - /// properties.emplace_back("inputstream.adaptive.manifest_update_parameter", "full"); - /// properties.emplace_back(PVR_STREAM_PROPERTY_MIMETYPE, "application/xml+dash"); - /// return PVR_ERROR_NO_ERROR; - /// } - /// - /// ... - /// ~~~~~~~~~~~~~ - /// - ///@{ - - /// @brief the URL of the stream that should be played. - /// - #define PVR_STREAM_PROPERTY_STREAMURL "streamurl" - - /// @brief To define in stream properties the name of the inputstream add-on - /// that should be used. - /// - /// Leave blank to use Kodi's built-in playing capabilities or to allow ffmpeg - /// to handle directly set to @ref PVR_STREAM_PROPERTY_VALUE_INPUTSTREAMFFMPEG. - /// - #define PVR_STREAM_PROPERTY_INPUTSTREAM STREAM_PROPERTY_INPUTSTREAM - - /// @brief Identification string for an input stream. - /// - /// This value can be used in addition to @ref PVR_STREAM_PROPERTY_INPUTSTREAM. - /// It is used to provide the respective inpustream addon with additional - /// identification. - /// - /// The difference between this and other stream properties is that it is also - /// passed in the associated @ref kodi::addon::CAddonBase::CreateInstance() - /// call. - /// - /// This makes it possible to select different processing classes within the - /// associated add-on. - /// - /// - ///--------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// - /// // On PVR instance of addon - /// PVR_ERROR CMyPVRInstance::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, - /// std::vector& properties) - /// { - /// ... - /// // For here on example the inpustream is also inside the PVR addon - /// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM, "pvr.my_one"); - /// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM_INSTANCE_ID, "my_special_id_1"); - /// return PVR_ERROR_NO_ERROR; - /// } - /// - /// ... - /// - /// // On CAddonBase part of addon - /// ADDON_STATUS CMyAddon::CreateInstanceEx(int instanceType, - /// std::string instanceID, - /// KODI_HANDLE instance, - /// KODI_HANDLE& addonInstance - /// const std::string& version) - /// { - /// if (instanceType == ADDON_INSTANCE_INPUTSTREAM) - /// { - /// kodi::Log(ADDON_LOG_NOTICE, "Creating my special inputstream"); - /// if (instanceID == "my_special_id_1") - /// addonInstance = new CMyPVRClientInstance_Type1(instance, version); - /// else if (instanceID == "my_special_id_2") - /// addonInstance = new CMyPVRClientInstance_Type2(instance, version); - /// return ADDON_STATUS_OK; - /// } - /// else if (...) - /// { - /// ... - /// } - /// return ADDON_STATUS_UNKNOWN; - /// } - /// - /// ... - /// ~~~~~~~~~~~~~ - /// - #define PVR_STREAM_PROPERTY_INPUTSTREAM_INSTANCE_ID STREAM_PROPERTY_INPUTSTREAM_INSTANCE_ID - - /// @brief the MIME type of the stream that should be played. - /// - #define PVR_STREAM_PROPERTY_MIMETYPE "mimetype" - - /// @brief "true" to denote that the stream that should be played is a - /// realtime stream. - /// - /// Any other value indicates that this is no realtime stream. - /// - #define PVR_STREAM_PROPERTY_ISREALTIMESTREAM STREAM_PROPERTY_ISREALTIMESTREAM - - /// @brief "true" to denote that if the stream is from an EPG tag. - /// - /// It should be played is a live stream. Otherwise if it's a EPG tag it will - /// play as normal video. - /// - #define PVR_STREAM_PROPERTY_EPGPLAYBACKASLIVE "epgplaybackaslive" - - /// @brief Special value for @ref PVR_STREAM_PROPERTY_INPUTSTREAM to use - /// ffmpeg to directly play a stream URL. - #define PVR_STREAM_PROPERTY_VALUE_INPUTSTREAMFFMPEG STREAM_PROPERTY_VALUE_INPUTSTREAMFFMPEG - - ///@} - //----------------------------------------------------------------------------- - - /*! - * @brief "C" PVR add-on capabilities. - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref kodi::addon::PVRCapabilities for description of values. - */ - typedef struct PVR_ADDON_CAPABILITIES - { - bool bSupportsEPG; - bool bSupportsEPGEdl; - bool bSupportsTV; - bool bSupportsRadio; - bool bSupportsRecordings; - bool bSupportsRecordingsUndelete; - bool bSupportsTimers; - bool bSupportsChannelGroups; - bool bSupportsChannelScan; - bool bSupportsChannelSettings; - bool bHandlesInputStream; - bool bHandlesDemuxing; - bool bSupportsRecordingPlayCount; - bool bSupportsLastPlayedPosition; - bool bSupportsRecordingEdl; - bool bSupportsRecordingsRename; - bool bSupportsRecordingsLifetimeChange; - bool bSupportsDescrambleInfo; - bool bSupportsAsyncEPGTransfer; - bool bSupportsRecordingSize; - - unsigned int iRecordingsLifetimesSize; - struct PVR_ATTRIBUTE_INT_VALUE recordingsLifetimeValues[PVR_ADDON_ATTRIBUTE_VALUES_ARRAY_SIZE]; - } PVR_ADDON_CAPABILITIES; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_menu_hook.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_menu_hook.h deleted file mode 100644 index df2216f..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_menu_hook.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "pvr_defines.h" - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C" Definitions group 7 - Menu hook -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_Menuhook_PVR_MENUHOOK_CAT enum PVR_MENUHOOK_CAT - /// @ingroup cpp_kodi_addon_pvr_Defs_Menuhook - /// @brief **PVR context menu hook categories**\n - /// Possible menu types given to Kodi with @ref kodi::addon::CInstancePVRClient::AddMenuHook(). - /// - ///@{ - typedef enum PVR_MENUHOOK_CAT - { - /// @brief __-1__ : Unknown menu hook. - PVR_MENUHOOK_UNKNOWN = -1, - - /// @brief __0__ : All categories. - PVR_MENUHOOK_ALL = 0, - - /// @brief __1__ : For channels. - PVR_MENUHOOK_CHANNEL = 1, - - /// @brief __2__ : For timers. - PVR_MENUHOOK_TIMER = 2, - - /// @brief __3__ : For EPG. - PVR_MENUHOOK_EPG = 3, - - /// @brief __4__ : For recordings. - PVR_MENUHOOK_RECORDING = 4, - - /// @brief __5__ : For deleted recordings. - PVR_MENUHOOK_DELETED_RECORDING = 5, - - /// @brief __6__ : For settings. - PVR_MENUHOOK_SETTING = 6, - } PVR_MENUHOOK_CAT; - ///@} - //---------------------------------------------------------------------------- - - /*! - * @brief "C" PVR add-on menu hook. - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref kodi::addon::PVRMenuhook for description of values. - */ - typedef struct PVR_MENUHOOK - { - unsigned int iHookId; - unsigned int iLocalizedStringId; - enum PVR_MENUHOOK_CAT category; - } PVR_MENUHOOK; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_recordings.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_recordings.h deleted file mode 100644 index 1a7fc66..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_recordings.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "pvr_defines.h" - -#include -#include -#include - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C" Definitions group 5 - PVR recordings -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_Recording_PVR_RECORDING_FLAG enum PVR_RECORDING_FLAG - /// @ingroup cpp_kodi_addon_pvr_Defs_Recording - /// @brief **Bit field of independent flags associated with the EPG entry.**\n - /// Values used by @ref kodi::addon::PVRRecording::SetFlags(). - /// - /// Here's example about the use of this: - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVRRecording tag; - /// tag.SetFlags(PVR_RECORDING_FLAG_IS_SERIES | PVR_RECORDING_FLAG_IS_PREMIERE); - /// ~~~~~~~~~~~~~ - /// - ///@{ - typedef enum PVR_RECORDING_FLAG - { - /// @brief __0000 0000__ : Nothing special to say about this recording. - PVR_RECORDING_FLAG_UNDEFINED = 0, - - /// @brief __0000 0001__ : This recording is part of a series. - PVR_RECORDING_FLAG_IS_SERIES = (1 << 0), - - /// @brief __0000 0010__ : This recording will be flagged as new. - PVR_RECORDING_FLAG_IS_NEW = (1 << 1), - - /// @brief __0000 0100__ : This recording will be flagged as a premiere. - PVR_RECORDING_FLAG_IS_PREMIERE = (1 << 2), - - /// @brief __0000 1000__ : This recording will be flagged as a finale. - PVR_RECORDING_FLAG_IS_FINALE = (1 << 3), - - /// @brief __0001 0000__ : This recording will be flagged as live. - PVR_RECORDING_FLAG_IS_LIVE = (1 << 4), - } PVR_RECORDING_FLAG; - ///@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording - /// @brief Special @ref kodi::addon::PVRRecording::SetSeriesNumber() and - /// @ref kodi::addon::PVRRecording::SetEpisodeNumber() value to indicate it is - /// not to be used. - /// - /// Used if recording has no valid season and/or episode info. - /// - #define PVR_RECORDING_INVALID_SERIES_EPISODE EPG_TAG_INVALID_SERIES_EPISODE - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording - /// @brief Value where set in background to inform that related part not used. - /// - /// Normally this related parts need not to set by this as it is default. - #define PVR_RECORDING_VALUE_NOT_AVAILABLE -1 - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_Recording_PVR_RECORDING_CHANNEL_TYPE enum PVR_RECORDING_CHANNEL_TYPE - /// @ingroup cpp_kodi_addon_pvr_Defs_Recording - /// @brief **PVR recording channel types**\n - /// Used on @ref kodi::addon::PVRRecording::SetChannelType() value to set related - /// type. - /// - ///@{ - typedef enum PVR_RECORDING_CHANNEL_TYPE - { - /// @brief __0__ : Unknown type. - PVR_RECORDING_CHANNEL_TYPE_UNKNOWN = 0, - - /// @brief __1__ : TV channel. - PVR_RECORDING_CHANNEL_TYPE_TV = 1, - - /// @brief __2__ : Radio channel. - PVR_RECORDING_CHANNEL_TYPE_RADIO = 2, - } PVR_RECORDING_CHANNEL_TYPE; - ///@} - //---------------------------------------------------------------------------- - - /*! - * @brief "C" PVR add-on recording. - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref kodi::addon::PVRRecording for description of values. - */ - typedef struct PVR_RECORDING - { - char strRecordingId[PVR_ADDON_NAME_STRING_LENGTH]; - char strTitle[PVR_ADDON_NAME_STRING_LENGTH]; - char strEpisodeName[PVR_ADDON_NAME_STRING_LENGTH]; - int iSeriesNumber; - int iEpisodeNumber; - int iYear; - char strDirectory[PVR_ADDON_URL_STRING_LENGTH]; - char strPlotOutline[PVR_ADDON_DESC_STRING_LENGTH]; - char strPlot[PVR_ADDON_DESC_STRING_LENGTH]; - char strGenreDescription[PVR_ADDON_DESC_STRING_LENGTH]; - char strChannelName[PVR_ADDON_NAME_STRING_LENGTH]; - char strIconPath[PVR_ADDON_URL_STRING_LENGTH]; - char strThumbnailPath[PVR_ADDON_URL_STRING_LENGTH]; - char strFanartPath[PVR_ADDON_URL_STRING_LENGTH]; - time_t recordingTime; - int iDuration; - int iPriority; - int iLifetime; - int iGenreType; - int iGenreSubType; - int iPlayCount; - int iLastPlayedPosition; - bool bIsDeleted; - unsigned int iEpgEventId; - int iChannelUid; - enum PVR_RECORDING_CHANNEL_TYPE channelType; - char strFirstAired[PVR_ADDON_DATE_STRING_LENGTH]; - unsigned int iFlags; - int64_t sizeInBytes; - } PVR_RECORDING; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_stream.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_stream.h deleted file mode 100644 index 04b4059..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_stream.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "pvr_defines.h" - -#ifdef BUILD_KODI_ADDON -#include "../../../DemuxPacket.h" -#else -#include "cores/VideoPlayer/Interface/Addon/DemuxPacket.h" -#endif - -#include -#include - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C" Definitions group 9 - PVR stream definitions (NOTE: Becomes replaced -// in future by inputstream addon instance way) -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_Stream - /// @brief Maximum of allowed streams - /// - #define PVR_STREAM_MAX_STREAMS 20 - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_Stream - /// @brief Invalid codec identifier - /// - #define PVR_INVALID_CODEC_ID 0 - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_addon_pvr_Defs_Stream - /// @brief Invalid codec - /// - #define PVR_INVALID_CODEC \ - { \ - PVR_CODEC_TYPE_UNKNOWN, PVR_INVALID_CODEC_ID \ - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVR_CODEC_TYPE enum PVR_CODEC_TYPE - /// @ingroup cpp_kodi_addon_pvr_Defs_Stream - /// @brief **Inputstream types**\n - /// To identify type on stream. - /// - /// Used on @ref kodi::addon::PVRStreamProperties::SetCodecType and @ref kodi::addon::PVRStreamProperties::SetCodecType. - /// - ///@{ - typedef enum PVR_CODEC_TYPE - { - /// @brief To set nothing defined. - PVR_CODEC_TYPE_UNKNOWN = -1, - - /// @brief To identify @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties as Video. - PVR_CODEC_TYPE_VIDEO, - - /// @brief To identify @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties as Audio. - PVR_CODEC_TYPE_AUDIO, - - /// @brief To identify @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties as Data. - /// - /// With codec id related source identified. - PVR_CODEC_TYPE_DATA, - - /// @brief To identify @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties as Subtitle. - PVR_CODEC_TYPE_SUBTITLE, - - /// @brief To identify @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties as Radio RDS. - PVR_CODEC_TYPE_RDS, - - PVR_CODEC_TYPE_NB - } PVR_CODEC_TYPE; - ///@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVR_CODEC struct PVR_CODEC - /// @ingroup cpp_kodi_addon_pvr_Defs_Stream - /// @brief **Codec identification structure**\n - /// Identifier about stream between Kodi and addon. - /// - ///@{ - typedef struct PVR_CODEC - { - /// @brief Used codec type for stream. - enum PVR_CODEC_TYPE codec_type; - - /// @brief Related codec identifier, normally match the ffmpeg id's. - unsigned int codec_id; - } PVR_CODEC; - ///@} - //---------------------------------------------------------------------------- - - /*! - * @brief "C" Stream properties - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties for description of values. - */ - typedef struct PVR_STREAM_PROPERTIES - { - unsigned int iStreamCount; - struct PVR_STREAM - { - unsigned int iPID; - enum PVR_CODEC_TYPE iCodecType; - unsigned int iCodecId; - char strLanguage[4]; - int iSubtitleInfo; - int iFPSScale; - int iFPSRate; - int iHeight; - int iWidth; - float fAspect; - int iChannels; - int iSampleRate; - int iBlockAlign; - int iBitRate; - int iBitsPerSample; - } stream[PVR_STREAM_MAX_STREAMS]; - } PVR_STREAM_PROPERTIES; - - /*! - * @brief "C" Times of playing stream (Live TV and recordings) - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes for description of values. - */ - typedef struct PVR_STREAM_TIMES - { - time_t startTime; - int64_t ptsStart; - int64_t ptsBegin; - int64_t ptsEnd; - } PVR_STREAM_TIMES; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_timers.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_timers.h deleted file mode 100644 index bc16adb..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_timers.h +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "pvr_defines.h" - -#include -#include -#include - -//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ -// "C" Definitions group 6 - PVR timers -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVR_TIMER_ definition PVR_TIMER (various) - /// @ingroup cpp_kodi_addon_pvr_Defs_Timer - /// @brief **PVR timer various different definitions**\n - /// This mostly used on @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimer "kodi::addon::PVRTimer" - /// to define default or not available. - /// - ///@{ - - //============================================================================ - /// @brief Numeric PVR timer type definitions (@ref kodi::addon::PVRTimer::SetTimerType() - /// values). - /// - /// "Null" value for a numeric timer type. - #define PVR_TIMER_TYPE_NONE 0 - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Special @ref kodi::addon::PVRTimer::SetClientIndex() value to indicate - /// that a timer has not (yet) a valid client index. - /// - /// Timer has not (yet) a valid client index. - #define PVR_TIMER_NO_CLIENT_INDEX 0 - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Special @ref kodi::addon::PVRTimer::SetParentClientIndex() value to - /// indicate that a timer has no parent. - /// - /// Timer has no parent; it was not scheduled by a repeating timer. - #define PVR_TIMER_NO_PARENT PVR_TIMER_NO_CLIENT_INDEX - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Special @ref kodi::addon::PVRTimer::SetEPGUid() value to indicate - /// that a timer has no EPG event uid. - /// - /// Timer has no EPG event unique identifier. - #define PVR_TIMER_NO_EPG_UID EPG_TAG_INVALID_UID - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Special @ref kodi::addon::PVRTimer::SetClientChannelUid() value to - /// indicate "any channel". Useful for some repeating timer types. - /// - /// denotes "any channel", not a specific one. - /// - #define PVR_TIMER_ANY_CHANNEL -1 - //---------------------------------------------------------------------------- - - //============================================================================ - /// @brief Value where set in background to inform that related part not used. - /// - /// Normally this related parts need not to set by this as it is default. - #define PVR_TIMER_VALUE_NOT_AVAILABLE -1 - //---------------------------------------------------------------------------- - - ///@} - //---------------------------------------------------------------------------- - - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVR_TIMER_TYPES enum PVR_TIMER_TYPES - /// @ingroup cpp_kodi_addon_pvr_Defs_Timer - /// @brief **PVR timer type attributes (@ref kodi::addon::PVRTimerType::SetAttributes() values).**\n - /// To defines the attributes for a type. These values are bit fields that can be - /// used together. - /// - ///-------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::addon::PVRTimerType tag; - /// tag.SetAttributes(PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_IS_REPEATING); - /// ~~~~~~~~~~~~~ - /// - ///@{ - typedef enum PVR_TIMER_TYPES - { - /// @brief __0000 0000 0000 0000 0000 0000 0000 0000__ :\n Empty attribute value. - PVR_TIMER_TYPE_ATTRIBUTE_NONE = 0, - - /// @brief __0000 0000 0000 0000 0000 0000 0000 0001__ :\n Defines whether this is a type for - /// manual (time-based) or epg-based timers. - PVR_TIMER_TYPE_IS_MANUAL = (1 << 0), - - /// @brief __0000 0000 0000 0000 0000 0000 0000 0010__ :\n Defines whether this is a type for - /// repeating or one-shot timers. - PVR_TIMER_TYPE_IS_REPEATING = (1 << 1), - - /// @brief __0000 0000 0000 0000 0000 0000 0000 0100__ :\n Timers of this type must not be edited - /// by Kodi. - PVR_TIMER_TYPE_IS_READONLY = (1 << 2), - - /// @brief __0000 0000 0000 0000 0000 0000 0000 1000__ :\n Timers of this type must not be created - /// by Kodi. All other operations are allowed, though. - PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES = (1 << 3), - - /// @brief __0000 0000 0000 0000 0000 0000 0001 0000__ :\n This type supports enabling/disabling - /// of the timer (@ref kodi::addon::PVRTimer::SetState() with - /// @ref PVR_TIMER_STATE_SCHEDULED | @ref PVR_TIMER_STATE_DISABLED). - PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE = (1 << 4), - - /// @brief __0000 0000 0000 0000 0000 0000 0010 0000__ :\n This type supports channels - /// (@ref kodi::addon::PVRTimer::SetClientChannelUid()). - PVR_TIMER_TYPE_SUPPORTS_CHANNELS = (1 << 5), - - /// @brief __0000 0000 0000 0000 0000 0000 0100 0000__ :\n This type supports a recording start - /// time (@ref kodi::addon::PVRTimer::SetStartTime()). - PVR_TIMER_TYPE_SUPPORTS_START_TIME = (1 << 6), - - /// @brief __0000 0000 0000 0000 0000 0000 1000 0000__ :\n This type supports matching epg episode - /// title using@ref kodi::addon::PVRTimer::SetEPGSearchString(). - PVR_TIMER_TYPE_SUPPORTS_TITLE_EPG_MATCH = (1 << 7), - - /// @brief __0000 0000 0000 0000 0000 0001 0000 0000__ :\n This type supports matching "more" epg - /// data (not just episode title) using @ref kodi::addon::PVRTimer::SetEPGSearchString(). - /// Setting @ref PVR_TIMER_TYPE_SUPPORTS_FULLTEXT_EPG_MATCH implies - /// @ref PVR_TIMER_TYPE_SUPPORTS_TITLE_EPG_MATCH. - PVR_TIMER_TYPE_SUPPORTS_FULLTEXT_EPG_MATCH = (1 << 8), - - /// @brief __0000 0000 0000 0000 0000 0010 0000 0000__ :\n This type supports a first day the - /// timer gets active (@ref kodi::addon::PVRTimer::SetFirstDay()). - PVR_TIMER_TYPE_SUPPORTS_FIRST_DAY = (1 << 9), - - /// @brief __0000 0000 0000 0000 0000 0100 0000 0000__ :\n This type supports weekdays for - /// defining the recording schedule (@ref kodi::addon::PVRTimer::SetWeekdays()). - PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS = (1 << 10), - - /// @brief __0000 0000 0000 0000 0000 1000 0000 0000__ :\n This type supports the "record only new episodes" feature - /// (@ref kodi::addon::PVRTimer::SetPreventDuplicateEpisodes()). - PVR_TIMER_TYPE_SUPPORTS_RECORD_ONLY_NEW_EPISODES = (1 << 11), - - /// @brief __0000 0000 0000 0000 0001 0000 0000 0000__ :\n This type supports pre and post record time (@ref kodi::addon::PVRTimer::SetMarginStart(), - /// @ref kodi::addon::PVRTimer::SetMarginEnd()). - PVR_TIMER_TYPE_SUPPORTS_START_END_MARGIN = (1 << 12), - - /// @brief __0000 0000 0000 0000 0010 0000 0000 0000__ :\n This type supports recording priority (@ref kodi::addon::PVRTimer::SetPriority()). - PVR_TIMER_TYPE_SUPPORTS_PRIORITY = (1 << 13), - - /// @brief __0000 0000 0000 0000 0100 0000 0000 0000__ :\n This type supports recording lifetime (@ref kodi::addon::PVRTimer::SetLifetime()). - PVR_TIMER_TYPE_SUPPORTS_LIFETIME = (1 << 14), - - /// @brief __0000 0000 0000 0000 1000 0000 0000 0000__ :\n This type supports placing recordings in user defined folders - /// (@ref kodi::addon::PVRTimer::SetDirectory()). - PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS = (1 << 15), - - /// @brief __0000 0000 0000 0001 0000 0000 0000 0000__ :\n This type supports a list of recording groups - /// (@ref kodi::addon::PVRTimer::SetRecordingGroup()). - PVR_TIMER_TYPE_SUPPORTS_RECORDING_GROUP = (1 << 16), - - /// @brief __0000 0000 0000 0010 0000 0000 0000 0000__ :\n This type supports a recording end time (@ref kodi::addon::PVRTimer::SetEndTime()). - PVR_TIMER_TYPE_SUPPORTS_END_TIME = (1 << 17), - - /// @brief __0000 0000 0000 0100 0000 0000 0000 0000__ :\n Enables an 'Any Time' over-ride option for start time - /// (using @ref kodi::addon::PVRTimer::SetStartAnyTime()). - PVR_TIMER_TYPE_SUPPORTS_START_ANYTIME = (1 << 18), - - /// @brief __0000 0000 0000 1000 0000 0000 0000 0000__ :\n Enables a separate 'Any Time' over-ride for end time - /// (using @ref kodi::addon::PVRTimer::SetEndAnyTime()). - PVR_TIMER_TYPE_SUPPORTS_END_ANYTIME = (1 << 19), - - /// @brief __0000 0000 0001 0000 0000 0000 0000 0000__ :\n This type supports specifying a maximum recordings setting' - /// (@ref kodi::addon::PVRTimer::SetMaxRecordings()). - PVR_TIMER_TYPE_SUPPORTS_MAX_RECORDINGS = (1 << 20), - - /// @brief __0000 0000 0010 0000 0000 0000 0000 0000__ :\n This type should not appear on any create menus which don't - /// provide an associated @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "EPG tag". - PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE = (1 << 21), - - /// @brief __0000 0000 0100 0000 0000 0000 0000 0000__ :\n This type should not appear on any create menus which provide an - /// associated @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "EPG tag". - PVR_TIMER_TYPE_FORBIDS_EPG_TAG_ON_CREATE = (1 << 22), - - /// @brief __0000 0000 1000 0000 0000 0000 0000 0000__ :\n This type should not appear on any create menus unless associated - /// with an @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "EPG tag" with - /// 'series' attributes. - /// - /// Following conditions allow this: - /// - @ref kodi::addon::PVREPGTag::SetFlags() have flag @ref EPG_TAG_FLAG_IS_SERIES - /// - @ref kodi::addon::PVREPGTag::SetSeriesNumber() > 0 - /// - @ref kodi::addon::PVREPGTag::SetEpisodeNumber() > 0 - /// - @ref kodi::addon::PVREPGTag::SetEpisodePartNumber() > 0 - /// - /// Implies @ref PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE. - PVR_TIMER_TYPE_REQUIRES_EPG_SERIES_ON_CREATE = (1 << 23), - - /// @brief __0000 0001 0000 0000 0000 0000 0000 0000__ :\n This type supports 'any channel', for example when defining a timer - /// rule that should match any channel instaed of a particular channel. - PVR_TIMER_TYPE_SUPPORTS_ANY_CHANNEL = (1 << 24), - - /// @brief __0000 0010 0000 0000 0000 0000 0000 0000__ :\n This type should not appear on any create menus which don't provide - /// an associated @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "EPG tag" with - /// a series link. - PVR_TIMER_TYPE_REQUIRES_EPG_SERIESLINK_ON_CREATE = (1 << 25), - - /// @brief __0000 0100 0000 0000 0000 0000 0000 0000__ :\n This type allows deletion of an otherwise read-only timer. - PVR_TIMER_TYPE_SUPPORTS_READONLY_DELETE = (1 << 26), - - /// @brief __0000 1000 0000 0000 0000 0000 0000 0000__ :\n Timers of this type do trigger a reminder if time is up. - PVR_TIMER_TYPE_IS_REMINDER = (1 << 27), - - /// @brief __0001 0000 0000 0000 0000 0000 0000 0000__ :\n This type supports pre record time (@ref kodi::addon::PVRTimer::SetMarginStart()). - PVR_TIMER_TYPE_SUPPORTS_START_MARGIN = (1 << 28), - - /// @brief __0010 0000 0000 0000 0000 0000 0000 0000__ :\n This type supports post record time (@ref kodi::addon::PVRTimer::SetMarginEnd()). - PVR_TIMER_TYPE_SUPPORTS_END_MARGIN = (1 << 29), - } PVR_TIMER_TYPES; - ///@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVR_WEEKDAY enum PVR_WEEKDAY - /// @ingroup cpp_kodi_addon_pvr_Defs_Timer - /// @brief **PVR timer weekdays** (@ref kodi::addon::PVRTimer::SetWeekdays() **values**)\n - /// Used to select the days of a week you want. - /// - /// It can be also used to select several days e.g.: - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// unsigned int day = PVR_WEEKDAY_MONDAY | PVR_WEEKDAY_SATURDAY; - /// ... - /// ~~~~~~~~~~~~~ - /// - ///@{ - typedef enum PVR_WEEKDAYS - { - /// @brief __0000 0000__ : Nothing selected. - PVR_WEEKDAY_NONE = 0, - - /// @brief __0000 0001__ : To select Monday. - PVR_WEEKDAY_MONDAY = (1 << 0), - - /// @brief __0000 0010__ : To select Tuesday. - PVR_WEEKDAY_TUESDAY = (1 << 1), - - /// @brief __0000 0100__ : To select Wednesday. - PVR_WEEKDAY_WEDNESDAY = (1 << 2), - - /// @brief __0000 1000__ : To select Thursday. - PVR_WEEKDAY_THURSDAY = (1 << 3), - - /// @brief __0001 0000__ : To select Friday. - PVR_WEEKDAY_FRIDAY = (1 << 4), - - /// @brief __0010 0000__ : To select Saturday. - PVR_WEEKDAY_SATURDAY = (1 << 5), - - /// @brief __0100 0000__ : To select Sunday. - PVR_WEEKDAY_SUNDAY = (1 << 6), - - /// @brief __0111 1111__ : To select all days of week. - PVR_WEEKDAY_ALLDAYS = PVR_WEEKDAY_MONDAY | PVR_WEEKDAY_TUESDAY | PVR_WEEKDAY_WEDNESDAY | - PVR_WEEKDAY_THURSDAY | PVR_WEEKDAY_FRIDAY | PVR_WEEKDAY_SATURDAY | - PVR_WEEKDAY_SUNDAY - } PVR_WEEKDAY; - ///@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVR_TIMER_STATE enum PVR_TIMER_STATE - /// @ingroup cpp_kodi_addon_pvr_Defs_Timer - /// @brief **PVR timer states**\n - /// To set within @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimer "kodi::addon::PVRTimer" - /// the needed state about. - /// - ///@{ - typedef enum PVR_TIMER_STATE - { - /// @brief __0__ : The timer was just created on the backend and is not yet active. - /// - /// This state must not be used for timers just created on the client side. - PVR_TIMER_STATE_NEW = 0, - - /// @brief __1__ : The timer is scheduled for recording. - PVR_TIMER_STATE_SCHEDULED = 1, - - /// @brief __2__ : The timer is currently recordings. - PVR_TIMER_STATE_RECORDING = 2, - - /// @brief __3__ : The recording completed successfully. - PVR_TIMER_STATE_COMPLETED = 3, - - /// @brief __4__ : Recording started, but was aborted. - PVR_TIMER_STATE_ABORTED = 4, - - /// @brief __5__ : The timer was scheduled, but was canceled. - PVR_TIMER_STATE_CANCELLED = 5, - - /// @brief __6__ : The scheduled timer conflicts with another one, but will be - /// recorded. - PVR_TIMER_STATE_CONFLICT_OK = 6, - - /// @brief __7__ : The scheduled timer conflicts with another one and won't be - /// recorded. - PVR_TIMER_STATE_CONFLICT_NOK = 7, - - /// @brief __8__ : The timer is scheduled, but can't be recorded for some reason. - PVR_TIMER_STATE_ERROR = 8, - - /// @brief __9__ : The timer was disabled by the user, can be enabled via setting - /// the state to @ref PVR_TIMER_STATE_SCHEDULED. - PVR_TIMER_STATE_DISABLED = 9, - } PVR_TIMER_STATE; - ///@} - //---------------------------------------------------------------------------- - - /*! - * @brief "C" PVR add-on timer event. - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimer "kodi::addon::PVRTimer" for - * description of values. - */ - typedef struct PVR_TIMER - { - unsigned int iClientIndex; - unsigned int iParentClientIndex; - int iClientChannelUid; - time_t startTime; - time_t endTime; - bool bStartAnyTime; - bool bEndAnyTime; - enum PVR_TIMER_STATE state; - unsigned int iTimerType; - char strTitle[PVR_ADDON_NAME_STRING_LENGTH]; - char strEpgSearchString[PVR_ADDON_NAME_STRING_LENGTH]; - bool bFullTextEpgSearch; - char strDirectory[PVR_ADDON_URL_STRING_LENGTH]; - char strSummary[PVR_ADDON_DESC_STRING_LENGTH]; - int iPriority; - int iLifetime; - int iMaxRecordings; - unsigned int iRecordingGroup; - time_t firstDay; - unsigned int iWeekdays; - unsigned int iPreventDuplicateEpisodes; - unsigned int iEpgUid; - unsigned int iMarginStart; - unsigned int iMarginEnd; - int iGenreType; - int iGenreSubType; - char strSeriesLink[PVR_ADDON_URL_STRING_LENGTH]; - } PVR_TIMER; - - /*! - * @brief "C" PVR add-on timer event type. - * - * Structure used to interface in "C" between Kodi and Addon. - * - * See @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType "kodi::addon::PVRTimerType" for - * description of values. - */ - typedef struct PVR_TIMER_TYPE - { - unsigned int iId; - uint64_t iAttributes; - char strDescription[PVR_ADDON_TIMERTYPE_STRING_LENGTH]; - - unsigned int iPrioritiesSize; - struct PVR_ATTRIBUTE_INT_VALUE priorities[PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE]; - int iPrioritiesDefault; - - unsigned int iLifetimesSize; - struct PVR_ATTRIBUTE_INT_VALUE lifetimes[PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE]; - int iLifetimesDefault; - - unsigned int iPreventDuplicateEpisodesSize; - struct PVR_ATTRIBUTE_INT_VALUE preventDuplicateEpisodes[PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE]; - unsigned int iPreventDuplicateEpisodesDefault; - - unsigned int iRecordingGroupSize; - struct PVR_ATTRIBUTE_INT_VALUE recordingGroup[PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE]; - unsigned int iRecordingGroupDefault; - - unsigned int iMaxRecordingsSize; - struct PVR_ATTRIBUTE_INT_VALUE maxRecordings[PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE_SMALL]; - int iMaxRecordingsDefault; - } PVR_TIMER_TYPE; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon_base.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon_base.h deleted file mode 100644 index 1924d77..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/addon_base.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (C) 2005-2019 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "stdbool.h" -#include "stdint.h" - -#ifndef TARGET_WINDOWS -#ifndef __cdecl -#define __cdecl -#endif -#ifndef __declspec -#define __declspec(X) -#endif -#endif - -#undef ATTRIBUTE_PACKED -#undef PRAGMA_PACK_BEGIN -#undef PRAGMA_PACK_END - -#if defined(__GNUC__) -#define ATTRIBUTE_PACKED __attribute__((packed)) -#define PRAGMA_PACK 0 -#define ATTRIBUTE_HIDDEN __attribute__((visibility("hidden"))) -#endif - -#if !defined(ATTRIBUTE_PACKED) -#define ATTRIBUTE_PACKED -#define PRAGMA_PACK 1 -#endif - -#if !defined(ATTRIBUTE_HIDDEN) -#define ATTRIBUTE_HIDDEN -#endif - -#ifdef _MSC_VER -#define ATTRIBUTE_FORCEINLINE __forceinline -#elif defined(__GNUC__) -#define ATTRIBUTE_FORCEINLINE inline __attribute__((__always_inline__)) -#elif defined(__CLANG__) -#if __has_attribute(__always_inline__) -#define ATTRIBUTE_FORCEINLINE inline __attribute__((__always_inline__)) -#else -#define ATTRIBUTE_FORCEINLINE inline -#endif -#else -#define ATTRIBUTE_FORCEINLINE inline -#endif - -/* - * To have a on add-on and kodi itself handled string always on known size! - */ -#define ADDON_STANDARD_STRING_LENGTH 1024 -#define ADDON_STANDARD_STRING_LENGTH_SMALL 256 - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //============================================================================ - /// @ingroup cpp_kodi_addon_addonbase - /// @brief Return value of functions in @ref cpp_kodi_addon_addonbase "kodi::addon::CAddonBase" - /// and associated classes. - /// - ///@{ - typedef enum ADDON_STATUS - { - /// @brief For everything OK and no error - ADDON_STATUS_OK, - - /// @brief A needed connection was lost - ADDON_STATUS_LOST_CONNECTION, - - /// @brief Addon needs a restart inside Kodi - ADDON_STATUS_NEED_RESTART, - - /// @brief Necessary settings are not yet set - ADDON_STATUS_NEED_SETTINGS, - - /// @brief Unknown and incomprehensible error - ADDON_STATUS_UNKNOWN, - - /// @brief Permanent failure, like failing to resolve methods - ADDON_STATUS_PERMANENT_FAILURE, - - /* internal used return error if function becomes not used from child on - * addon */ - ADDON_STATUS_NOT_IMPLEMENTED - } ADDON_STATUS; - ///@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_Defs_AddonLog enum AddonLog - /// @ingroup cpp_kodi_Defs - /// @brief **Log file type definitions**\n - /// These define the types of log entries given with @ref kodi::Log() to Kodi. - /// - /// ------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// kodi::Log(ADDON_LOG_ERROR, "%s: There is an error occurred!", __func__); - /// - /// ~~~~~~~~~~~~~ - /// - ///@{ - typedef enum AddonLog - { - /// @brief **0** : To include debug information in the log file. - ADDON_LOG_DEBUG = 0, - - /// @brief **1** : To include information messages in the log file. - ADDON_LOG_INFO = 1, - - /// @brief **2** : To write warnings in the log file. - ADDON_LOG_WARNING = 2, - - /// @brief **3** : To report error messages in the log file. - ADDON_LOG_ERROR = 3, - - /// @brief **4** : To notify fatal unrecoverable errors, which can may also indicate - /// upcoming crashes. - ADDON_LOG_FATAL = 4 - } AddonLog; - ///@} - //---------------------------------------------------------------------------- - - /*! @brief Standard undefined pointer handle */ - typedef void* KODI_HANDLE; - - /*! - * @brief Handle used to return data from the PVR add-on to CPVRClient - */ - struct ADDON_HANDLE_STRUCT - { - void* callerAddress; /*!< address of the caller */ - void* dataAddress; /*!< address to store data in */ - int dataIdentifier; /*!< parameter to pass back when calling the callback */ - }; - typedef struct ADDON_HANDLE_STRUCT* ADDON_HANDLE; - - /*! - * @brief Callback function tables from addon to Kodi - * Set complete from Kodi! - */ - struct AddonToKodiFuncTable_kodi; - struct AddonToKodiFuncTable_kodi_audioengine; - struct AddonToKodiFuncTable_kodi_filesystem; - struct AddonToKodiFuncTable_kodi_network; - struct AddonToKodiFuncTable_kodi_gui; - typedef struct AddonToKodiFuncTable_Addon - { - // Pointer inside Kodi, used on callback functions to give related handle - // class, for this ADDON::CAddonDll inside Kodi. - KODI_HANDLE kodiBase; - - // Function addresses used for callbacks from addon to Kodi - char* (*get_type_version)(void* kodiBase, int type); - - void (*free_string)(void* kodiBase, char* str); - void (*free_string_array)(void* kodiBase, char** arr, int numElements); - char* (*get_addon_path)(void* kodiBase); - char* (*get_base_user_path)(void* kodiBase); - void (*addon_log_msg)(void* kodiBase, const int loglevel, const char* msg); - - bool (*get_setting_bool)(void* kodiBase, const char* id, bool* value); - bool (*get_setting_int)(void* kodiBase, const char* id, int* value); - bool (*get_setting_float)(void* kodiBase, const char* id, float* value); - bool (*get_setting_string)(void* kodiBase, const char* id, char** value); - - bool (*set_setting_bool)(void* kodiBase, const char* id, bool value); - bool (*set_setting_int)(void* kodiBase, const char* id, int value); - bool (*set_setting_float)(void* kodiBase, const char* id, float value); - bool (*set_setting_string)(void* kodiBase, const char* id, const char* value); - - void* (*get_interface)(void* kodiBase, const char* name, const char* version); - - struct AddonToKodiFuncTable_kodi* kodi; - struct AddonToKodiFuncTable_kodi_audioengine* kodi_audioengine; - struct AddonToKodiFuncTable_kodi_filesystem* kodi_filesystem; - struct AddonToKodiFuncTable_kodi_gui* kodi_gui; - struct AddonToKodiFuncTable_kodi_network* kodi_network; - - // Move up by min version change about - bool (*is_setting_using_default)(void* kodiBase, const char* id); - } AddonToKodiFuncTable_Addon; - - /*! - * @brief Function tables from Kodi to addon - */ - typedef struct KodiToAddonFuncTable_Addon - { - void (*destroy)(); - ADDON_STATUS (*get_status)(); - ADDON_STATUS(*create_instance) - (int instanceType, - const char* instanceID, - KODI_HANDLE instance, - const char* version, - KODI_HANDLE* addonInstance, - KODI_HANDLE parent); - void (*destroy_instance)(int instanceType, KODI_HANDLE instance); - ADDON_STATUS (*set_setting)(const char* settingName, const void* settingValue); - } KodiToAddonFuncTable_Addon; - - /*! - * @brief Main structure passed from kodi to addon with basic information needed to - * create add-on. - */ - typedef struct AddonGlobalInterface - { - // String with full path where add-on is installed (without his name on end) - // Set from Kodi! - const char* libBasePath; - - // Master API version of Kodi itself (ADDON_GLOBAL_VERSION_MAIN) - const char* kodi_base_api_version; - - // Pointer of first created instance, used in case this add-on goes with single way - // Set from Kodi! - KODI_HANDLE firstKodiInstance; - - // Pointer to master base class inside add-on - // Set from addon header (kodi::addon::CAddonBase)! - KODI_HANDLE addonBase; - - // Pointer to a instance used on single way (together with this class) - // Set from addon header (kodi::addon::IAddonInstance)! - KODI_HANDLE globalSingleInstance; - - // Callback function tables from addon to Kodi - // Set from Kodi! - AddonToKodiFuncTable_Addon* toKodi; - - // Function tables from Kodi to addon - // Set from addon header! - KodiToAddonFuncTable_Addon* toAddon; - } AddonGlobalInterface; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/audio_engine.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/audio_engine.h deleted file mode 100644 index 02e96ac..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/audio_engine.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright (C) 2005-2019 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "stdint.h" - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ - // "C" Definitions, structures and enumerators of audio engine - //{{{ - - //============================================================================ - /// @defgroup cpp_kodi_audioengine_Defs_AudioEngineStreamOptions enum AudioEngineStreamOptions - /// @ingroup cpp_kodi_audioengine_Defs - /// @brief **Bit options to pass to CAEStream**\n - /// A bit field of stream options. - /// - /// - /// ------------------------------------------------------------------------ - /// - /// **Usage example:** - /// ~~~~~~~~~~~~~{.cpp} - /// // Here only as minimal, "format" must be set to wanted types - /// kodi::audioengine::AudioEngineFormat format; - /// m_audioengine = new kodi::audioengine::CAEStream(format, AUDIO_STREAM_FORCE_RESAMPLE | AUDIO_STREAM_AUTOSTART); - /// ~~~~~~~~~~~~~ - /// - //@{ - typedef enum AudioEngineStreamOptions - { - /// force resample even if rates match - AUDIO_STREAM_FORCE_RESAMPLE = 1 << 0, - /// create the stream paused - AUDIO_STREAM_PAUSED = 1 << 1, - /// autostart the stream when enough data is buffered - AUDIO_STREAM_AUTOSTART = 1 << 2, - } AudioEngineStreamOptions; - //@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_audioengine_Defs_AudioEngineChannel enum AudioEngineChannel - /// @ingroup cpp_kodi_audioengine_Defs - /// @brief **The possible channels**\n - /// Used to set available or used channels on stream. - /// - /// - /// ------------------------------------------------------------------------ - /// - /// **Usage example:** - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::audioengine::AudioEngineFormat format; - /// format.SetChannelLayout(std::vector(AUDIOENGINE_CH_FL, AUDIOENGINE_CH_FR)); - /// ~~~~~~~~~~~~~ - /// - //@{ - enum AudioEngineChannel - { - /// Used inside to indicate the end of a list and not for addon use directly. - AUDIOENGINE_CH_NULL = -1, - /// RAW Audio format - AUDIOENGINE_CH_RAW, - /// Front left - AUDIOENGINE_CH_FL, - /// Front right - AUDIOENGINE_CH_FR, - /// Front center - AUDIOENGINE_CH_FC, - /// LFE / Subwoofer - AUDIOENGINE_CH_LFE, - /// Back left - AUDIOENGINE_CH_BL, - /// Back right - AUDIOENGINE_CH_BR, - /// Front left over center - AUDIOENGINE_CH_FLOC, - /// Front right over center - AUDIOENGINE_CH_FROC, - /// Back center - AUDIOENGINE_CH_BC, - /// Side left - AUDIOENGINE_CH_SL, - /// Side right - AUDIOENGINE_CH_SR, - /// Top front left - AUDIOENGINE_CH_TFL, - /// Top front right - AUDIOENGINE_CH_TFR, - /// Top front center - AUDIOENGINE_CH_TFC, - /// Top center - AUDIOENGINE_CH_TC, - /// Top back left - AUDIOENGINE_CH_TBL, - /// Top back right - AUDIOENGINE_CH_TBR, - /// Top back center - AUDIOENGINE_CH_TBC, - /// Back left over center - AUDIOENGINE_CH_BLOC, - /// Back right over center - AUDIOENGINE_CH_BROC, - /// Maximum possible value, to use e.g. as size inside list - AUDIOENGINE_CH_MAX - }; - //@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_audioengine_Defs_AudioEngineDataFormat enum AudioEngineDataFormat - /// @ingroup cpp_kodi_audioengine_Defs - /// @brief **Audio sample formats**\n - /// The bit layout of the audio data. - /// - /// LE = Little Endian, BE = Big Endian, NE = Native Endian - /// - /// For planar sample formats, each audio channel is in a separate data plane, - /// and linesize is the buffer size, in bytes, for a single plane. All data - /// planes must be the same size. For packed sample formats, only the first - /// data plane is used, and samples for each channel are interleaved. In this - /// case, linesize is the buffer size, in bytes, for the 1 plane. - /// - /// @note This is ordered from the worst to best preferred formats - /// - /// - /// ------------------------------------------------------------------------ - /// - /// **Usage example:** - /// ~~~~~~~~~~~~~{.cpp} - /// kodi::audioengine::AudioEngineFormat format; - /// format.SetDataFormat(AUDIOENGINE_FMT_FLOATP); - /// ~~~~~~~~~~~~~ - /// - //@{ - enum AudioEngineDataFormat - { - /// To define format as invalid - AUDIOENGINE_FMT_INVALID = -1, - - /// Unsigned integer 8 bit - AUDIOENGINE_FMT_U8, - - /// Big Endian signed integer 16 bit - AUDIOENGINE_FMT_S16BE, - /// Little Endian signed integer 16 bit - AUDIOENGINE_FMT_S16LE, - /// Native Endian signed integer 16 bit - AUDIOENGINE_FMT_S16NE, - - /// Big Endian signed integer 32 bit - AUDIOENGINE_FMT_S32BE, - /// Little Endian signed integer 32 bit - AUDIOENGINE_FMT_S32LE, - /// Native Endian signed integer 32 bit - AUDIOENGINE_FMT_S32NE, - - /// Big Endian signed integer 24 bit (in 4 bytes) - AUDIOENGINE_FMT_S24BE4, - /// Little Endian signed integer 24 bit (in 4 bytes) - AUDIOENGINE_FMT_S24LE4, - /// Native Endian signed integer 24 bit (in 4 bytes) - AUDIOENGINE_FMT_S24NE4, - /// S32 with bits_per_sample < 32 - AUDIOENGINE_FMT_S24NE4MSB, - - /// Big Endian signed integer 24 bit (3 bytes) - AUDIOENGINE_FMT_S24BE3, - /// Little Endian signed integer 24 bit (3 bytes) - AUDIOENGINE_FMT_S24LE3, - /// Native Endian signed integer 24 bit (3 bytes) - AUDIOENGINE_FMT_S24NE3, - - /// Double floating point - AUDIOENGINE_FMT_DOUBLE, - /// Floating point - AUDIOENGINE_FMT_FLOAT, - - /// **Bitstream**\n - /// RAW Audio format - AUDIOENGINE_FMT_RAW, - - /// **Planar format**\n - /// Unsigned byte - AUDIOENGINE_FMT_U8P, - /// **Planar format**\n - /// Native Endian signed 16 bit - AUDIOENGINE_FMT_S16NEP, - /// **Planar format**\n - /// Native Endian signed 32 bit - AUDIOENGINE_FMT_S32NEP, - /// **Planar format**\n - /// Native Endian signed integer 24 bit (in 4 bytes) - AUDIOENGINE_FMT_S24NE4P, - /// **Planar format**\n - /// S32 with bits_per_sample < 32 - AUDIOENGINE_FMT_S24NE4MSBP, - /// **Planar format**\n - /// Native Endian signed integer 24 bit (in 3 bytes) - AUDIOENGINE_FMT_S24NE3P, - /// **Planar format**\n - /// Double floating point - AUDIOENGINE_FMT_DOUBLEP, - /// **Planar format**\n - /// Floating point - AUDIOENGINE_FMT_FLOATP, - - /// Amount of sample formats. - AUDIOENGINE_FMT_MAX - }; - //@} - //---------------------------------------------------------------------------- - - /*! - * @brief Internal API structure which are used for data exchange between - * Kodi and addon. - */ - struct AUDIO_ENGINE_FORMAT - { - /*! The stream's data format (eg, AUDIOENGINE_FMT_S16LE) */ - enum AudioEngineDataFormat m_dataFormat; - - /*! The stream's sample rate (eg, 48000) */ - unsigned int m_sampleRate; - - /*! The encoded streams sample rate if a bitstream, otherwise undefined */ - unsigned int m_encodedRate; - - /*! The amount of used speaker channels */ - unsigned int m_channelCount; - - /*! The stream's channel layout */ - enum AudioEngineChannel m_channels[AUDIOENGINE_CH_MAX]; - - /*! The number of frames per period */ - unsigned int m_frames; - - /*! The size of one frame in bytes */ - unsigned int m_frameSize; - }; - - /* A stream handle pointer, which is only used internally by the addon stream handle */ - typedef void AEStreamHandle; - - //}}} - - //¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ - // "C" Internal interface tables for intercommunications between addon and kodi - //{{{ - - /* - * Function address structure, not need to visible on dev kit doxygen - * documentation - */ - typedef struct AddonToKodiFuncTable_kodi_audioengine - { - AEStreamHandle* (*make_stream)(void* kodiBase, - struct AUDIO_ENGINE_FORMAT* format, - unsigned int options); - void (*free_stream)(void* kodiBase, AEStreamHandle* stream); - bool (*get_current_sink_format)(void* kodiBase, struct AUDIO_ENGINE_FORMAT* sink_format); - - // Audio Engine Stream definitions - unsigned int (*aestream_get_space)(void* kodiBase, AEStreamHandle* handle); - unsigned int (*aestream_add_data)(void* kodiBase, - AEStreamHandle* handle, - uint8_t* const* data, - unsigned int offset, - unsigned int frames, - double pts, - bool hasDownmix, - double centerMixLevel); - double (*aestream_get_delay)(void* kodiBase, AEStreamHandle* handle); - bool (*aestream_is_buffering)(void* kodiBase, AEStreamHandle* handle); - double (*aestream_get_cache_time)(void* kodiBase, AEStreamHandle* handle); - double (*aestream_get_cache_total)(void* kodiBase, AEStreamHandle* handle); - void (*aestream_pause)(void* kodiBase, AEStreamHandle* handle); - void (*aestream_resume)(void* kodiBase, AEStreamHandle* handle); - void (*aestream_drain)(void* kodiBase, AEStreamHandle* handle, bool wait); - bool (*aestream_is_draining)(void* kodiBase, AEStreamHandle* handle); - bool (*aestream_is_drained)(void* kodiBase, AEStreamHandle* handle); - void (*aestream_flush)(void* kodiBase, AEStreamHandle* handle); - float (*aestream_get_volume)(void* kodiBase, AEStreamHandle* handle); - void (*aestream_set_volume)(void* kodiBase, AEStreamHandle* handle, float volume); - float (*aestream_get_amplification)(void* kodiBase, AEStreamHandle* handle); - void (*aestream_set_amplification)(void* kodiBase, AEStreamHandle* handle, float amplify); - unsigned int (*aestream_get_frame_size)(void* kodiBase, AEStreamHandle* handle); - unsigned int (*aestream_get_channel_count)(void* kodiBase, AEStreamHandle* handle); - unsigned int (*aestream_get_sample_rate)(void* kodiBase, AEStreamHandle* handle); - enum AudioEngineDataFormat (*aestream_get_data_format)(void* kodiBase, AEStreamHandle* handle); - double (*aestream_get_resample_ratio)(void* kodiBase, AEStreamHandle* handle); - void (*aestream_set_resample_ratio)(void* kodiBase, AEStreamHandle* handle, double ratio); - } AddonToKodiFuncTable_kodi_audioengine; - - //}}} - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/filesystem.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/filesystem.h deleted file mode 100644 index b68a24c..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/filesystem.h +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include -#include -#include - -#ifdef _WIN32 // windows -#ifndef _SSIZE_T_DEFINED -typedef intptr_t ssize_t; -#define _SSIZE_T_DEFINED -#endif // !_SSIZE_T_DEFINED - -// Prevent conflicts with Windows macros where have this names. -#ifdef CreateDirectory -#undef CreateDirectory -#endif // CreateDirectory -#ifdef DeleteFile -#undef DeleteFile -#endif // DeleteFile -#endif // _WIN32 - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ - // "C" Definitions, structures and enumerators of filesystem - //{{{ - - //============================================================================ - /// @defgroup cpp_kodi_vfs_Defs_OpenFileFlags enum OpenFileFlags - /// @ingroup cpp_kodi_vfs_Defs - /// @brief **Flags to define way how file becomes opened**\n - /// The values can be used together, e.g. `file.Open("myfile", ADDON_READ_TRUNCATED | ADDON_READ_CHUNKED);` - /// - /// Used on @ref kodi::vfs::CFile::OpenFile(). - /// - ///@{ - typedef enum OpenFileFlags - { - /// @brief **0000 0000 0001** :\n - /// Indicate that caller can handle truncated reads, where function - /// returns before entire buffer has been filled. - ADDON_READ_TRUNCATED = 0x01, - - /// @brief **0000 0000 0010** :\n - /// Indicate that that caller support read in the minimum defined - /// chunk size, this disables internal cache then. - ADDON_READ_CHUNKED = 0x02, - - /// @brief **0000 0000 0100** :\n - /// Use cache to access this file. - ADDON_READ_CACHED = 0x04, - - /// @brief **0000 0000 1000** :\n - /// Open without caching. regardless to file type. - ADDON_READ_NO_CACHE = 0x08, - - /// @brief **0000 0001 0000** :\n - /// Calcuate bitrate for file while reading. - ADDON_READ_BITRATE = 0x10, - - /// @brief **0000 0010 0000** :\n - /// Indicate to the caller we will seek between multiple streams in - /// the file frequently. - ADDON_READ_MULTI_STREAM = 0x20, - - /// @brief **0000 0100 0000** :\n - /// indicate to the caller file is audio and/or video (and e.g. may - /// grow). - ADDON_READ_AUDIO_VIDEO = 0x40, - - /// @brief **0000 1000 0000** :\n - /// Indicate that caller will do write operations before reading. - ADDON_READ_AFTER_WRITE = 0x80, - - /// @brief **0001 0000 0000** :\n - /// Indicate that caller want to reopen a file if its already open. - ADDON_READ_REOPEN = 0x100 - } OpenFileFlags; - ///@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_vfs_Defs_CURLOptiontype enum CURLOptiontype - /// @ingroup cpp_kodi_vfs_Defs - /// @brief **CURL message types**\n - /// Used on kodi::vfs::CFile::CURLAddOption(). - /// - //@{ - typedef enum CURLOptiontype - { - /// @brief Set a general option. - ADDON_CURL_OPTION_OPTION, - - /// @brief Set a protocol option. - /// - /// The following names for *ADDON_CURL_OPTION_PROTOCOL* are possible: - /// - /// | Option name | Description - /// |------------------------------------:|:-------------------------------- - /// | `accept-charset` | Set the "accept-charset" header - /// | `acceptencoding or encoding` | Set the "accept-encoding" header - /// | `active-remote` | Set the "active-remote" header - /// | `auth` | Set the authentication method. Possible values: any, anysafe, digest, ntlm - /// | `connection-timeout` | Set the connection timeout in seconds - /// | `cookie` | Set the "cookie" header - /// | `customrequest` | Set a custom HTTP request like DELETE - /// | `noshout` | Set to true if kodi detects a stream as shoutcast by mistake. - /// | `postdata` | Set the post body (value needs to be base64 encoded). (Implicitly sets the request to POST) - /// | `referer` | Set the "referer" header - /// | `user-agent` | Set the "user-agent" header - /// | `seekable` | Set the stream seekable. 1: enable, 0: disable - /// | `sslcipherlist` | Set list of accepted SSL ciphers. - /// - ADDON_CURL_OPTION_PROTOCOL, - - /// @brief Set User and password - ADDON_CURL_OPTION_CREDENTIALS, - - /// @brief Add a Header - ADDON_CURL_OPTION_HEADER - } CURLOptiontype; - //@} - //---------------------------------------------------------------------------- - - //============================================================================ - /// @defgroup cpp_kodi_vfs_Defs_FilePropertyTypes enum FilePropertyTypes - /// @ingroup cpp_kodi_vfs_Defs - /// @brief **File property types**\n - /// Mostly to read internet sources. - /// - /// Used on kodi::vfs::CFile::GetPropertyValue() and kodi::vfs::CFile::GetPropertyValues(). - /// - //@{ - typedef enum FilePropertyTypes - { - /// @brief Get protocol response line. - ADDON_FILE_PROPERTY_RESPONSE_PROTOCOL, - /// @brief Get a response header. - ADDON_FILE_PROPERTY_RESPONSE_HEADER, - /// @brief Get file content type. - ADDON_FILE_PROPERTY_CONTENT_TYPE, - /// @brief Get file content charset. - ADDON_FILE_PROPERTY_CONTENT_CHARSET, - /// @brief Get file mime type. - ADDON_FILE_PROPERTY_MIME_TYPE, - /// @brief Get file effective URL (last one if redirected). - ADDON_FILE_PROPERTY_EFFECTIVE_URL - } FilePropertyTypes; - //@} - //---------------------------------------------------------------------------- - - //}}} - - //¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ - // "C" Internal interface tables for intercommunications between addon and kodi - //{{{ - - struct KODI_HTTP_HEADER - { - void* handle; - - char* (*get_value)(void* kodiBase, void* handle, const char* param); - char** (*get_values)(void* kodiBase, void* handle, const char* param, int* length); - char* (*get_header)(void* kodiBase, void* handle); - char* (*get_mime_type)(void* kodiBase, void* handle); - char* (*get_charset)(void* kodiBase, void* handle); - char* (*get_proto_line)(void* kodiBase, void* handle); - }; - - struct STAT_STRUCTURE - { - /// ID of device containing file - uint32_t deviceId; - /// Total size, in bytes - uint64_t size; - /// Time of last access - time_t accessTime; - /// Time of last modification - time_t modificationTime; - /// Time of last status change - time_t statusTime; - /// The stat url is a directory - bool isDirectory; - /// The stat url is a symbolic link - bool isSymLink; - }; - - struct VFS_CACHE_STATUS_DATA - { - uint64_t forward; - unsigned int maxrate; - unsigned int currate; - bool lowspeed; - }; - - struct VFSProperty - { - char* name; - char* val; - }; - - struct VFSDirEntry - { - char* label; //!< item label - char* title; //!< item title - char* path; //!< item path - unsigned int num_props; //!< Number of properties attached to item - struct VFSProperty* properties; //!< Properties - time_t date_time; //!< file creation date & time - bool folder; //!< Item is a folder - uint64_t size; //!< Size of file represented by item - }; - - typedef struct AddonToKodiFuncTable_kodi_filesystem - { - bool (*can_open_directory)(void* kodiBase, const char* url); - bool (*create_directory)(void* kodiBase, const char* path); - bool (*remove_directory)(void* kodiBase, const char* path); - bool (*directory_exists)(void* kodiBase, const char* path); - bool (*get_directory)(void* kodiBase, - const char* path, - const char* mask, - struct VFSDirEntry** items, - unsigned int* num_items); - void (*free_directory)(void* kodiBase, struct VFSDirEntry* items, unsigned int num_items); - - bool (*file_exists)(void* kodiBase, const char* filename, bool useCache); - bool (*stat_file)(void* kodiBase, const char* filename, struct STAT_STRUCTURE* buffer); - bool (*delete_file)(void* kodiBase, const char* filename); - bool (*rename_file)(void* kodiBase, const char* filename, const char* newFileName); - bool (*copy_file)(void* kodiBase, const char* filename, const char* dest); - - char* (*get_file_md5)(void* kodiBase, const char* filename); - char* (*get_cache_thumb_name)(void* kodiBase, const char* filename); - char* (*make_legal_filename)(void* kodiBase, const char* filename); - char* (*make_legal_path)(void* kodiBase, const char* path); - char* (*translate_special_protocol)(void* kodiBase, const char* strSource); - bool (*is_internet_stream)(void* kodiBase, const char* path, bool strictCheck); - bool (*is_on_lan)(void* kodiBase, const char* path); - bool (*is_remote)(void* kodiBase, const char* path); - bool (*is_local)(void* kodiBase, const char* path); - bool (*is_url)(void* kodiBase, const char* path); - bool (*get_http_header)(void* kodiBase, const char* url, struct KODI_HTTP_HEADER* headers); - bool (*get_mime_type)(void* kodiBase, const char* url, char** content, const char* useragent); - bool (*get_content_type)(void* kodiBase, - const char* url, - char** content, - const char* useragent); - bool (*get_cookies)(void* kodiBase, const char* url, char** cookies); - bool (*http_header_create)(void* kodiBase, struct KODI_HTTP_HEADER* headers); - void (*http_header_free)(void* kodiBase, struct KODI_HTTP_HEADER* headers); - - void* (*open_file)(void* kodiBase, const char* filename, unsigned int flags); - void* (*open_file_for_write)(void* kodiBase, const char* filename, bool overwrite); - ssize_t (*read_file)(void* kodiBase, void* file, void* ptr, size_t size); - bool (*read_file_string)(void* kodiBase, void* file, char* szLine, int iLineLength); - ssize_t (*write_file)(void* kodiBase, void* file, const void* ptr, size_t size); - void (*flush_file)(void* kodiBase, void* file); - int64_t (*seek_file)(void* kodiBase, void* file, int64_t position, int whence); - int (*truncate_file)(void* kodiBase, void* file, int64_t size); - int64_t (*get_file_position)(void* kodiBase, void* file); - int64_t (*get_file_length)(void* kodiBase, void* file); - double (*get_file_download_speed)(void* kodiBase, void* file); - void (*close_file)(void* kodiBase, void* file); - int (*get_file_chunk_size)(void* kodiBase, void* file); - bool (*io_control_get_seek_possible)(void* kodiBase, void* file); - bool (*io_control_get_cache_status)(void* kodiBase, - void* file, - struct VFS_CACHE_STATUS_DATA* status); - bool (*io_control_set_cache_rate)(void* kodiBase, void* file, unsigned int rate); - bool (*io_control_set_retry)(void* kodiBase, void* file, bool retry); - char** (*get_property_values)( - void* kodiBase, void* file, int type, const char* name, int* numValues); - - void* (*curl_create)(void* kodiBase, const char* url); - bool (*curl_add_option)( - void* kodiBase, void* file, int type, const char* name, const char* value); - bool (*curl_open)(void* kodiBase, void* file, unsigned int flags); - - bool (*get_disk_space)( - void* kodiBase, const char* path, uint64_t* capacity, uint64_t* free, uint64_t* available); - } AddonToKodiFuncTable_kodi_filesystem; - - //}}} - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/general.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/general.h deleted file mode 100644 index ede8e94..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/general.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - //============================================================================ - /// \ingroup cpp_kodi_Defs - /// @brief For kodi::CurrentKeyboardLayout used defines - /// - typedef enum StdKbButtons - { - /// The quantity of buttons per row on Kodi's standard keyboard - STD_KB_BUTTONS_PER_ROW = 20, - /// The quantity of rows on Kodi's standard keyboard - STD_KB_BUTTONS_MAX_ROWS = 4, - /// Keyboard layout type, this for initial standard - STD_KB_MODIFIER_KEY_NONE = 0x00, - /// Keyboard layout type, this for shift controled layout (uppercase) - STD_KB_MODIFIER_KEY_SHIFT = 0x01, - /// Keyboard layout type, this to show symbols - STD_KB_MODIFIER_KEY_SYMBOL = 0x02 - } StdKbButtons; - //---------------------------------------------------------------------------- - - //============================================================================ - /// \ingroup cpp_kodi_Defs - /// @brief For kodi::QueueNotification() used message types - /// - typedef enum QueueMsg - { - /// Show info notification message - QUEUE_INFO, - /// Show warning notification message - QUEUE_WARNING, - /// Show error notification message - QUEUE_ERROR, - /// Show with own given image and parts if set on values - QUEUE_OWN_STYLE - } QueueMsg; - //---------------------------------------------------------------------------- - - //============================================================================ - /// \ingroup cpp_kodi_Defs - /// @brief Format codes to get string from them. - /// - /// Used on kodi::GetLanguage(). - /// - typedef enum LangFormats - { - /// two letter code as defined in ISO 639-1 - LANG_FMT_ISO_639_1, - /// three letter code as defined in ISO 639-2/T or ISO 639-2/B - LANG_FMT_ISO_639_2, - /// full language name in English - LANG_FMT_ENGLISH_NAME - } LangFormats; - //---------------------------------------------------------------------------- - - /* - * For interface between add-on and kodi. - * - * This structure defines the addresses of functions stored inside Kodi which - * are then available for the add-on to call - * - * All function pointers there are used by the C++ interface functions below. - * You find the set of them on xbmc/addons/interfaces/General.cpp - * - * Note: For add-on development itself this is not needed - */ - typedef struct AddonKeyboardKeyTable - { - char* keys[STD_KB_BUTTONS_MAX_ROWS][STD_KB_BUTTONS_PER_ROW]; - } AddonKeyboardKeyTable; - typedef struct AddonToKodiFuncTable_kodi - { - char* (*get_addon_info)(void* kodiBase, const char* id); - bool (*open_settings_dialog)(void* kodiBase); - char* (*unknown_to_utf8)(void* kodiBase, const char* source, bool* ret, bool failOnBadChar); - char* (*get_localized_string)(void* kodiBase, long label_id); - char* (*get_language)(void* kodiBase, int format, bool region); - bool (*queue_notification)(void* kodiBase, - int type, - const char* header, - const char* message, - const char* imageFile, - unsigned int displayTime, - bool withSound, - unsigned int messageTime); - void (*get_md5)(void* kodiBase, const char* text, char* md5); - char* (*get_temp_path)(void* kodiBase); - char* (*get_region)(void* kodiBase, const char* id); - void (*get_free_mem)(void* kodiBase, long* free, long* total, bool as_bytes); - int (*get_global_idle_time)(void* kodiBase); - bool (*is_addon_avilable)(void* kodiBase, const char* id, char** version, bool* enabled); - void (*kodi_version)(void* kodiBase, - char** compile_name, - int* major, - int* minor, - char** revision, - char** tag, - char** tagversion); - char* (*get_current_skin_id)(void* kodiBase); - bool (*get_keyboard_layout)(void* kodiBase, - char** layout_name, - int modifier_key, - struct AddonKeyboardKeyTable* layout); - bool (*change_keyboard_layout)(void* kodiBase, char** layout_name); - } AddonToKodiFuncTable_kodi; - - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/network.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/network.h deleted file mode 100644 index 6c0441f..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/c-api/network.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - /* - * For interface between add-on and kodi. - * - * This structure defines the addresses of functions stored inside Kodi which - * are then available for the add-on to call - * - * All function pointers there are used by the C++ interface functions below. - * You find the set of them on xbmc/addons/interfaces/General.cpp - * - * Note: For add-on development itself this is not needed - */ - typedef struct AddonToKodiFuncTable_kodi_network - { - bool (*wake_on_lan)(void* kodiBase, const char* mac); - char* (*get_ip_address)(void* kodiBase); - char* (*dns_lookup)(void* kodiBase, const char* url, bool* ret); - char* (*url_encode)(void* kodiBase, const char* url); - char* (*get_hostname)(void* kodiBase); - bool (*is_local_host)(void* kodiBase, const char* hostname); - bool (*is_host_on_lan)(void* kodiBase, const char* hostname, bool offLineCheck); - char* (*get_user_agent)(void* kodiBase); - } AddonToKodiFuncTable_kodi_network; - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/CMakeLists.txt deleted file mode 100644 index 834ec00..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -set(HEADERS General.h - ListItem.h - Window.h - definitions.h - renderHelper.h) - -if(NOT ENABLE_STATIC_LIBS) - core_add_library(addons_kodi-addon-dev-kit_include_kodi_gui) -endif() diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/General.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/General.h deleted file mode 100644 index b5a6393..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/General.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../AddonBase.h" -#include "definitions.h" - -namespace kodi -{ -namespace gui -{ - - //============================================================================ - /// - // \defgroup cpp_kodi_gui ::general - /// \addtogroup cpp_kodi_gui - /// @{ - /// @brief **Allow use of binary classes and function to use on add-on's** - /// - /// Permits the use of the required functions of the add-on to Kodi. This class - /// also contains some functions to the control. - /// - /// These are pure functions them no other initialization need. - /// - /// It has the header \ref kodi/gui/General.h "#include " be included - /// to enjoy it. - /// - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui - /// @brief Performs a graphical lock of rendering engine - /// - inline void ATTRIBUTE_HIDDEN Lock() - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->general->lock(); - } - - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui - /// @brief Performs a graphical unlock of previous locked rendering engine - /// - inline void ATTRIBUTE_HIDDEN Unlock() - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->general->unlock(); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui - /// @brief Return the the current screen height with pixel - /// - inline int ATTRIBUTE_HIDDEN GetScreenHeight() - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->general->get_screen_height(CAddonBase::m_interface->toKodi->kodiBase); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui - /// @brief Return the the current screen width with pixel - /// - inline int ATTRIBUTE_HIDDEN GetScreenWidth() - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->general->get_screen_width(CAddonBase::m_interface->toKodi->kodiBase); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui - /// @brief Return the the current screen rendering resolution - /// - inline int ATTRIBUTE_HIDDEN GetVideoResolution() - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->general->get_video_resolution(CAddonBase::m_interface->toKodi->kodiBase); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui - /// @brief Returns the id for the current 'active' dialog as an integer. - /// - /// @return The currently active dialog Id - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// .. - /// int wid = kodi::gui::GetCurrentWindowDialogId(); - /// .. - /// ~~~~~~~~~~~~~ - /// - inline int ATTRIBUTE_HIDDEN GetCurrentWindowDialogId() - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->general->get_current_window_dialog_id(CAddonBase::m_interface->toKodi->kodiBase); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui - /// @brief Returns the id for the current 'active' window as an integer. - /// - /// @return The currently active window Id - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// .. - /// int wid = kodi::gui::GetCurrentWindowId(); - /// .. - /// ~~~~~~~~~~~~~ - /// - inline int ATTRIBUTE_HIDDEN GetCurrentWindowId() - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->general->get_current_window_id(CAddonBase::m_interface->toKodi->kodiBase); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui - /// \brief To get hardware specific device context interface - /// - /// \return The currently active device context - /// - /// \warning This function is only be supported under Windows, on all other - /// OS it return `nullptr`! - /// - /// \note Returned Windows class pointer is `ID3D11DeviceContext1`. - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// .. - /// ID3D11DeviceContext1* context = static_cast(kodi::gui::GetHWContext()); - /// .. - /// ~~~~~~~~~~~~~ - /// - inline void* GetHWContext() - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->general->get_hw_context(CAddonBase::m_interface->toKodi->kodiBase); - } - //-------------------------------------------------------------------------- - -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/ListItem.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/ListItem.h deleted file mode 100644 index 1af4863..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/ListItem.h +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../AddonBase.h" -#include "definitions.h" - -#include - -namespace kodi -{ -namespace gui -{ - - class CWindow; - - class ATTRIBUTE_HIDDEN CAddonGUIControlBase - { - public: - GUIHANDLE GetControlHandle() const { return m_controlHandle; } - - protected: - explicit CAddonGUIControlBase(CAddonGUIControlBase* window) - : m_controlHandle(nullptr), - m_interface(::kodi::addon::CAddonBase::m_interface->toKodi), - m_Window(window) {} - - virtual ~CAddonGUIControlBase() = default; - - friend class CWindow; - - GUIHANDLE m_controlHandle; - AddonToKodiFuncTable_Addon* m_interface; - CAddonGUIControlBase* m_Window; - - private: - CAddonGUIControlBase() = delete; - CAddonGUIControlBase(const CAddonGUIControlBase&) = delete; - CAddonGUIControlBase &operator=(const CAddonGUIControlBase&) = delete; - }; - - class CListItem; - typedef std::shared_ptr ListItemPtr; - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_CListItem List Item - /// \ingroup cpp_kodi_gui - /// @brief \cpp_class{ kodi::gui::CListItem } - /// **Selectable window list item** - /// - /// The list item control is used for creating item lists in Kodi - /// - /// The with \ref ListItem.h "#include " given - /// class is used to create a item entry for a list on window and to support it's - /// control. - /// - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_CListItem_Defs Definitions, structures and enumerators - /// \ingroup cpp_kodi_gui_CListItem - /// @brief **Library definition values** - /// - - class ATTRIBUTE_HIDDEN CListItem : public CAddonGUIControlBase - { - public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief Class constructor with parameters - /// - /// @param[in] label Item label - /// @param[in] label2 Second Item label (if needed) - /// @param[in] iconImage Item icon image (if needed) - /// @param[in] path Path to where item is defined - /// - CListItem( - const std::string& label = "", - const std::string& label2 = "", - const std::string& iconImage = "", - const std::string& path = "") - : CAddonGUIControlBase(nullptr) - { - m_controlHandle = m_interface->kodi_gui->listItem->create(m_interface->kodiBase, label.c_str(), - label2.c_str(), iconImage.c_str(), - path.c_str()); - } - - /* - * Constructor used for parts given by list items from addon window - * - * Related to call of "ListItemPtr kodi::gui::CWindow::GetListItem(int listPos)" - * Not needed for addon development itself - */ - explicit CListItem(GUIHANDLE listItemHandle) - : CAddonGUIControlBase(nullptr) - { - m_controlHandle = listItemHandle; - } - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief Class destructor - /// - ~CListItem() override - { - m_interface->kodi_gui->listItem->destroy(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief Returns the listitem label. - /// - /// @return Label of item - /// - std::string GetLabel() - { - std::string label; - char* ret = m_interface->kodi_gui->listItem->get_label(m_interface->kodiBase, m_controlHandle); - if (ret != nullptr) - { - if (std::strlen(ret)) - label = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return label; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief Sets the listitem label. - /// - /// @param[in] label string or unicode - text string. - /// - void SetLabel(const std::string& label) - { - m_interface->kodi_gui->listItem->set_label(m_interface->kodiBase, m_controlHandle, label.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief Returns the second listitem label. - /// - /// @return Second label of item - /// - std::string GetLabel2() - { - std::string label; - char* ret = m_interface->kodi_gui->listItem->get_label2(m_interface->kodiBase, m_controlHandle); - if (ret != nullptr) - { - if (std::strlen(ret)) - label = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return label; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief Sets the listitem's label2. - /// - /// @param[in] label string or unicode - text string. - /// - void SetLabel2(const std::string& label) - { - m_interface->kodi_gui->listItem->set_label2(m_interface->kodiBase, m_controlHandle, label.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief Sets the listitem's art - /// - /// @param[in] type Type of Art to set - /// - Some default art values (any string possible): - /// | value (type) | Type | - /// |:-------------:|:--------------------------------------------------| - /// | thumb | string - image filename - /// | poster | string - image filename - /// | banner | string - image filename - /// | fanart | string - image filename - /// | clearart | string - image filename - /// | clearlogo | string - image filename - /// | landscape | string - image filename - /// | icon | string - image filename - /// @return The url to use for Art - /// - std::string GetArt(const std::string& type) - { - std::string strReturn; - char* ret = m_interface->kodi_gui->listItem->get_art(m_interface->kodiBase, m_controlHandle, type.c_str()); - if (ret != nullptr) - { - if (std::strlen(ret)) - strReturn = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return strReturn; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief Sets the listitem's art - /// - /// @param[in] type Type of Art to set - /// @param[in] url The url to use for Art - /// - Some default art values (any string possible): - /// | value (type) | Type | - /// |:-------------:|:--------------------------------------------------| - /// | thumb | string - image filename - /// | poster | string - image filename - /// | banner | string - image filename - /// | fanart | string - image filename - /// | clearart | string - image filename - /// | clearlogo | string - image filename - /// | landscape | string - image filename - /// | icon | string - image filename - /// - void SetArt(const std::string& type, const std::string& url) - { - m_interface->kodi_gui->listItem->set_art(m_interface->kodiBase, m_controlHandle, type.c_str(), url.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief Returns the path / filename of this listitem. - /// - /// @return Path string - /// - std::string GetPath() - { - std::string strReturn; - char* ret = m_interface->kodi_gui->listItem->get_path(m_interface->kodiBase, m_controlHandle); - if (ret != nullptr) - { - if (std::strlen(ret)) - strReturn = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return strReturn; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief Sets the listitem's path. - /// - /// @param[in] path string or unicode - path, activated when - /// item is clicked. - /// - /// @note You can use the above as keywords for arguments. - /// - void SetPath(const std::string& path) - { - m_interface->kodi_gui->listItem->set_path(m_interface->kodiBase, m_controlHandle, path.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief Sets a listitem property, similar to an infolabel. - /// - /// @param[in] key string - property name. - /// @param[in] value string or unicode - value of property. - /// - /// @note Key is NOT case sensitive. - /// You can use the above as keywords for arguments and skip certain\n - /// optional arguments.\n - /// Once you use a keyword, all following arguments require the - /// keyword. - /// - /// Some of these are treated internally by Kodi, such as the - /// 'StartOffset' property, which is the offset in seconds at which to - /// start playback of an item. Others may be used in the skin to add - /// extra information, such as 'WatchedCount' for tvshow items - /// - void SetProperty(const std::string& key, const std::string& value) - { - m_interface->kodi_gui->listItem->set_property(m_interface->kodiBase, m_controlHandle, key.c_str(), value.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief Returns a listitem property as a string, similar to an infolabel. - /// - /// @param[in] key string - property name. - /// @return string - List item property - /// - /// @note Key is NOT case sensitive.\n - /// You can use the above as keywords for arguments and skip certain - /// optional arguments.\n - /// Once you use a keyword, all following arguments require the - /// keyword. - /// - std::string GetProperty(const std::string& key) - { - std::string label; - char* ret = m_interface->kodi_gui->listItem->get_property(m_interface->kodiBase, m_controlHandle, key.c_str()); - if (ret != nullptr) - { - if (std::strlen(ret)) - label = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return label; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief To control selection of item in list (also multiple selection, - /// in list on serveral items possible). - /// - /// @param[in] selected if true becomes set as selected - /// - void Select(bool selected) - { - m_interface->kodi_gui->listItem->select(m_interface->kodiBase, m_controlHandle, selected); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CListItem - /// @brief Returns the listitem's selected status. - /// - /// @return true if selected, otherwise false - /// - bool IsSelected() - { - return m_interface->kodi_gui->listItem->is_selected(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - }; - -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/Window.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/Window.h deleted file mode 100644 index 5011374..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/Window.h +++ /dev/null @@ -1,909 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../AddonBase.h" -#include "ListItem.h" - -#ifdef BUILD_KODI_ADDON -#include "../ActionIDs.h" -#else -#include "input/actions/ActionIDs.h" -#endif - -namespace kodi -{ -namespace gui -{ - - class CListItem; - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_CWindow Window - /// \ingroup cpp_kodi_gui - /// @brief \cpp_class{ kodi::gui::CWindow } - /// **Main window control class** - /// - /// The with \ref Window.h "#include " - /// included file brings support to create a window or dialog on Kodi. - /// - /// -------------------------------------------------------------------------- - /// - /// On functions defined input variable controlId (GUI control identifier) - /// is the on window.xml defined value behind type added with id="..." and - /// used to identify for changes there and on callbacks. - /// - /// ~~~~~~~~~~~~~{.xml} - /// - /// Title Label - /// ... - /// - /// - /// progress control - /// ... - /// - /// ~~~~~~~~~~~~~ - /// - /// - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_CWindow_Defs Definitions, structures and enumerators - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Library definition values - /// - - class ATTRIBUTE_HIDDEN CWindow : public CAddonGUIControlBase - { - public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Class constructor with needed values for window / dialog. - /// - /// Creates a new Window class. - /// - /// @param[in] xmlFilename XML file for the skin - /// @param[in] defaultSkin default skin to use if needed not available - /// @param[in] asDialog Use window as dialog if set - /// @param[in] isMedia [opt] bool - if False, create a regular window. - /// if True, create a mediawindow. - /// (default=false) - /// @note only usable for windows not for dialogs. - /// - /// - CWindow(const std::string& xmlFilename, const std::string& defaultSkin, bool asDialog, bool isMedia = false) - : CAddonGUIControlBase(nullptr) - { - m_controlHandle = m_interface->kodi_gui->window->create(m_interface->kodiBase, xmlFilename.c_str(), - defaultSkin.c_str(), asDialog, isMedia); - if (!m_controlHandle) - kodi::Log(ADDON_LOG_FATAL, "kodi::gui::CWindow can't create window class from Kodi !!!"); - m_interface->kodi_gui->window->set_callbacks(m_interface->kodiBase, m_controlHandle, this, - CBOnInit, CBOnFocus, CBOnClick, CBOnAction, - CBGetContextButtons, CBOnContextButton); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup CWindow - /// @brief Class destructor - /// - /// - /// - ~CWindow() override - { - if (m_controlHandle) - m_interface->kodi_gui->window->destroy(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Show this window. - /// - /// Shows this window by activating it, calling close() after it wil activate the - /// current window again. - /// - /// @note If your Add-On ends this window will be closed to. To show it forever, - /// make a loop at the end of your Add-On or use doModal() instead. - /// - /// @warning If used must be the class be global present until Kodi becomes - /// closed. The creation can be done after before "Show" becomes called, but - /// not delete class after them. - /// - /// @return Return true if call and show is successed, - /// if false was something failed to get needed - /// skin parts. - /// - bool Show() - { - return m_interface->kodi_gui->window->show(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Closes this window. - /// - /// Closes this window by activating the old window. - /// @note The window is not deleted with this method. - /// - void Close() - { - m_interface->kodi_gui->window->close(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Display this window until close() is called. - /// - void DoModal() - { - m_interface->kodi_gui->window->do_modal(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Gives the control with the supplied focus. - /// - /// @param[in] iControlId On skin defined id of control - /// @return Return true if call and focus is successed, - /// if false was something failed to get needed - /// skin parts. - /// - /// - bool SetFocusId(int iControlId) - { - return m_interface->kodi_gui->window->set_focus_id(m_interface->kodiBase, m_controlHandle, iControlId); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Returns the id of the control which is focused. - /// - /// @return Focused control id - /// - /// - int GetFocusId() - { - return m_interface->kodi_gui->window->get_focus_id(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief To set the used label on given control id - /// - /// @param[in] controlId Control id where label need to set - /// @param[in] label Label to use - /// - /// - void SetControlLabel(int controlId, const std::string& label) - { - m_interface->kodi_gui->window->set_control_label(m_interface->kodiBase, m_controlHandle, controlId, label.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief To set the visibility on given control id - /// - /// @param[in] controlId Control id where visibility is changed - /// @param[in] visible Boolean value with `true` for visible, `false` for hidden - /// - /// - void SetControlVisible(int controlId, bool visible) - { - m_interface->kodi_gui->window->set_control_visible(m_interface->kodiBase, m_controlHandle, controlId, visible); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief To set the selection on given control id - /// - /// @param[in] controlId Control id where selection is changed - /// @param[in] selected Boolean value with `true` for selected, `false` for not - /// - /// - void SetControlSelected(int controlId, bool selected) - { - m_interface->kodi_gui->window->set_control_selected(m_interface->kodiBase, m_controlHandle, controlId, selected); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Sets a window property, similar to an infolabel. - /// - /// @param[in] key string - property name. - /// @param[in] value string or unicode - value of property. - /// - /// @note Key is NOT case sensitive. Setting value to an empty string is - /// equivalent to clearProperty(key).\n - /// You can use the above as keywords for arguments and skip certain - /// optional arguments.\n - /// Once you use a keyword, all following arguments require the keyword. - /// - void SetProperty(const std::string& key, const std::string& value) - { - m_interface->kodi_gui->window->set_property(m_interface->kodiBase, m_controlHandle, key.c_str(), value.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Returns a window property as a string, similar to an infolabel. - /// - /// @param[in] key string - property name. - /// @return The property as strin (if present) - /// - /// @note Key is NOT case sensitive. Setting value to an empty string is - /// equivalent to clearProperty(key).\n - /// You can use the above as keywords for arguments and skip certain - /// optional arguments.\n - /// Once you use a keyword, all following arguments require the keyword. - /// - /// - std::string GetProperty(const std::string& key) const - { - std::string label; - char* ret = m_interface->kodi_gui->window->get_property(m_interface->kodiBase, m_controlHandle, key.c_str()); - if (ret != nullptr) - { - if (std::strlen(ret)) - label = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return label; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Sets a window property with integer value - /// - /// @param[in] key string - property name. - /// @param[in] value integer value to set - /// - /// - void SetPropertyInt(const std::string& key, int value) - { - m_interface->kodi_gui->window->set_property_int(m_interface->kodiBase, m_controlHandle, key.c_str(), value); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Returns a window property with integer value - /// - /// @param[in] key string - property name. - /// @return integer value of property - /// - int GetPropertyInt(const std::string& key) const - { - return m_interface->kodi_gui->window->get_property_int(m_interface->kodiBase, m_controlHandle, key.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Sets a window property with boolean value - /// - /// @param[in] key string - property name. - /// @param[in] value boolean value to set - /// - /// - void SetPropertyBool(const std::string& key, bool value) - { - m_interface->kodi_gui->window->set_property_bool(m_interface->kodiBase, m_controlHandle, key.c_str(), value); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Returns a window property with boolean value - /// - /// @param[in] key string - property name. - /// @return boolean value of property - /// - bool GetPropertyBool(const std::string& key) const - { - return m_interface->kodi_gui->window->get_property_bool(m_interface->kodiBase, m_controlHandle, key.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Sets a window property with double value - /// - /// @param[in] key string - property name. - /// @param[in] value double value to set - /// - /// - void SetPropertyDouble(const std::string& key, double value) - { - m_interface->kodi_gui->window->set_property_double(m_interface->kodiBase, m_controlHandle, key.c_str(), value); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Returns a window property with double value - /// - /// @param[in] key string - property name. - /// @return double value of property - /// - /// - double GetPropertyDouble(const std::string& key) const - { - return m_interface->kodi_gui->window->get_property_double(m_interface->kodiBase, m_controlHandle, key.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Remove all present properties from window - /// - /// - /// - void ClearProperties() - { - m_interface->kodi_gui->window->clear_properties(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Clears the specific window property. - /// - /// @param[in] key string - property name. - /// - /// @note Key is NOT case sensitive. Equivalent to SetProperty(key, "") - /// You can use the above as keywords for arguments and skip certain - /// optional arguments. - /// Once you use a keyword, all following arguments require the - /// keyword. - /// - /// - ///----------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// .. - /// ClearProperty('Category') - /// .. - /// ~~~~~~~~~~~~~ - /// - void ClearProperty(const std::string& key) - { - m_interface->kodi_gui->window->clear_property(m_interface->kodiBase, m_controlHandle, key.c_str()); - } - //-------------------------------------------------------------------------- - - //@{ - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Function delete all entries in integrated list. - /// - /// - /// - void ClearList() - { - m_interface->kodi_gui->window->clear_item_list(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief To add a list item in the on window integrated list. - /// - /// @param[in] item List item to add - /// @param[in] itemPosition [opt] The position for item, default is on end - /// - /// - void AddListItem(ListItemPtr item, int itemPosition = -1) - { - m_interface->kodi_gui->window->add_list_item(m_interface->kodiBase, m_controlHandle, item->m_controlHandle, itemPosition); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief To add a list item based upon string in the on window integrated list. - /// - /// @param[in] item List item to add - /// @param[in] itemPosition [opt] The position for item, default is on end - /// - /// - void AddListItem(const std::string item, int itemPosition = -1) - { - m_interface->kodi_gui->window->add_list_item(m_interface->kodiBase, m_controlHandle, std::make_shared(item)->m_controlHandle, itemPosition); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Remove list item on position. - /// - /// @param[in] itemPosition List position to remove - /// - /// - void RemoveListItem(int itemPosition) - { - m_interface->kodi_gui->window->remove_list_item_from_position(m_interface->kodiBase, m_controlHandle, itemPosition); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Remove item with given control class from list. - /// - /// @param[in] item List item control class to remove - /// - /// - void RemoveListItem(ListItemPtr item) - { - m_interface->kodi_gui->window->remove_list_item(m_interface->kodiBase, m_controlHandle, item->m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief To get list item control class on wanted position. - /// - /// @param[in] listPos Position from where control is needed - /// @return The list item control class or null if not found - /// - /// @warning Function returns a new generated **CListItem** class! - /// - ListItemPtr GetListItem(int listPos) - { - GUIHANDLE handle = m_interface->kodi_gui->window->get_list_item(m_interface->kodiBase, m_controlHandle, listPos); - if (!handle) - return ListItemPtr(); - - return std::make_shared(handle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief To set position of selected part in list. - /// - /// @param[in] listPos Position to use - /// - /// - void SetCurrentListPosition(int listPos) - { - m_interface->kodi_gui->window->set_current_list_position(m_interface->kodiBase, m_controlHandle, listPos); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief To get current selected position in list - /// - /// @return Current list position - /// - /// - int GetCurrentListPosition() - { - return m_interface->kodi_gui->window->get_current_list_position(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief To get the amount of entries in the list. - /// - /// @return Size of in window integrated control class - /// - /// - int GetListSize() - { - return m_interface->kodi_gui->window->get_list_size(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Sets a container property, similar to an infolabel. - /// - /// @param[in] key string - property name. - /// @param[in] value string or unicode - value of property. - /// - /// @note Key is NOT case sensitive.\n - /// You can use the above as keywords for arguments and skip certain - /// optional arguments.\n - /// Once you use a keyword, all following arguments require the keyword. - /// - /// - void SetContainerProperty(const std::string& key, const std::string& value) - { - m_interface->kodi_gui->window->set_container_property(m_interface->kodiBase, m_controlHandle, key.c_str(), value.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Sets the content type of the container. - /// - /// @param[in] value string or unicode - content value. - /// - /// __Available content types__ - /// | Name | Media | - /// |:-----------:|:-----------------------------------------| - /// | actors | Videos - /// | addons | Addons, Music, Pictures, Programs, Videos - /// | albums | Music, Videos - /// | artists | Music, Videos - /// | countries | Music, Videos - /// | directors | Videos - /// | files | Music, Videos - /// | games | Games - /// | genres | Music, Videos - /// | images | Pictures - /// | mixed | Music, Videos - /// | movies | Videos - /// | Musicvideos | Music, Videos - /// | playlists | Music, Videos - /// | seasons | Videos - /// | sets | Videos - /// | songs | Music - /// | studios | Music, Videos - /// | tags | Music, Videos - /// | tvshows | Videos - /// | videos | Videos - /// | years | Music, Videos - /// - /// - void SetContainerContent(const std::string& value) - { - m_interface->kodi_gui->window->set_container_content(m_interface->kodiBase, m_controlHandle, value.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief Get the id of the currently visible container. - /// - /// @return currently visible container id - /// - /// - int GetCurrentContainerId() - { - return m_interface->kodi_gui->window->get_current_container_id(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - //@} - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow - /// @brief To inform Kodi that it need to render region new. - /// - /// - void MarkDirtyRegion() - { - return m_interface->kodi_gui->window->mark_dirty_region(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - // - /// @defgroup cpp_kodi_gui_CWindow_callbacks Callback functions from Kodi to add-on - /// \ingroup cpp_kodi_gui_CWindow - //@{ - /// @brief GUI window callback functions. - /// - /// Functions to handle control callbacks from Kodi - /// - /// ------------------------------------------------------------------------ - /// - /// @link cpp_kodi_gui_CWindow Go back to normal functions from CWindow@endlink - // - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow_callbacks - /// @brief OnInit method. - /// - /// @return Return true if initialize was done successful - /// - /// - virtual bool OnInit() { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow_callbacks - /// @brief OnFocus method. - /// - /// @param[in] controlId GUI control identifier - /// @return Return true if focus condition was handled there or false to handle them by Kodi itself - /// - /// - virtual bool OnFocus(int controlId) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow_callbacks - /// @brief OnClick method. - /// - /// @param[in] controlId GUI control identifier - /// @return Return true if click was handled there - /// or false to handle them by Kodi itself - /// - /// - virtual bool OnClick(int controlId) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow_callbacks - /// @brief OnAction method. - /// - /// @param[in] actionId The action id to perform, see - /// \ref kodi_key_action_ids to get list of - /// them - /// @return Return true if action was handled there - /// or false to handle them by Kodi itself - /// - /// - /// This method will receive all actions that the main program will send - /// to this window. - /// - /// @note - /// - By default, only the \c PREVIOUS_MENU and \c NAV_BACK actions are handled. - /// - Overwrite this method to let your code handle all actions. - /// - Don't forget to capture \c ACTION_PREVIOUS_MENU or \c ACTION_NAV_BACK, else the user can't close this window. - /// - /// - ///-------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// .. - /// /* Window used with parent / child way */ - /// bool cYOUR_CLASS::OnAction(int actionId) - /// { - /// switch (action) - /// { - /// case ACTION_PREVIOUS_MENU: - /// case ACTION_NAV_BACK: - /// printf("action recieved: previous"); - /// Close(); - /// return true; - /// case ACTION_SHOW_INFO: - /// printf("action recieved: show info"); - /// break; - /// case ACTION_STOP: - /// printf("action recieved: stop"); - /// break; - /// case ACTION_PAUSE: - /// printf("action recieved: pause"); - /// break; - /// default: - /// break; - /// } - /// return false; - /// } - /// .. - /// ~~~~~~~~~~~~~ - /// - virtual bool OnAction(int actionId, uint32_t buttoncode, wchar_t unicode) - { - switch (actionId) - { - case ACTION_PREVIOUS_MENU: - case ACTION_NAV_BACK: - Close(); - return true; - default: - break; - } - return false; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow_callbacks - /// @brief Get context menu buttons for list entry - /// - /// @param[in] itemNumber selected list item entry - /// @param[in] buttons list where context menus becomes added with his - /// identifier and name. - /// - virtual void GetContextButtons(int itemNumber, std::vector< std::pair > &buttons) - { - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow_callbacks - /// @brief Called after selection in context menu - /// - /// @param[in] itemNumber selected list item entry - /// @param[in] button the pressed button id - /// @return true if handled, otherwise false - /// - virtual bool OnContextButton(int itemNumber, unsigned int button) - { - return false; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_CWindow_callbacks - /// @brief **Set independent callbacks** - /// - /// If the class is used independent (with "new CWindow") and - /// not as parent (with "cCLASS_own : CWindow") from own must be the - /// callback from Kodi to add-on overdriven with own functions! - /// - /// @param[in] cbhdl The pointer to own handle data - /// structure / class - /// @param[in] CBOnInit Own defined window init function - /// @param[in] CBOnFocus Own defined focus function - /// @param[in] CBOnClick Own defined click function - /// @param[in] CBOnAction Own defined action function - /// @param[in] CBGetContextButtons [opt] To get context menu entries for - /// lists function - /// @param[in] CBOnContextButton [opt] Used context menu entry function - /// - /// - ///-------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// ... - /// - /// bool OnInit(GUIHANDLE cbhdl) - /// { - /// ... - /// return true; - /// } - /// - /// bool OnFocus(GUIHANDLE cbhdl, int controlId) - /// { - /// ... - /// return true; - /// } - /// - /// bool OnClick(GUIHANDLE cbhdl, int controlId) - /// { - /// ... - /// return true; - /// } - /// - /// bool OnAction(GUIHANDLE cbhdl, int actionId) - /// { - /// ... - /// return true; - /// } - /// - /// ... - /// /* Somewhere where you create the window */ - /// CWindow myWindow = new CWindow; - /// myWindow->SetIndependentCallbacks(myWindow, OnInit, OnFocus, OnClick, OnAction); - /// ... - /// ~~~~~~~~~~~~~ - /// - void SetIndependentCallbacks( - GUIHANDLE cbhdl, - bool (*CBOnInit) (GUIHANDLE cbhdl), - bool (*CBOnFocus) (GUIHANDLE cbhdl, int controlId), - bool (*CBOnClick) (GUIHANDLE cbhdl, int controlId), - bool (*CBOnAction) (GUIHANDLE cbhdl, int actionId, uint32_t buttoncode, wchar_t unicode), - void (*CBGetContextButtons) (GUIHANDLE cbhdl, int itemNumber, gui_context_menu_pair* buttons, unsigned int* size) = nullptr, - bool (*CBOnContextButton) (GUIHANDLE cbhdl, int itemNumber, unsigned int button) = nullptr) - { - if (!cbhdl || - !CBOnInit || !CBOnFocus || !CBOnClick || !CBOnAction) - { - kodi::Log(ADDON_LOG_FATAL, "kodi::gui::CWindow::%s called with nullptr !!!", __FUNCTION__); - return; - } - - m_interface->kodi_gui->window->set_callbacks(m_interface->kodiBase, m_controlHandle, cbhdl, - CBOnInit, CBOnFocus, CBOnClick, CBOnAction, - CBGetContextButtons, CBOnContextButton); - } - //-------------------------------------------------------------------------- - //@} - - private: - static bool CBOnInit(GUIHANDLE cbhdl) - { - return static_cast(cbhdl)->OnInit(); - } - - static bool CBOnFocus(GUIHANDLE cbhdl, int controlId) - { - return static_cast(cbhdl)->OnFocus(controlId); - } - - static bool CBOnClick(GUIHANDLE cbhdl, int controlId) - { - return static_cast(cbhdl)->OnClick(controlId); - } - - static bool CBOnAction(GUIHANDLE cbhdl, int actionId, uint32_t buttoncode, wchar_t unicode) - { - return static_cast(cbhdl)->OnAction(actionId, buttoncode, unicode); - } - - static void CBGetContextButtons(GUIHANDLE cbhdl, int itemNumber, gui_context_menu_pair* buttons, unsigned int* size) - { - std::vector< std::pair > buttonList; - static_cast(cbhdl)->GetContextButtons(itemNumber, buttonList); - if (!buttonList.empty()) - { - unsigned int presentSize = static_cast(buttonList.size()); - if (presentSize > *size) - kodi::Log(ADDON_LOG_WARNING, "GetContextButtons: More as allowed '%i' entries present!", *size); - else - *size = presentSize; - for (unsigned int i = 0; i < *size; ++i) - { - buttons[i].id = buttonList[i].first; - strncpy(buttons[i].name, buttonList[i].second.c_str(), ADDON_MAX_CONTEXT_ENTRY_NAME_LENGTH); - } - } - } - - static bool CBOnContextButton(GUIHANDLE cbhdl, int itemNumber, unsigned int button) - { - return static_cast(cbhdl)->OnContextButton(itemNumber, button); - } - }; - -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Button.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Button.h deleted file mode 100644 index 081ab06..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Button.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../Window.h" - -namespace kodi -{ -namespace gui -{ -namespace controls -{ - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_controls_CButton Control Button -/// \ingroup cpp_kodi_gui -/// @brief \cpp_class{ kodi::gui::controls::CButton } -/// **Standard push button control for window** -/// -/// The button control is used for creating push buttons in Kodi. You can -/// choose the position, size, and look of the button, as well as choosing -/// what action(s) should be performed when pushed. -/// -/// It has the header \ref Button.h "#include " -/// be included to enjoy it. -/// -/// Here you find the needed skin part for a \ref skin_Button_control "button control" -/// -/// @note The call of the control is only possible from the corresponding -/// window as its class and identification number is required. -/// -class ATTRIBUTE_HIDDEN CButton : public CAddonGUIControlBase -{ -public: - //========================================================================== - /// - /// @ingroup cpp_kodi_gui_control_CButton - /// @brief Construct a new control - /// - /// @param[in] window related window control class - /// @param[in] controlId Used skin xml control id - /// - CButton(CWindow* window, int controlId) : CAddonGUIControlBase(window) - { - m_controlHandle = m_interface->kodi_gui->window->get_control_button( - m_interface->kodiBase, m_Window->GetControlHandle(), controlId); - if (!m_controlHandle) - kodi::Log(ADDON_LOG_FATAL, "kodi::gui::CButton can't create control class from Kodi !!!"); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_gui_control_CButton - /// @brief Destructor - /// - ~CButton() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_gui_control_CButton - /// @brief Set the control on window to visible - /// - /// @param[in] visible If true visible, otherwise hidden - /// - void SetVisible(bool visible) - { - m_interface->kodi_gui->control_button->set_visible(m_interface->kodiBase, m_controlHandle, - visible); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_gui_control_CButton - /// @brief Set's the control's enabled/disabled state - /// - /// @param[in] enabled If true enabled, otherwise disabled - /// - void SetEnabled(bool enabled) - { - m_interface->kodi_gui->control_button->set_enabled(m_interface->kodiBase, m_controlHandle, - enabled); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_gui_control_CButton - /// @brief To set the text string on button - /// - /// @param[in] label Text to show - /// - void SetLabel(const std::string& label) - { - m_interface->kodi_gui->control_button->set_label(m_interface->kodiBase, m_controlHandle, - label.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_gui_control_CButton - /// @brief Get the used text from button - /// - /// @return Text shown - /// - std::string GetLabel() const - { - std::string label; - char* ret = - m_interface->kodi_gui->control_button->get_label(m_interface->kodiBase, m_controlHandle); - if (ret != nullptr) - { - if (std::strlen(ret)) - label = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return label; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_gui_control_CButton - /// @brief If two labels are used for button becomes it set with them - /// - /// @param[in] label Text for second label - /// - void SetLabel2(const std::string& label) - { - m_interface->kodi_gui->control_button->set_label2(m_interface->kodiBase, m_controlHandle, - label.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// @ingroup cpp_kodi_gui_control_CButton - /// @brief Get the second label if present - /// - /// @return Second label - /// - std::string GetLabel2() const - { - std::string label; - char* ret = - m_interface->kodi_gui->control_button->get_label2(m_interface->kodiBase, m_controlHandle); - if (ret != nullptr) - { - if (std::strlen(ret)) - label = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return label; - } - //-------------------------------------------------------------------------- -}; - -} /* namespace controls */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/CMakeLists.txt deleted file mode 100644 index c7cc1dd..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set(HEADERS Button.h - Edit.h - FadeLabel.h - Image.h - Label.h - Progress.h - RadioButton.h - Rendering.h - SettingsSlider.h - Slider.h - Spin.h - TextBox.h) - -if(NOT ENABLE_STATIC_LIBS) - core_add_library(addons_kodi-addon-dev-kit_include_kodi_gui_controls) -endif() diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Edit.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Edit.h deleted file mode 100644 index 99c01de..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Edit.h +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../Window.h" - -namespace kodi -{ -namespace gui -{ -namespace controls -{ - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_controls_CEdit Control Edit - /// \ingroup cpp_kodi_gui - /// @brief \cpp_class{ kodi::gui::controls::CEdit } - /// **Editable window text control used as an input control for the osd keyboard - /// and other input fields** - /// - /// The edit control allows a user to input text in Kodi. You can choose the - /// font, size, colour, location and header of the text to be displayed. - /// - /// It has the header \ref Edit.h "#include " - /// be included to enjoy it. - /// - /// Here you find the needed skin part for a \ref skin_Edit_control - /// "edit control". - /// - /// @note The call of the control is only possible from the corresponding - /// window as its class and identification number is required. - /// - - //============================================================================ - // see gui/definition.h for use of group "cpp_kodi_gui_controls_CEdit_Defs" - /// - /// \defgroup cpp_kodi_gui_controls_CEdit_Defs Definitions, structures and enumerators - /// \ingroup cpp_kodi_gui_controls_CEdit - /// @brief **Library definition values** - /// - -} /* namespace controls */ -} /* namespace gui */ -} /* namespace kodi */ - -//============================================================================ -/// -/// \ingroup cpp_kodi_gui_controls_CEdit_Defs -/// @{ -/// @anchor AddonGUIInputType -/// @brief Text input types used on kodi::gui::controls::CEdit -enum AddonGUIInputType -{ - /// Text inside edit control only readable - ADDON_INPUT_TYPE_READONLY = -1, - /// Normal text entries - ADDON_INPUT_TYPE_TEXT = 0, - /// To use on edit control only numeric numbers - ADDON_INPUT_TYPE_NUMBER, - /// To insert seconds - ADDON_INPUT_TYPE_SECONDS, - /// To insert time - ADDON_INPUT_TYPE_TIME, - /// To insert a date - ADDON_INPUT_TYPE_DATE, - /// Used for write in IP addresses - ADDON_INPUT_TYPE_IPADDRESS, - /// Text field used as password entry field with not visible text - ADDON_INPUT_TYPE_PASSWORD, - /// Text field used as password entry field with not visible text but - /// returned as MD5 value - ADDON_INPUT_TYPE_PASSWORD_MD5, - /// Use text field for search purpose - ADDON_INPUT_TYPE_SEARCH, - /// Text field as filter - ADDON_INPUT_TYPE_FILTER, - /// - ADDON_INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW -}; -/// @} -//---------------------------------------------------------------------------- - -namespace kodi -{ -namespace gui -{ -namespace controls -{ - -class ATTRIBUTE_HIDDEN CEdit : public CAddonGUIControlBase -{ -public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CEdit - /// @brief Construct a new control - /// - /// @param[in] window related window control class - /// @param[in] controlId Used skin xml control id - /// - CEdit(CWindow* window, int controlId) : CAddonGUIControlBase(window) - { - m_controlHandle = m_interface->kodi_gui->window->get_control_edit( - m_interface->kodiBase, m_Window->GetControlHandle(), controlId); - if (!m_controlHandle) - kodi::Log(ADDON_LOG_FATAL, - "kodi::gui::control::CEdit can't create control class from Kodi !!!"); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CEdit - /// @brief Destructor - /// - ~CEdit() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CEdit - /// @brief Set the control on window to visible - /// - /// @param[in] visible If true visible, otherwise hidden - /// - void SetVisible(bool visible) - { - m_interface->kodi_gui->control_edit->set_visible(m_interface->kodiBase, m_controlHandle, - visible); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CEdit - /// @brief Set's the control's enabled/disabled state - /// - /// @param[in] enabled If true enabled, otherwise disabled - /// - void SetEnabled(bool enabled) - { - m_interface->kodi_gui->control_edit->set_enabled(m_interface->kodiBase, m_controlHandle, - enabled); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CEdit - /// @brief To set the text string on edit control - /// - /// @param[in] label Text to show - /// - void SetLabel(const std::string& label) - { - m_interface->kodi_gui->control_edit->set_label(m_interface->kodiBase, m_controlHandle, - label.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CEdit - /// @brief Returns the text heading for this edit control. - /// - /// @return Heading text - /// - std::string GetLabel() const - { - std::string label; - char* ret = - m_interface->kodi_gui->control_edit->get_label(m_interface->kodiBase, m_controlHandle); - if (ret != nullptr) - { - if (std::strlen(ret)) - label = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return label; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CEdit - /// @brief Set's text heading for this edit control. - /// - /// @param[in] text string or unicode - text string. - /// - void SetText(const std::string& text) - { - m_interface->kodi_gui->control_edit->set_text(m_interface->kodiBase, m_controlHandle, - text.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CEdit - /// @brief Returns the text value for this edit control. - /// - /// @return Text value of control - /// - std::string GetText() const - { - std::string text; - char* ret = - m_interface->kodi_gui->control_edit->get_text(m_interface->kodiBase, m_controlHandle); - if (ret != nullptr) - { - if (std::strlen(ret)) - text = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return text; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CEdit - /// @brief Set the cursor position on text. - /// - /// @param[in] iPosition The position to set - /// - void SetCursorPosition(unsigned int iPosition) - { - m_interface->kodi_gui->control_edit->set_cursor_position(m_interface->kodiBase, m_controlHandle, - iPosition); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CEdit - /// @brief To get current cursor position on text field - /// - /// @return The current cursor position - /// - unsigned int GetCursorPosition() - { - return m_interface->kodi_gui->control_edit->get_cursor_position(m_interface->kodiBase, - m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CEdit - /// @brief To set field input type which are defined on \ref AddonGUIInputType - /// - /// @param[in] type The \ref AddonGUIInputType "Add-on input type" - /// to use - /// @param[in] heading The heading text for related keyboard - /// dialog - /// - void SetInputType(AddonGUIInputType type, const std::string& heading) - { - m_interface->kodi_gui->control_edit->set_input_type(m_interface->kodiBase, m_controlHandle, - static_cast(type), heading.c_str()); - } - //-------------------------------------------------------------------------- -}; - -} /* namespace controls */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/FadeLabel.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/FadeLabel.h deleted file mode 100644 index 02c843f..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/FadeLabel.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../Window.h" - -namespace kodi -{ -namespace gui -{ -namespace controls -{ - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_controls_CFadeLabel Control Fade Label -/// \ingroup cpp_kodi_gui -/// @brief \cpp_class{ kodi::gui::controls::CFadeLabel } -/// **Window control used to show multiple pieces of text in the same position, -/// by fading from one to the other** -/// -/// The fade label control is used for displaying multiple pieces of text in -/// the same space in Kodi. You can choose the font, size, colour, location -/// and contents of the text to be displayed. The first piece of information -/// to display fades in over 50 frames, then scrolls off to the left. Once it -/// is finished scrolling off screen, the second piece of information fades -/// in and the process repeats. A fade label control is not supported in a -/// list container. -/// -/// It has the header \ref FadeLabel.h "#include " -/// be included to enjoy it. -/// -/// Here you find the needed skin part for a \ref Fade_Label_Control "fade label control" -/// -/// @note The call of the control is only possible from the corresponding -/// window as its class and identification number is required. -/// -class ATTRIBUTE_HIDDEN CFadeLabel : public CAddonGUIControlBase -{ -public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CFadeLabel - /// @brief Construct a new control. - /// - /// @param[in] window related window control class - /// @param[in] controlId Used skin xml control id - /// - CFadeLabel(CWindow* window, int controlId) : CAddonGUIControlBase(window) - { - m_controlHandle = m_interface->kodi_gui->window->get_control_fade_label( - m_interface->kodiBase, m_Window->GetControlHandle(), controlId); - if (!m_controlHandle) - kodi::Log(ADDON_LOG_FATAL, - "kodi::gui::controls::CFadeLabel can't create control class from Kodi !!!"); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CFadeLabel - /// @brief Destructor. - /// - ~CFadeLabel() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CFadeLabel - /// @brief Set the control on window to visible. - /// - /// @param[in] visible If true visible, otherwise hidden - /// - void SetVisible(bool visible) - { - m_interface->kodi_gui->control_fade_label->set_visible(m_interface->kodiBase, m_controlHandle, - visible); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CFadeLabel - /// @brief To add additional text string on fade label. - /// - /// @param[in] label Text to show - /// - void AddLabel(const std::string& label) - { - m_interface->kodi_gui->control_fade_label->add_label(m_interface->kodiBase, m_controlHandle, - label.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CFadeLabel - /// @brief Get the used text from button - /// - /// @return Text shown - /// - std::string GetLabel() const - { - std::string label; - char* ret = m_interface->kodi_gui->control_fade_label->get_label(m_interface->kodiBase, - m_controlHandle); - if (ret != nullptr) - { - if (std::strlen(ret)) - label = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return label; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CFadeLabel - /// @brief To enable or disable scrolling on fade label - /// - /// @param[in] scroll To enable scrolling set to true, otherwise is - /// disabled - /// - void SetScrolling(bool scroll) - { - m_interface->kodi_gui->control_fade_label->set_scrolling(m_interface->kodiBase, m_controlHandle, - scroll); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CFadeLabel - /// @brief To reset al inserted labels. - /// - void Reset() - { - m_interface->kodi_gui->control_fade_label->reset(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- -}; - -} /* namespace controls */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Image.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Image.h deleted file mode 100644 index b4d092f..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Image.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../Window.h" - -namespace kodi -{ -namespace gui -{ -namespace controls -{ - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_controls_CImage Control Image -/// \ingroup cpp_kodi_gui -/// @brief \cpp_class{ kodi::gui::controls::CImage } -/// **Window control used to show an image.** -/// -/// The image control is used for displaying images in Kodi. You can choose -/// the position, size, transparency and contents of the image to be displayed. -/// -/// It has the header \ref Image.h "#include " -/// be included to enjoy it. -/// -/// Here you find the needed skin part for a \ref Image_Control "image control" -/// -/// @note The call of the control is only possible from the corresponding -/// window as its class and identification number is required. -/// -class ATTRIBUTE_HIDDEN CImage : public CAddonGUIControlBase -{ -public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CImage - /// @brief Construct a new control - /// - /// @param[in] window related window control class - /// @param[in] controlId Used skin xml control id - /// - CImage(CWindow* window, int controlId) : CAddonGUIControlBase(window) - { - m_controlHandle = m_interface->kodi_gui->window->get_control_image( - m_interface->kodiBase, m_Window->GetControlHandle(), controlId); - if (!m_controlHandle) - kodi::Log(ADDON_LOG_FATAL, - "kodi::gui::controls::CImage can't create control class from Kodi !!!"); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CImage - /// @brief Destructor - /// - ~CImage() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CImage - /// @brief Set the control on window to visible - /// - /// @param[in] visible If true visible, otherwise hidden - /// - void SetVisible(bool visible) - { - m_interface->kodi_gui->control_image->set_visible(m_interface->kodiBase, m_controlHandle, - visible); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CImage - /// @brief To set the filename used on image control. - /// - /// @param[in] filename Image file to use - /// @param[in] useCache To define storage of image, default is - /// in cache, if false becomes it loaded - /// always on changes again - /// - void SetFileName(const std::string& filename, bool useCache = true) - { - m_interface->kodi_gui->control_image->set_filename(m_interface->kodiBase, m_controlHandle, - filename.c_str(), useCache); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CImage - /// @brief To set set the diffuse color on image. - /// - /// @param[in] colorDiffuse Color to use for diffuse - /// - void SetColorDiffuse(uint32_t colorDiffuse) - { - m_interface->kodi_gui->control_image->set_color_diffuse(m_interface->kodiBase, m_controlHandle, - colorDiffuse); - } - //-------------------------------------------------------------------------- -}; - -} /* namespace controls */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Label.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Label.h deleted file mode 100644 index 82604bd..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Label.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../Window.h" - -namespace kodi -{ -namespace gui -{ -namespace controls -{ - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_controls_CLabel Control Label -/// \ingroup cpp_kodi_gui -/// @brief \cpp_class{ kodi::gui::controls::CLabel } -/// **Window control used to show some lines of text.** -/// -/// The label control is used for displaying text in Kodi. You can choose -/// the font, size, colour, location and contents of the text to be displayed. -/// -/// It has the header \ref Label.h "#include " -/// be included to enjoy it. -/// -/// Here you find the needed skin part for a \ref Label_Control "label control" -/// -/// @note The call of the control is only possible from the corresponding -/// window as its class and identification number is required. -/// -class ATTRIBUTE_HIDDEN CLabel : public CAddonGUIControlBase -{ -public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CLabel - /// @brief Construct a new control - /// - /// @param[in] window related window control class - /// @param[in] controlId Used skin xml control id - /// - CLabel(CWindow* window, int controlId) : CAddonGUIControlBase(window) - { - m_controlHandle = m_interface->kodi_gui->window->get_control_label( - m_interface->kodiBase, m_Window->GetControlHandle(), controlId); - if (!m_controlHandle) - kodi::Log(ADDON_LOG_FATAL, - "kodi::gui::controls::CLabel can't create control class from Kodi !!!"); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CLabel - /// @brief Destructor - /// - ~CLabel() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CLabel - /// @brief Set the control on window to visible - /// - /// @param[in] visible If true visible, otherwise hidden - /// - void SetVisible(bool visible) - { - m_interface->kodi_gui->control_label->set_visible(m_interface->kodiBase, m_controlHandle, - visible); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CLabel - /// @brief To set the text string on label - /// - /// @param[in] text Text to show - /// - void SetLabel(const std::string& text) - { - m_interface->kodi_gui->control_label->set_label(m_interface->kodiBase, m_controlHandle, - text.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CLabel - /// @brief Get the used text from control - /// - /// @return Used text on label control - /// - std::string GetLabel() const - { - std::string label; - char* ret = - m_interface->kodi_gui->control_label->get_label(m_interface->kodiBase, m_controlHandle); - if (ret != nullptr) - { - if (std::strlen(ret)) - label = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return label; - } - //-------------------------------------------------------------------------- -}; - -} /* namespace controls */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Progress.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Progress.h deleted file mode 100644 index 8cb582b..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Progress.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../Window.h" - -namespace kodi -{ -namespace gui -{ -namespace controls -{ - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_controls_CProgress Control Progress -/// \ingroup cpp_kodi_gui -/// @brief \cpp_class{ kodi::gui::controls::CProgress } -/// **Window control to show the progress of a particular operation** -/// -/// The progress control is used to show the progress of an item that may take -/// a long time, or to show how far through a movie you are. You can choose -/// the position, size, and look of the progress control. -/// -/// It has the header \ref Progress.h "#include " -/// be included to enjoy it. -/// -/// Here you find the needed skin part for a \ref Progress_Control "progress control" -/// -/// @note The call of the control is only possible from the corresponding -/// window as its class and identification number is required. -/// -class ATTRIBUTE_HIDDEN CProgress : public CAddonGUIControlBase -{ -public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CProgress - /// @brief Construct a new control - /// - /// @param[in] window related window control class - /// @param[in] controlId Used skin xml control id - /// - CProgress(CWindow* window, int controlId) : CAddonGUIControlBase(window) - { - m_controlHandle = m_interface->kodi_gui->window->get_control_progress( - m_interface->kodiBase, m_Window->GetControlHandle(), controlId); - if (!m_controlHandle) - kodi::Log(ADDON_LOG_FATAL, - "kodi::gui::controls::CProgress can't create control class from Kodi !!!"); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CProgress - /// @brief Destructor - /// - ~CProgress() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CProgress - /// @brief Set the control on window to visible - /// - /// @param[in] visible If true visible, otherwise hidden - /// - void SetVisible(bool visible) - { - m_interface->kodi_gui->control_progress->set_visible(m_interface->kodiBase, m_controlHandle, - visible); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CProgress - /// @brief To set Percent position of control - /// - /// @param[in] percent The percent position to use - /// - void SetPercentage(float percent) - { - m_interface->kodi_gui->control_progress->set_percentage(m_interface->kodiBase, m_controlHandle, - percent); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CProgress - /// @brief Get the active percent position of progress bar - /// - /// @return Progress position as percent - /// - float GetPercentage() const - { - return m_interface->kodi_gui->control_progress->get_percentage(m_interface->kodiBase, - m_controlHandle); - } - //-------------------------------------------------------------------------- -}; - -} /* namespace controls */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/RadioButton.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/RadioButton.h deleted file mode 100644 index 305195d..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/RadioButton.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../Window.h" - -namespace kodi -{ -namespace gui -{ -namespace controls -{ - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_controls_CRadioButton Control Radio Button -/// \ingroup cpp_kodi_gui -/// @brief \cpp_class{ kodi::gui::controls::CRadioButton } -/// **Window control for a radio button (as used for on/off settings)** -/// -/// The radio button control is used for creating push button on/off settings -/// in Kodi. You can choose the position, size, and look of the button. When -/// the user clicks on the radio button, the state will change, toggling the -/// extra textures (textureradioon and textureradiooff). Used for settings -/// controls. -/// -/// It has the header \ref RadioButton.h "#include " -/// be included to enjoy it. -/// -/// Here you find the needed skin part for a \ref Radio_button_control "radio button control" -/// -/// @note The call of the control is only possible from the corresponding -/// window as its class and identification number is required. -/// -class ATTRIBUTE_HIDDEN CRadioButton : public CAddonGUIControlBase -{ -public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRadioButton - /// @brief Construct a new control - /// - /// @param[in] window related window control class - /// @param[in] controlId Used skin xml control id - /// - CRadioButton(CWindow* window, int controlId) : CAddonGUIControlBase(window) - { - m_controlHandle = m_interface->kodi_gui->window->get_control_radio_button( - m_interface->kodiBase, m_Window->GetControlHandle(), controlId); - if (!m_controlHandle) - kodi::Log(ADDON_LOG_FATAL, - "kodi::gui::controls::CRadioButton can't create control class from Kodi !!!"); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRadioButton - /// @brief Destructor - /// - ~CRadioButton() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRadioButton - /// @brief Set the control on window to visible - /// - /// @param[in] visible If true visible, otherwise hidden - /// - void SetVisible(bool visible) - { - m_interface->kodi_gui->control_radio_button->set_visible(m_interface->kodiBase, m_controlHandle, - visible); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRadioButton - /// @brief Set's the control's enabled/disabled state - /// - /// @param[in] enabled If true enabled, otherwise disabled - /// - void SetEnabled(bool enabled) - { - m_interface->kodi_gui->control_radio_button->set_enabled(m_interface->kodiBase, m_controlHandle, - enabled); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRadioButton - /// @brief To set the text string on radio button - /// - /// @param[in] label Text to show - /// - void SetLabel(const std::string& label) - { - m_interface->kodi_gui->control_radio_button->set_label(m_interface->kodiBase, m_controlHandle, - label.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRadioButton - /// @brief Get the used text from control - /// - /// @return Text shown - /// - std::string GetLabel() const - { - std::string label; - char* ret = m_interface->kodi_gui->control_radio_button->get_label(m_interface->kodiBase, - m_controlHandle); - if (ret != nullptr) - { - if (std::strlen(ret)) - label = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return label; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRadioButton - /// @brief To set radio button condition to on or off - /// - /// @param[in] selected true set radio button to selection on, otherwise - /// off - /// - void SetSelected(bool selected) - { - m_interface->kodi_gui->control_radio_button->set_selected(m_interface->kodiBase, - m_controlHandle, selected); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRadioButton - /// @brief Get the current selected condition of radio button - /// - /// @return Selected condition - /// - bool IsSelected() const - { - return m_interface->kodi_gui->control_radio_button->is_selected(m_interface->kodiBase, - m_controlHandle); - } - //-------------------------------------------------------------------------- -}; - -} /* namespace controls */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Rendering.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Rendering.h deleted file mode 100644 index 7cc9b24..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Rendering.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../Window.h" -#include "../renderHelper.h" - -namespace kodi -{ -namespace gui -{ -namespace controls -{ - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_controls_CRendering Control Rendering -/// \ingroup cpp_kodi_gui -/// @brief \cpp_class{ kodi::gui::controls::CRendering } -/// **Window control for rendering own parts** -/// -/// This rendering control is used when own parts are needed. You have the -/// control over them to render direct OpenGL or DirectX content to the -/// screen set by the size of them. -/// -/// Alternative can be the virtual functions from t his been ignored if the -/// callbacks are defined by the \ref CRendering_SetIndependentCallbacks function and -/// class is used as single and not as a parent class. -/// -/// It has the header \ref Rendering.h "#include " -/// be included to enjoy it. -/// -/// Here you find the needed skin part for a \ref Addon_Rendering_control "rendering control" -/// -/// @note The call of the control is only possible from the corresponding -/// window as its class and identification number is required. -/// - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_controls_CRendering_Defs Definitions, structures and enumerators -/// \ingroup cpp_kodi_gui_controls_CRendering -/// @brief **Library definition values** -/// - -class ATTRIBUTE_HIDDEN CRendering : public CAddonGUIControlBase -{ -public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRendering - /// @brief Construct a new control - /// - /// @param[in] window related window control class - /// @param[in] controlId Used skin xml control id - /// - CRendering(CWindow* window, int controlId) : CAddonGUIControlBase(window) - { - m_controlHandle = m_interface->kodi_gui->window->get_control_render_addon( - m_interface->kodiBase, m_Window->GetControlHandle(), controlId); - if (m_controlHandle) - m_interface->kodi_gui->control_rendering->set_callbacks(m_interface->kodiBase, - m_controlHandle, this, OnCreateCB, - OnRenderCB, OnStopCB, OnDirtyCB); - else - kodi::Log(ADDON_LOG_FATAL, "kodi::gui::controls::%s can't create control class from Kodi !!!", - __FUNCTION__); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRendering - /// @brief Destructor - /// - ~CRendering() override - { - m_interface->kodi_gui->control_rendering->destroy(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRendering - /// @brief To create rendering control on Add-on - /// - /// Function creates the needed rendering control for Kodi which becomes - /// handled and processed from Add-on - /// - /// @note This is callback function from Kodi to Add-on and not to use - /// for calls from add-on to this function. - /// - /// @param[in] x Horizontal position - /// @param[in] y Vertical position - /// @param[in] w Width of control - /// @param[in] h Height of control - /// @param[in] device The device to use. For OpenGL is empty - /// on Direct X is the needed device send. - /// @return Add-on needs to return true if successed, - /// otherwise false. - /// - virtual bool Create(int x, int y, int w, int h, void* device) { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRendering - /// @brief Render process call from Kodi - /// - /// @note This is callback function from Kodi to Add-on and not to use - /// for calls from add-on to this function. - /// - virtual void Render() {} - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRendering - /// @brief Call from Kodi to stop rendering process - /// - /// @note This is callback function from Kodi to Add-on and not to use - /// for calls from add-on to this function. - /// - virtual void Stop() {} - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRendering - /// @brief Call from Kodi where add-on becomes asked about dirty rendering - /// region. - /// - /// @note This is callback function from Kodi to Add-on and not to use - /// for calls from add-on to this function. - /// - virtual bool Dirty() { return false; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CRendering - /// \anchor CRendering_SetIndependentCallbacks - /// @brief If the class is used independent (with "new CRendering") - /// and not as parent (with "cCLASS_own : CRendering") from own must - /// be the callback from Kodi to add-on overdriven with own functions! - /// - void SetIndependentCallbacks( - GUIHANDLE cbhdl, - bool (*CBCreate)(GUIHANDLE cbhdl, int x, int y, int w, int h, void* device), - void (*CBRender)(GUIHANDLE cbhdl), - void (*CBStop)(GUIHANDLE cbhdl), - bool (*CBDirty)(GUIHANDLE cbhdl)) - { - if (!cbhdl || !CBCreate || !CBRender || !CBStop || !CBDirty) - { - kodi::Log(ADDON_LOG_ERROR, "kodi::gui::controls::%s called with nullptr !!!", __FUNCTION__); - return; - } - - m_interface->kodi_gui->control_rendering->set_callbacks( - m_interface->kodiBase, m_controlHandle, cbhdl, CBCreate, CBRender, CBStop, CBDirty); - } - //-------------------------------------------------------------------------- - -private: - /* - * Defined callback functions from Kodi to add-on, for use in parent / child system - * (is private)! - */ - static bool OnCreateCB(void* cbhdl, int x, int y, int w, int h, void* device) - { - static_cast(cbhdl)->m_renderHelper = kodi::gui::GetRenderHelper(); - return static_cast(cbhdl)->Create(x, y, w, h, device); - } - - static void OnRenderCB(void* cbhdl) - { - if (!static_cast(cbhdl)->m_renderHelper) - return; - static_cast(cbhdl)->m_renderHelper->Begin(); - static_cast(cbhdl)->Render(); - static_cast(cbhdl)->m_renderHelper->End(); - } - - static void OnStopCB(void* cbhdl) - { - static_cast(cbhdl)->Stop(); - static_cast(cbhdl)->m_renderHelper = nullptr; - } - - static bool OnDirtyCB(void* cbhdl) { return static_cast(cbhdl)->Dirty(); } - - std::shared_ptr m_renderHelper; -}; - -} /* namespace controls */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/SettingsSlider.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/SettingsSlider.h deleted file mode 100644 index 76a02aa..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/SettingsSlider.h +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../Window.h" - -namespace kodi -{ -namespace gui -{ -namespace controls -{ - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_controls_CSettingsSlider Control Settings Slider -/// \ingroup cpp_kodi_gui -/// @brief \cpp_class{ kodi::gui::controls::CSettingsSlider } -/// **Window control for moveable slider with text name** -/// -/// The settings slider control is used in the settings screens for when an -/// option is best specified on a sliding scale. You can choose the position, -/// size, and look of the slider control. It is basically a cross between the -/// button control and a slider control. It has a label and focus and non -/// focus textures, as well as a slider control on the right. -/// -/// It has the header \ref SettingsSlider.h "#include " -/// be included to enjoy it. -/// -/// Here you find the needed skin part for a \ref Settings_Slider_Control "settings slider control" -/// -/// @note The call of the control is only possible from the corresponding -/// window as its class and identification number is required. -/// -class ATTRIBUTE_HIDDEN CSettingsSlider : public CAddonGUIControlBase -{ -public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief Construct a new control - /// - /// @param[in] window related window control class - /// @param[in] controlId Used skin xml control id - /// - CSettingsSlider(CWindow* window, int controlId) : CAddonGUIControlBase(window) - { - m_controlHandle = m_interface->kodi_gui->window->get_control_settings_slider( - m_interface->kodiBase, m_Window->GetControlHandle(), controlId); - if (!m_controlHandle) - kodi::Log(ADDON_LOG_FATAL, - "kodi::gui::controls::CSettingsSlider can't create control class from Kodi !!!"); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief Destructor - /// - ~CSettingsSlider() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief Set the control on window to visible - /// - /// @param[in] visible If true visible, otherwise hidden - /// - void SetVisible(bool visible) - { - m_interface->kodi_gui->control_settings_slider->set_visible(m_interface->kodiBase, - m_controlHandle, visible); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief Set's the control's enabled/disabled state - /// - /// @param[in] enabled If true enabled, otherwise disabled - /// - void SetEnabled(bool enabled) - { - m_interface->kodi_gui->control_settings_slider->set_enabled(m_interface->kodiBase, - m_controlHandle, enabled); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief To set the text string on settings slider - /// - /// @param[in] text Text to show - /// - void SetText(const std::string& text) - { - m_interface->kodi_gui->control_settings_slider->set_text(m_interface->kodiBase, m_controlHandle, - text.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief To reset slider on defaults - /// - void Reset() - { - m_interface->kodi_gui->control_settings_slider->reset(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief To set the the range as integer of slider, e.g. -10 is the slider - /// start and e.g. +10 is the from here defined position where it reach the - /// end. - /// - /// Ad default is the range from 0 to 100. - /// - /// The integer interval is as default 1 and can be changed with - /// @ref SetIntInterval. - /// - /// @param[in] start Integer start value - /// @param[in] end Integer end value - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only - /// one each can be used. - /// - void SetIntRange(int start, int end) - { - m_interface->kodi_gui->control_settings_slider->set_int_range(m_interface->kodiBase, - m_controlHandle, start, end); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief Set the slider position with the given integer value. The Range - /// must be defined with a call from \ref SetIntRange before. - /// - /// @param[in] value Position in range to set with integer - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values ​​can be not together and can, therefore, only - /// one each can be used. - /// - void SetIntValue(int value) - { - m_interface->kodi_gui->control_settings_slider->set_int_value(m_interface->kodiBase, - m_controlHandle, value); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief To get the current position as integer value. - /// - /// @return The position as integer - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values ​​can be not together and can, therefore, only - /// one each can be used. - /// - int GetIntValue() const - { - return m_interface->kodi_gui->control_settings_slider->get_int_value(m_interface->kodiBase, - m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief To set the interval steps of slider, as default is it 1. If it - /// becomes changed with this function will a step of the user with the - /// value fixed here be executed. - /// - /// @param[in] interval Intervall step to set. - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values ​​can be not together and can, therefore, only - /// one each can be used. - /// - void SetIntInterval(int interval) - { - m_interface->kodi_gui->control_settings_slider->set_int_interval(m_interface->kodiBase, - m_controlHandle, interval); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief Sets the percent of the slider. - /// - /// @param[in] percent float - Percent value of slide - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values ​​can be not together and can, therefore, only - /// one each can be used. - /// - void SetPercentage(float percent) - { - m_interface->kodi_gui->control_settings_slider->set_percentage(m_interface->kodiBase, - m_controlHandle, percent); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief Returns a float of the percent of the slider. - /// - /// @return float - Percent of slider - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values ​​can be not together and can, therefore, only - /// one each can be used. - /// - float GetPercentage() const - { - return m_interface->kodi_gui->control_settings_slider->get_percentage(m_interface->kodiBase, - m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief To set the the range as float of slider, e.g. -25.0 is the slider - /// start and e.g. +25.0 is the from here defined position where it reach - /// the end. - /// - /// As default is the range 0.0 to 1.0. - /// - /// The float interval is as default 0.1 and can be changed with - /// @ref SetFloatInterval. - /// - /// @param[in] start Integer start value - /// @param[in] end Integer end value - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values ​​ can be not together and can, therefore, only - /// one each can be used. - /// - void SetFloatRange(float start, float end) - { - m_interface->kodi_gui->control_settings_slider->set_float_range(m_interface->kodiBase, - m_controlHandle, start, end); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief Set the slider position with the given float value. The Range - /// can be defined with a call from \ref SetIntRange before, as default it - /// is 0.0 to 1.0. - /// - /// @param[in] value Position in range to set with float - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values ​​can be not together and can, therefore, only - /// one each can be used. - /// - void SetFloatValue(float value) - { - m_interface->kodi_gui->control_settings_slider->set_float_value(m_interface->kodiBase, - m_controlHandle, value); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief To get the current position as float value. - /// - /// @return The position as float - /// - float GetFloatValue() const - { - return m_interface->kodi_gui->control_settings_slider->get_float_value(m_interface->kodiBase, - m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSettingsSlider - /// @brief To set the interval steps of slider, as default is it 0.1 If it - /// becomes changed with this function will a step of the user with the - /// value fixed here be executed. - /// - /// @param[in] interval Intervall step to set. - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values ​​can be not together and can, therefore, only - /// one each can be used. - /// - void SetFloatInterval(float interval) - { - m_interface->kodi_gui->control_settings_slider->set_float_interval(m_interface->kodiBase, - m_controlHandle, interval); - } - //-------------------------------------------------------------------------- -}; - -} /* namespace controls */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Slider.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Slider.h deleted file mode 100644 index 715cc7d..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Slider.h +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../Window.h" - -namespace kodi -{ -namespace gui -{ -namespace controls -{ - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_controls_CSlider Control Slider -/// \ingroup cpp_kodi_gui -/// @brief \cpp_class{ kodi::gui::controls::CSlider } -/// **Window control for moveable slider** -/// -/// The slider control is used for things where a sliding bar best represents -/// the operation at hand (such as a volume control or seek control). You can -/// choose the position, size, and look of the slider control. -/// -/// It has the header \ref Slider.h "#include " -/// be included to enjoy it. -/// -/// Here you find the needed skin part for a \ref Slider_Control "slider control" -/// -/// @note The call of the control is only possible from the corresponding -/// window as its class and identification number is required. -/// -class ATTRIBUTE_HIDDEN CSlider : public CAddonGUIControlBase -{ -public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief Construct a new control - /// - /// @param[in] window related window control class - /// @param[in] controlId Used skin xml control id - /// - CSlider(CWindow* window, int controlId) : CAddonGUIControlBase(window) - { - m_controlHandle = m_interface->kodi_gui->window->get_control_slider( - m_interface->kodiBase, m_Window->GetControlHandle(), controlId); - if (!m_controlHandle) - kodi::Log(ADDON_LOG_FATAL, - "kodi::gui::controls::CSlider can't create control class from Kodi !!!"); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief Destructor - /// - ~CSlider() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief Set the control on window to visible - /// - /// @param[in] visible If true visible, otherwise hidden - /// - void SetVisible(bool visible) - { - m_interface->kodi_gui->control_slider->set_visible(m_interface->kodiBase, m_controlHandle, - visible); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief Set's the control's enabled/disabled state - /// - /// @param[in] enabled If true enabled, otherwise disabled - /// - void SetEnabled(bool enabled) - { - m_interface->kodi_gui->control_slider->set_enabled(m_interface->kodiBase, m_controlHandle, - enabled); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief To reset slider on defaults - /// - void Reset() - { - m_interface->kodi_gui->control_slider->reset(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief With GetDescription becomes a string value of position returned. - /// - /// @return Text string about current slider position - /// - /// The following are the text definition returned from this: - /// | Value | Without range selection | With range selection | - /// |:---------:|:------------------------|:-------------------------------| - /// | float | %2.2f | [%2.2f, %2.2f] | - /// | integer | %i | [%i, %i] | - /// | percent | %i%% | [%i%%, %i%%] | - /// - std::string GetDescription() const - { - std::string text; - char* ret = m_interface->kodi_gui->control_slider->get_description(m_interface->kodiBase, - m_controlHandle); - if (ret != nullptr) - { - if (std::strlen(ret)) - text = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return text; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief To set the the range as integer of slider, e.g. -10 is the slider - /// start and e.g. +10 is the from here defined position where it reach the - /// end. - /// - /// Ad default is the range from 0 to 100. - /// - /// The integer interval is as default 1 and can be changed with - /// @ref SetIntInterval. - /// - /// @param[in] start Integer start value - /// @param[in] end Integer end value - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only one - /// each can be used. - /// - void SetIntRange(int start, int end) - { - m_interface->kodi_gui->control_slider->set_int_range(m_interface->kodiBase, m_controlHandle, - start, end); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup CSlider - /// @brief Set the slider position with the given integer value. The Range - /// must be defined with a call from \ref SetIntRange before. - /// - /// @param[in] value Position in range to set with integer - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only one - /// each can be used. - /// - void SetIntValue(int value) - { - m_interface->kodi_gui->control_slider->set_int_value(m_interface->kodiBase, m_controlHandle, - value); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief To get the current position as integer value. - /// - /// @return The position as integer - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only - /// one each can be used. - /// - int GetIntValue() const - { - return m_interface->kodi_gui->control_slider->get_int_value(m_interface->kodiBase, - m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief To set the interval steps of slider, as default is it 1. If it - /// becomes changed with this function will a step of the user with the - /// value fixed here be executed. - /// - /// @param[in] interval Intervall step to set. - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only one - /// each can be used. - /// - void SetIntInterval(int interval) - { - m_interface->kodi_gui->control_slider->set_int_interval(m_interface->kodiBase, m_controlHandle, - interval); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief Sets the percent of the slider. - /// - /// @param[in] percent float - Percent value of slide - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only one - /// each can be used. - /// - void SetPercentage(float percent) - { - m_interface->kodi_gui->control_slider->set_percentage(m_interface->kodiBase, m_controlHandle, - percent); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief Returns a float of the percent of the slider. - /// - /// @return float - Percent of slider - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only one - /// each can be used. - /// - float GetPercentage() const - { - return m_interface->kodi_gui->control_slider->get_percentage(m_interface->kodiBase, - m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief To set the the range as float of slider, e.g. -25.0 is the slider - /// start and e.g. +25.0 is the from here defined position where it reach - /// the end. - /// - /// As default is the range 0.0 to 1.0. - /// - /// The float interval is as default 0.1 and can be changed with - /// @ref SetFloatInterval. - /// - /// @param[in] start Integer start value - /// @param[in] end Integer end value - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only - /// one each can be used. - /// - void SetFloatRange(float start, float end) - { - m_interface->kodi_gui->control_slider->set_float_range(m_interface->kodiBase, m_controlHandle, - start, end); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief Set the slider position with the given float value. The Range - /// can be defined with a call from \ref SetIntRange before, as default it - /// is 0.0 to 1.0. - /// - /// @param[in] value Position in range to set with float - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only one - /// each can be used. - /// - void SetFloatValue(float value) - { - m_interface->kodi_gui->control_slider->set_float_value(m_interface->kodiBase, m_controlHandle, - value); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief To get the current position as float value. - /// - /// @return The position as float - /// - float GetFloatValue() const - { - return m_interface->kodi_gui->control_slider->get_float_value(m_interface->kodiBase, - m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSlider - /// @brief To set the interval steps of slider, as default is it 0.1 If it - /// becomes changed with this function will a step of the user with the - /// value fixed here be executed. - /// - /// @param[in] interval Intervall step to set. - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only - /// one each can be used. - /// - void SetFloatInterval(float interval) - { - m_interface->kodi_gui->control_slider->set_float_interval(m_interface->kodiBase, - m_controlHandle, interval); - } - //-------------------------------------------------------------------------- -}; - -} /* namespace controls */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Spin.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Spin.h deleted file mode 100644 index db8d491..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/Spin.h +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../Window.h" - -namespace kodi -{ -namespace gui -{ -namespace controls -{ - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_controls_CSpin Control Spin - /// \ingroup cpp_kodi_gui - /// @brief \cpp_class{ kodi::gui::controls::CSpin } - /// **Window control used for cycling up/down controls** - /// - /// The settings spin control is used in the settings screens for when a list - /// of options can be chosen from using up/down arrows. You can choose the - /// position, size, and look of the spin control. It is basically a cross - /// between the button control and a spin control. It has a label and focus - /// and non focus textures, as well as a spin control on the right. - /// - /// It has the header \ref Spin.h "#include " - /// be included to enjoy it. - /// - /// Here you find the needed skin part for a \ref Spin_Control "spin control" - /// - /// @note The call of the control is only possible from the corresponding - /// window as its class and identification number is required. - /// - - - //============================================================================ - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @anchor AddonGUISpinControlType - /// @brief The values here defines the used value format for steps on - /// spin control. - /// - typedef enum AddonGUISpinControlType - { - /// One spin step interpreted as integer - ADDON_SPIN_CONTROL_TYPE_INT = 1, - /// One spin step interpreted as floating point value - ADDON_SPIN_CONTROL_TYPE_FLOAT = 2, - /// One spin step interpreted as text string - ADDON_SPIN_CONTROL_TYPE_TEXT = 3, - /// One spin step interpreted as a page change value - ADDON_SPIN_CONTROL_TYPE_PAGE = 4 - } AddonGUISpinControlType; - //---------------------------------------------------------------------------- - - class ATTRIBUTE_HIDDEN CSpin : public CAddonGUIControlBase - { - public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief Construct a new control - /// - /// @param[in] window related window control class - /// @param[in] controlId Used skin xml control id - /// - CSpin(CWindow* window, int controlId) - : CAddonGUIControlBase(window) - { - m_controlHandle = m_interface->kodi_gui->window->get_control_spin(m_interface->kodiBase, m_Window->GetControlHandle(), controlId); - if (!m_controlHandle) - kodi::Log(ADDON_LOG_FATAL, "kodi::gui::controls::CSpin can't create control class from Kodi !!!"); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief Destructor - /// - ~CSpin() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief Set the control on window to visible - /// - /// @param[in] visible If true visible, otherwise hidden - /// - void SetVisible(bool visible) - { - m_interface->kodi_gui->control_spin->set_visible(m_interface->kodiBase, m_controlHandle, visible); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief Set's the control's enabled/disabled state - /// - /// @param[in] enabled If true enabled, otherwise disabled - /// - void SetEnabled(bool enabled) - { - m_interface->kodi_gui->control_spin->set_enabled(m_interface->kodiBase, m_controlHandle, enabled); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief To set the text string on spin control - /// - /// @param[in] text Text to show as name for spin - /// - void SetText(const std::string& text) - { - m_interface->kodi_gui->control_spin->set_text(m_interface->kodiBase, m_controlHandle, text.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief To reset spin control to defaults - /// - void Reset() - { - m_interface->kodi_gui->control_spin->reset(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief To set the with SpinControlType defined types of spin. - /// - /// @param[in] type The type to use - /// - /// @note See description of \ref AddonGUISpinControlType for available types. - /// - void SetType(AddonGUISpinControlType type) - { - m_interface->kodi_gui->control_spin->set_type(m_interface->kodiBase, m_controlHandle, (int)type); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief To add a label entry in spin defined with a value as string. - /// - /// Format must be set to ADDON_SPIN_CONTROL_TYPE_TEXT to use this function. - /// - /// @param[in] label Label string to view on skin - /// @param[in] value String value to use for selection - /// of them. - /// - void AddLabel(const std::string& label, const std::string& value) - { - m_interface->kodi_gui->control_spin->add_string_label(m_interface->kodiBase, m_controlHandle, label.c_str(), value.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief To add a label entry in spin defined with a value as integer. - /// - /// Format must be set to ADDON_SPIN_CONTROL_TYPE_INT to use this function. - /// - /// @param[in] label Label string to view on skin - /// @param[in] value Integer value to use for selection - /// of them. - /// - void AddLabel(const std::string& label, int value) - { - m_interface->kodi_gui->control_spin->add_int_label(m_interface->kodiBase, m_controlHandle, label.c_str(), value); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief To change the spin to position with them string as value. - /// - /// Format must be set to ADDON_SPIN_CONTROL_TYPE_TEXT to use this function. - /// - /// @param[in] value String value to change to - /// - void SetStringValue(const std::string& value) - { - m_interface->kodi_gui->control_spin->set_string_value(m_interface->kodiBase, m_controlHandle, value.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief To get the current spin control position with text string value. - /// - /// Format must be set to ADDON_SPIN_CONTROL_TYPE_TEXT to use this function. - /// - /// @return Currently selected string value - /// - std::string GetStringValue() const - { - std::string value; - char* ret = m_interface->kodi_gui->control_spin->get_string_value(m_interface->kodiBase, m_controlHandle); - if (ret != nullptr) - { - if (std::strlen(ret)) - value = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return value; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief To set the the range as integer of slider, e.g. -10 is the slider - /// start and e.g. +10 is the from here defined position where it reach the - /// end. - /// - /// Ad default is the range from 0 to 100. - /// - /// @param[in] start Integer start value - /// @param[in] end Integer end value - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only - /// one each can be used and must be defined with \ref SetType before. - /// - void SetIntRange(int start, int end) - { - m_interface->kodi_gui->control_spin->set_int_range(m_interface->kodiBase, m_controlHandle, start, end); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief Set the slider position with the given integer value. The Range - /// must be defined with a call from \ref SetIntRange before. - /// - /// @param[in] value Position in range to set with integer - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only - /// one each can be used and must be defined with \ref SetType before. - /// - void SetIntValue(int value) - { - m_interface->kodi_gui->control_spin->set_int_value(m_interface->kodiBase, m_controlHandle, value); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief To get the current position as integer value. - /// - /// @return The position as integer - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only - /// one each can be used and must be defined with \ref SetType before. - /// - int GetIntValue() const - { - return m_interface->kodi_gui->control_spin->get_int_value(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief To set the the range as float of spin, e.g. -25.0 is the spin - /// start and e.g. +25.0 is the from here defined position where it reach - /// the end. - /// - /// As default is the range 0.0 to 1.0. - /// - /// The float interval is as default 0.1 and can be changed with - /// @ref SetFloatInterval. - /// - /// @param[in] start Integer start value - /// @param[in] end Integer end value - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only - /// one each can be used and must be defined with \ref SetType before. - /// - void SetFloatRange(float start, float end) - { - m_interface->kodi_gui->control_spin->set_float_range(m_interface->kodiBase, m_controlHandle, start, end); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief Set the spin position with the given float value. The Range - /// can be defined with a call from \ref SetIntRange before, as default it - /// is 0.0 to 1.0. - /// - /// @param[in] value Position in range to set with float - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only - /// one each can be used and must be defined with \ref SetType before. - /// - void SetFloatValue(float value) - { - m_interface->kodi_gui->control_spin->set_float_value(m_interface->kodiBase, m_controlHandle, value); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief To get the current position as float value. - /// - /// @return The position as float - /// - float GetFloatValue() const - { - return m_interface->kodi_gui->control_spin->get_float_value(m_interface->kodiBase, m_controlHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CSpin - /// @brief To set the interval steps of spin, as default is it 0.1 If it - /// becomes changed with this function will a step of the user with the - /// value fixed here be executed. - /// - /// @param[in] interval Intervall step to set. - /// - /// @note Percent, floating point or integer are alone possible. Combining - /// these different values can be not together and can, therefore, only - /// one each can be used and must be defined with \ref SetType before. - /// - void SetFloatInterval(float interval) - { - m_interface->kodi_gui->control_spin->set_float_interval(m_interface->kodiBase, m_controlHandle, interval); - } - //-------------------------------------------------------------------------- - }; - -} /* namespace controls */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/TextBox.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/TextBox.h deleted file mode 100644 index b4e8ae0..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/controls/TextBox.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../Window.h" - -namespace kodi -{ -namespace gui -{ -namespace controls -{ - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_controls_CTextBox Control Text Box -/// \ingroup cpp_kodi_gui -/// @brief \cpp_class{ kodi::gui::controls::CTextBox } -/// **Used to show a multi-page piece of text** -/// -/// The text box control can be used to display descriptions, help texts or -/// other larger texts. It corresponds to the representation which is also to -/// be seen on the CDialogTextViewer. -/// -/// It has the header \ref TextBox.h "#include " -/// be included to enjoy it. -/// -/// Here you find the needed skin part for a \ref Text_Box "textbox control". -/// -/// @note The call of the control is only possible from the corresponding -/// window as its class and identification number is required. -/// -class ATTRIBUTE_HIDDEN CTextBox : public CAddonGUIControlBase -{ -public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CTextBox - /// @brief Construct a new control - /// - /// @param[in] window related window control class - /// @param[in] controlId Used skin xml control id - /// - CTextBox(CWindow* window, int controlId) : CAddonGUIControlBase(window) - { - m_controlHandle = m_interface->kodi_gui->window->get_control_text_box( - m_interface->kodiBase, m_Window->GetControlHandle(), controlId); - if (!m_controlHandle) - kodi::Log(ADDON_LOG_FATAL, - "kodi::gui::controls::CTextBox can't create control class from Kodi !!!"); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CTextBox - /// @brief Destructor - /// - ~CTextBox() override = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CTextBox - /// @brief Set the control on window to visible - /// - /// @param[in] visible If true visible, otherwise hidden - /// - void SetVisible(bool visible) - { - m_interface->kodi_gui->control_text_box->set_visible(m_interface->kodiBase, m_controlHandle, - visible); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CTextBox - /// @brief To reset box an remove all the text - /// - void Reset() { m_interface->kodi_gui->control_text_box->reset(m_controlHandle, m_controlHandle); } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CTextBox - /// @brief To set the text on box - /// - /// @param[in] text Text to show - /// - void SetText(const std::string& text) - { - m_interface->kodi_gui->control_text_box->set_text(m_interface->kodiBase, m_controlHandle, - text.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CTextBox - /// @brief Get the used text from control - /// - /// @return Text shown - /// - std::string GetText() const - { - std::string text; - char* ret = - m_interface->kodi_gui->control_text_box->get_text(m_interface->kodiBase, m_controlHandle); - if (ret != nullptr) - { - if (std::strlen(ret)) - text = ret; - m_interface->free_string(m_interface->kodiBase, ret); - } - return text; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CTextBox - /// @brief To scroll text on other position - /// - /// @param[in] position The line position to scroll to - /// - void Scroll(unsigned int position) - { - m_interface->kodi_gui->control_text_box->scroll(m_interface->kodiBase, m_controlHandle, - position); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_controls_CTextBox - /// @brief To set automatic scrolling of textbox - /// - /// Specifies the timing and conditions of any autoscrolling this textbox - /// should have. Times are in milliseconds. The content is delayed for the - /// given delay, then scrolls at a rate of one line per time interval until - /// the end. If the repeat tag is present, it then delays for the repeat - /// time, fades out over 1 second, and repeats. It does not wrap or reset - /// to the top at the end of the scroll. - /// - /// @param[in] delay Content delay - /// @param[in] time One line per time interval - /// @param[in] repeat Delays with given time, fades out over 1 - /// second, and repeats - /// - void SetAutoScrolling(int delay, int time, int repeat) - { - m_interface->kodi_gui->control_text_box->set_auto_scrolling( - m_interface->kodiBase, m_controlHandle, delay, time, repeat); - } - //-------------------------------------------------------------------------- -}; - -} /* namespace controls */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/definitions.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/definitions.h deleted file mode 100644 index 4eb64c7..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/definitions.h +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include -#include - -/* - * Internal Structures to have "C"-Style data transfer - */ -extern "C" -{ - -typedef struct AddonToKodiFuncTable_kodi_gui_general -{ - void (*lock)(); - void (*unlock)(); - int (*get_screen_height)(void* kodiBase); - int (*get_screen_width)(void* kodiBase); - int (*get_video_resolution)(void* kodiBase); - int (*get_current_window_dialog_id)(void* kodiBase); - int (*get_current_window_id)(void* kodiBase); - void* (*get_hw_context)(void* kodiBase); -} AddonToKodiFuncTable_kodi_gui_general; - -typedef struct AddonToKodiFuncTable_kodi_gui_control_button -{ - void (*set_visible)(void* kodiBase, void* handle, bool visible); - void (*set_enabled)(void* kodiBase, void* handle, bool enabled); - void (*set_label)(void* kodiBase, void* handle, const char* label); - char* (*get_label)(void* kodiBase, void* handle); - void (*set_label2)(void* kodiBase, void* handle, const char *label); - char* (*get_label2)(void* kodiBase, void* handle); -} AddonToKodiFuncTable_kodi_gui_control_button; - -typedef struct AddonToKodiFuncTable_kodi_gui_control_edit -{ - void (*set_visible)(void* kodiBase, void* handle, bool visible); - void (*set_enabled)(void* kodiBase, void* handle, bool enabled); - void (*set_label)(void* kodiBase, void* handle, const char* label); - char* (*get_label)(void* kodiBase, void* handle); - void (*set_text)(void* kodiBase, void* handle, const char* text); - char* (*get_text)(void* kodiBase, void* handle); - void (*set_cursor_position)(void* kodiBase, void* handle, unsigned int position); - unsigned int (*get_cursor_position)(void* kodiBase, void* handle); - void (*set_input_type)(void* kodiBase, void* handle, int type, const char* heading); -} AddonToKodiFuncTable_kodi_gui_control_edit; - -typedef struct AddonToKodiFuncTable_kodi_gui_control_fade_label -{ - void (*set_visible)(void* kodiBase, void* handle, bool visible); - void (*add_label)(void* kodiBase, void* handle, const char* text); - char* (*get_label)(void* kodiBase, void* handle); - void (*set_scrolling)(void* kodiBase, void* handle, bool scroll); - void (*reset)(void* kodiBase, void* handle); -} AddonToKodiFuncTable_kodi_gui_control_fade_label; - -typedef struct AddonToKodiFuncTable_kodi_gui_control_image -{ - void (*set_visible)(void* kodiBase, void* handle, bool visible); - void (*set_filename)(void* kodiBase, void* handle, const char* filename, bool use_cache); - void (*set_color_diffuse)(void* kodiBase, void* handle, uint32_t color_diffuse); -} AddonToKodiFuncTable_kodi_gui_control_image; - -typedef struct AddonToKodiFuncTable_kodi_gui_control_label -{ - void (*set_visible)(void* kodiBase, void* handle, bool visible); - void (*set_label)(void* kodiBase, void* handle, const char* text); - char* (*get_label)(void* kodiBase, void* handle); -} AddonToKodiFuncTable_kodi_gui_control_label; - -typedef struct AddonToKodiFuncTable_kodi_gui_control_progress -{ - void (*set_visible)(void* kodiBase, void* handle, bool visible); - void (*set_percentage)(void* kodiBase, void* handle, float percent); - float (*get_percentage)(void* kodiBase, void* handle); -} AddonToKodiFuncTable_kodi_gui_control_progress; - -typedef struct AddonToKodiFuncTable_kodi_gui_control_radio_button -{ - void (*set_visible)(void* kodiBase, void* handle, bool visible); - void (*set_enabled)(void* kodiBase, void* handle, bool enabled); - void (*set_label)(void* kodiBase, void* handle, const char* text); - char* (*get_label)(void* kodiBase, void* handle); - void (*set_selected)(void* kodiBase, void* handle, bool selected); - bool (*is_selected)(void* kodiBase, void* handle); -} AddonToKodiFuncTable_kodi_gui_control_radio_button; - -typedef struct AddonToKodiFuncTable_kodi_gui_control_rendering -{ - void (*set_callbacks)(void* kodiBase, void* handle, void* clienthandle, - bool (*createCB)(void*,int,int,int,int,void*), - void (*renderCB)(void*), - void (*stopCB)(void*), - bool (*dirtyCB)(void*)); - void (*destroy)(void *kodiBase, void* handle); -} AddonToKodiFuncTable_kodi_gui_control_rendering; - -typedef struct AddonToKodiFuncTable_kodi_gui_control_settings_slider -{ - void (*set_visible)(void* kodiBase, void* handle, bool visible); - void (*set_enabled)(void* kodiBase, void* handle, bool enabled); - void (*set_text)(void* kodiBase, void* handle, const char* label); - void (*reset)(void* kodiBase, void* handle); - void (*set_int_range)(void* kodiBase, void* handle, int start, int end); - void (*set_int_value)(void* kodiBase, void* handle, int value); - int (*get_int_value)(void* kodiBase, void* handle); - void (*set_int_interval)(void* kodiBase, void* handle, int interval); - void (*set_percentage)(void* kodiBase, void* handle, float percent); - float (*get_percentage)(void* kodiBase, void* handle); - void (*set_float_range)(void* kodiBase, void* handle, float start, float end); - void (*set_float_value)(void* kodiBase, void* handle, float value); - float (*get_float_value)(void* kodiBase, void* handle); - void (*set_float_interval)(void* kodiBase, void* handle, float interval); -} AddonToKodiFuncTable_kodi_gui_control_settings_slider; - -typedef struct AddonToKodiFuncTable_kodi_gui_control_slider -{ - void (*set_visible)(void* kodiBase, void* handle, bool visible); - void (*set_enabled)(void* kodiBase, void* handle, bool enabled); - void (*reset)(void* kodiBase, void* handle); - char* (*get_description)(void* kodiBase, void* handle); - void (*set_int_range)(void* kodiBase, void* handle, int start, int end); - void (*set_int_value)(void* kodiBase, void* handle, int value); - int (*get_int_value)(void* kodiBase, void* handle); - void (*set_int_interval)(void* kodiBase, void* handle, int interval); - void (*set_percentage)(void* kodiBase, void* handle, float percent); - float (*get_percentage)(void* kodiBase, void* handle); - void (*set_float_range)(void* kodiBase, void* handle, float start, float end); - void (*set_float_value)(void* kodiBase, void* handle, float value); - float (*get_float_value)(void* kodiBase, void* handle); - void (*set_float_interval)(void* kodiBase, void* handle, float interval); -} AddonToKodiFuncTable_kodi_gui_control_slider; - -typedef struct AddonToKodiFuncTable_kodi_gui_control_spin -{ - void (*set_visible)(void* kodiBase, void* handle, bool visible); - void (*set_enabled)(void* kodiBase, void* handle, bool enabled); - void (*set_text)(void* kodiBase, void* handle, const char* text); - void (*reset)(void* kodiBase, void* handle); - void (*set_type)(void* kodiBase, void* handle, int type); - void (*add_string_label)(void* kodiBase, void* handle, const char* label, const char* value); - void (*set_string_value)(void* kodiBase, void* handle, const char* value); - char* (*get_string_value)(void* kodiBase, void* handle); - void (*add_int_label)(void* kodiBase, void* handle, const char* label, int value); - void (*set_int_range)(void* kodiBase, void* handle, int start, int end); - void (*set_int_value)(void* kodiBase, void* handle, int value); - int (*get_int_value)(void* kodiBase, void* handle); - void (*set_float_range)(void* kodiBase, void* handle, float start, float end); - void (*set_float_value)(void* kodiBase, void* handle, float value); - float (*get_float_value)(void* kodiBase, void* handle); - void (*set_float_interval)(void* kodiBase, void* handle, float interval); -} AddonToKodiFuncTable_kodi_gui_control_spin; - -typedef struct AddonToKodiFuncTable_kodi_gui_control_text_box -{ - void (*set_visible)(void* kodiBase, void* handle, bool visible); - void (*reset)(void* kodiBase, void* handle); - void (*set_text)(void* kodiBase, void* handle, const char* text); - char* (*get_text)(void* kodiBase, void* handle); - void (*scroll)(void* kodiBase, void* handle, unsigned int scroll); - void (*set_auto_scrolling)(void* kodiBase, void* handle, int delay, int time, int repeat); -} AddonToKodiFuncTable_kodi_gui_control_text_box; - -typedef struct AddonToKodiFuncTable_kodi_gui_dialogContextMenu -{ - int (*open)(void* kodiBase, const char *heading, const char *entries[], unsigned int size); -} AddonToKodiFuncTable_kodi_gui_dialogContextMenu; - -typedef struct AddonToKodiFuncTable_kodi_gui_dialogExtendedProgress -{ - void* (*new_dialog)(void* kodiBase, const char *title); - void (*delete_dialog)(void* kodiBase, void* handle); - char* (*get_title)(void* kodiBase, void* handle); - void (*set_title)(void* kodiBase, void* handle, const char *title); - char* (*get_text)(void* kodiBase, void* handle); - void (*set_text)(void* kodiBase, void* handle, const char *text); - bool (*is_finished)(void* kodiBase, void* handle); - void (*mark_finished)(void* kodiBase, void* handle); - float (*get_percentage)(void* kodiBase, void* handle); - void (*set_percentage)(void* kodiBase, void* handle, float percentage); - void (*set_progress)(void* kodiBase, void* handle, int currentItem, int itemCount); -} AddonToKodiFuncTable_kodi_gui_dialogExtendedProgress; - -typedef struct AddonToKodiFuncTable_kodi_gui_dialogFileBrowser -{ - bool (*show_and_get_directory)(void* kodiBase, const char* shares, const char* heading, const char* path_in, char** path_out, bool writeOnly); - bool (*show_and_get_file)(void* kodiBase, const char* shares, const char* mask, const char* heading, const char* path_in, char** path_out, bool use_thumbs, bool use_file_directories); - bool (*show_and_get_file_from_dir)(void* kodiBase, const char* directory, const char* mask, const char* heading, const char* path_in, char** path_out, bool use_thumbs, bool use_file_directories, bool singleList); - bool (*show_and_get_file_list)(void* kodiBase, const char* shares, const char* mask, const char* heading, char*** file_list, unsigned int* entries, bool use_thumbs, bool use_file_directories); - bool (*show_and_get_source)(void* kodiBase, const char* path_in, char** path_out, bool allow_network_shares, const char* additional_share, const char* type); - bool (*show_and_get_image)(void* kodiBase, const char* shares, const char* heading, const char* path_in, char** path_out); - bool (*show_and_get_image_list)(void* kodiBase, const char* shares, const char* heading, char*** file_list, unsigned int* entries); - void (*clear_file_list)(void* kodiBase, char*** file_list, unsigned int entries); -} AddonToKodiFuncTable_kodi_gui_dialogFileBrowser; - -// typedef void (*char_callback_t) (CGUIKeyboard *ref, const std::string &typedString); - -typedef struct AddonToKodiFuncTable_kodi_gui_dialogKeyboard -{ - bool (*show_and_get_input_with_head)(void* kodiBase, const char* text_in, char** text_out, const char* heading, bool allow_empty_result, bool hiddenInput, unsigned int auto_close_ms); - bool (*show_and_get_input)(void* kodiBase, const char* text_in, char** text_out, bool allow_empty_result, unsigned int auto_close_ms); - bool (*show_and_get_new_password_with_head)(void* kodiBase, const char* password_in, char** password_out, const char* heading, bool allow_empty_result, unsigned int auto_close_ms); - bool (*show_and_get_new_password)(void* kodiBase, const char* password_in, char** password_out, unsigned int auto_close_ms); - bool (*show_and_verify_new_password_with_head)(void* kodiBase, char** password_out, const char* heading, bool allow_empty_result, unsigned int auto_close_ms); - bool (*show_and_verify_new_password)(void* kodiBase, char** password_out, unsigned int auto_close_ms); - int (*show_and_verify_password)(void* kodiBase, const char* password_in, char** password_out, const char* heading, int retries, unsigned int auto_close_ms); - bool (*show_and_get_filter)(void* kodiBase, const char* text_in, char** text_out, bool searching, unsigned int auto_close_ms); - bool (*send_text_to_active_keyboard)(void* kodiBase, const char* text, bool close_keyboard); - bool (*is_keyboard_activated)(void* kodiBase); -} AddonToKodiFuncTable_kodi_gui_dialogKeyboard; - -typedef struct AddonToKodiFuncTable_kodi_gui_dialogNumeric -{ - bool (*show_and_verify_new_password)(void* kodiBase, char** password); - int (*show_and_verify_password)(void* kodiBase, const char* password, const char *heading, int retries); - bool (*show_and_verify_input)(void* kodiBase, const char* verify_in, char** verify_out, const char* heading, bool verify_input); - bool (*show_and_get_time)(void* kodiBase, tm *time, const char *heading); - bool (*show_and_get_date)(void* kodiBase, tm *date, const char *heading); - bool (*show_and_get_ip_address)(void* kodiBase, const char* ip_address_in, char** ip_address_out, const char *heading); - bool (*show_and_get_number)(void* kodiBase, const char* input_in, char** input_out, const char *heading, unsigned int auto_close_ms); - bool (*show_and_get_seconds)(void* kodiBase, const char* time_in, char** time_out, const char *heading); -} AddonToKodiFuncTable_kodi_gui_dialogNumeric; - -typedef struct AddonToKodiFuncTable_kodi_gui_dialogOK -{ - void (*show_and_get_input_single_text)(void* kodiBase, const char *heading, const char *text); - void (*show_and_get_input_line_text)(void* kodiBase, const char *heading, const char *line0, const char *line1, const char *line2); -} AddonToKodiFuncTable_kodi_gui_dialogOK; - -typedef struct AddonToKodiFuncTable_kodi_gui_dialogProgress -{ - void* (*new_dialog)(void* kodiBase); - void (*delete_dialog)(void* kodiBase, void* handle); - void (*open)(void* kodiBase, void* handle); - void (*set_heading)(void* kodiBase, void* handle, const char* heading); - void (*set_line)(void* kodiBase, void* handle, unsigned int lineNo, const char* line); - void (*set_can_cancel)(void* kodiBase, void* handle, bool canCancel); - bool (*is_canceled)(void* kodiBase, void* handle); - void (*set_percentage)(void* kodiBase, void* handle, int percentage); - int (*get_percentage)(void* kodiBase, void* handle); - void (*show_progress_bar)(void* kodiBase, void* handle, bool pnOff); - void (*set_progress_max)(void* kodiBase, void* handle, int max); - void (*set_progress_advance)(void* kodiBase, void* handle, int nSteps); - bool (*abort)(void* kodiBase, void* handle); -} AddonToKodiFuncTable_kodi_gui_dialogProgress; - -typedef struct AddonToKodiFuncTable_kodi_gui_dialogSelect -{ - int (*open)(void* kodiBase, const char *heading, const char *entries[], unsigned int size, int selected, unsigned int autoclose); - bool (*open_multi_select)(void* kodiBase, const char* heading, const char* entryIDs[], const char* entryNames[], - bool entriesSelected[], unsigned int size, unsigned int autoclose); -} AddonToKodiFuncTable_kodi_gui_dialogSelect; - -typedef struct AddonToKodiFuncTable_kodi_gui_dialogTextViewer -{ - void (*open)(void* kodiBase, const char *heading, const char *text); -} AddonToKodiFuncTable_kodi_gui_dialogTextViewer; - -typedef struct AddonToKodiFuncTable_kodi_gui_dialogYesNo -{ - bool (*show_and_get_input_single_text)(void* kodiBase, const char *heading, const char *text, bool *canceled, const char *noLabel, const char *yesLabel); - bool (*show_and_get_input_line_text)(void* kodiBase, const char *heading, const char *line0, const char *line1, const char *line2, const char *noLabel, const char *yesLabel); - bool (*show_and_get_input_line_button_text)(void* kodiBase, const char *heading, const char *line0, const char *line1, const char *line2, bool *canceled, const char *noLabel, const char *yesLabel); -} AddonToKodiFuncTable_kodi_gui_dialogYesNo; - -typedef struct AddonToKodiFuncTable_kodi_gui_listItem -{ - void* (*create)(void* kodiBase, const char* label, const char* label2, const char* icon_image, const char* path); - void (*destroy)(void* kodiBase, void* handle); - char* (*get_label)(void* kodiBase, void* handle); - void (*set_label)(void* kodiBase, void* handle, const char* label); - char* (*get_label2)(void* kodiBase, void* handle); - void (*set_label2)(void* kodiBase, void* handle, const char* label); - char* (*get_art)(void* kodiBase, void* handle, const char* type); - void (*set_art)(void* kodiBase, void* handle, const char* type, const char* image); - char* (*get_path)(void* kodiBase, void* handle); - void (*set_path)(void* kodiBase, void* handle, const char* path); - char* (*get_property)(void* kodiBase, void* handle, const char* key); - void (*set_property)(void* kodiBase, void* handle, const char* key, const char* value); - void (*select)(void* kodiBase, void* handle, bool select); - bool (*is_selected)(void* kodiBase, void* handle); -} AddonToKodiFuncTable_kodi_gui_listItem; - -#define ADDON_MAX_CONTEXT_ENTRIES 20 -#define ADDON_MAX_CONTEXT_ENTRY_NAME_LENGTH 80 -typedef struct gui_context_menu_pair -{ - unsigned int id; - char name[ADDON_MAX_CONTEXT_ENTRY_NAME_LENGTH]; -} gui_context_menu_pair; - -typedef struct AddonToKodiFuncTable_kodi_gui_window -{ - /* Window creation functions */ - void* (*create)(void* kodiBase, const char* xml_filename, const char* default_skin, bool as_dialog, bool is_media); - void (*destroy)(void* kodiBase, void* handle); - void (*set_callbacks)(void* kodiBase, void* handle, void* clienthandle, - bool (*CBInit)(void*), - bool (*CBFocus)(void*, int), - bool (*CBClick)(void*, int), - bool (*CBOnAction)(void*, int, uint32_t, wchar_t), - void (*CBGetContextButtons)(void*, int, gui_context_menu_pair*, unsigned int*), - bool (*CBOnContextButton)(void*, int, unsigned int)); - bool (*show)(void* kodiBase, void* handle); - bool (*close)(void* kodiBase, void* handle); - bool (*do_modal)(void* kodiBase, void* handle); - - /* Window control functions */ - bool (*set_focus_id)(void* kodiBase, void* handle, int control_id); - int (*get_focus_id)(void* kodiBase, void* handle); - void (*set_control_label)(void* kodiBase, void* handle, int control_id, const char* label); - void (*set_control_visible)(void* kodiBase, void* handle, int control_id, bool visible); - void (*set_control_selected)(void* kodiBase, void* handle, int control_id, bool selected); - - /* Window property functions */ - void (*set_property)(void* kodiBase, void* handle, const char* key, const char* value); - void (*set_property_int)(void* kodiBase, void* handle, const char* key, int value); - void (*set_property_bool)(void* kodiBase, void* handle, const char* key, bool value); - void (*set_property_double)(void* kodiBase, void* handle, const char* key, double value); - char* (*get_property)(void* kodiBase, void* handle, const char* key); - int (*get_property_int)(void* kodiBase, void* handle, const char* key); - bool (*get_property_bool)(void* kodiBase, void* handle, const char* key); - double (*get_property_double)(void* kodiBase, void* handle, const char* key); - void (*clear_properties)(void* kodiBase, void* handle); - void (*clear_property)(void* kodiBase, void* handle, const char* key); - - /* List item functions */ - void (*clear_item_list)(void* kodiBase, void* handle); - void (*add_list_item)(void* kodiBase, void* handle, void* item, int list_position); - void (*remove_list_item_from_position)(void* kodiBase, void* handle, int list_position); - void (*remove_list_item)(void* kodiBase, void* handle, void* item); - void* (*get_list_item)(void* kodiBase, void* handle, int list_position); - void (*set_current_list_position)(void* kodiBase, void* handle, int list_position); - int (*get_current_list_position)(void* kodiBase, void* handle); - int (*get_list_size)(void* kodiBase, void* handle); - void (*set_container_property)(void* kodiBase, void* handle, const char* key, const char* value); - void (*set_container_content)(void* kodiBase, void* handle, const char* value); - int (*get_current_container_id)(void* kodiBase, void* handle); - - /* Various functions */ - void (*mark_dirty_region)(void* kodiBase, void* handle); - - /* GUI control access functions */ - void* (*get_control_button)(void* kodiBase, void* handle, int control_id); - void* (*get_control_edit)(void* kodiBase, void* handle, int control_id); - void* (*get_control_fade_label)(void* kodiBase, void* handle, int control_id); - void* (*get_control_image)(void* kodiBase, void* handle, int control_id); - void* (*get_control_label)(void* kodiBase, void* handle, int control_id); - void* (*get_control_progress)(void* kodiBase, void* handle, int control_id); - void* (*get_control_radio_button)(void* kodiBase, void* handle, int control_id); - void* (*get_control_render_addon)(void* kodiBase, void* handle, int control_id); - void* (*get_control_settings_slider)(void* kodiBase, void* handle, int control_id); - void* (*get_control_slider)(void* kodiBase, void* handle, int control_id); - void* (*get_control_spin)(void* kodiBase, void* handle, int control_id); - void* (*get_control_text_box)(void* kodiBase, void* handle, int control_id); - void* (*get_control_dummy1)(void* kodiBase, void* handle, int control_id); - void* (*get_control_dummy2)(void* kodiBase, void* handle, int control_id); - void* (*get_control_dummy3)(void* kodiBase, void* handle, int control_id); - void* (*get_control_dummy4)(void* kodiBase, void* handle, int control_id); - void* (*get_control_dummy5)(void* kodiBase, void* handle, int control_id); - void* (*get_control_dummy6)(void* kodiBase, void* handle, int control_id); - void* (*get_control_dummy7)(void* kodiBase, void* handle, int control_id); - void* (*get_control_dummy8)(void* kodiBase, void* handle, int control_id); - void* (*get_control_dummy9)(void* kodiBase, void* handle, int control_id); - void* (*get_control_dummy10)(void* kodiBase, void* handle, int control_id); /* This and above used to add new get_control_* functions */ -} AddonToKodiFuncTable_kodi_gui_window; - -typedef struct AddonToKodiFuncTable_kodi_gui -{ - AddonToKodiFuncTable_kodi_gui_general* general; - AddonToKodiFuncTable_kodi_gui_control_button* control_button; - AddonToKodiFuncTable_kodi_gui_control_edit* control_edit; - AddonToKodiFuncTable_kodi_gui_control_fade_label* control_fade_label; - AddonToKodiFuncTable_kodi_gui_control_label* control_label; - AddonToKodiFuncTable_kodi_gui_control_image* control_image; - AddonToKodiFuncTable_kodi_gui_control_progress* control_progress; - AddonToKodiFuncTable_kodi_gui_control_radio_button* control_radio_button; - AddonToKodiFuncTable_kodi_gui_control_rendering* control_rendering; - AddonToKodiFuncTable_kodi_gui_control_settings_slider* control_settings_slider; - AddonToKodiFuncTable_kodi_gui_control_slider* control_slider; - AddonToKodiFuncTable_kodi_gui_control_spin* control_spin; - AddonToKodiFuncTable_kodi_gui_control_text_box* control_text_box; - void* control_dummy1; - void* control_dummy2; - void* control_dummy3; - void* control_dummy4; - void* control_dummy5; - void* control_dummy6; - void* control_dummy7; - void* control_dummy8; - void* control_dummy9; - void* control_dummy10; /* This and above used to add new controls */ - AddonToKodiFuncTable_kodi_gui_dialogContextMenu* dialogContextMenu; - AddonToKodiFuncTable_kodi_gui_dialogExtendedProgress* dialogExtendedProgress; - AddonToKodiFuncTable_kodi_gui_dialogFileBrowser* dialogFileBrowser; - AddonToKodiFuncTable_kodi_gui_dialogKeyboard* dialogKeyboard; - AddonToKodiFuncTable_kodi_gui_dialogNumeric* dialogNumeric; - AddonToKodiFuncTable_kodi_gui_dialogOK* dialogOK; - AddonToKodiFuncTable_kodi_gui_dialogProgress* dialogProgress; - AddonToKodiFuncTable_kodi_gui_dialogSelect* dialogSelect; - AddonToKodiFuncTable_kodi_gui_dialogTextViewer* dialogTextViewer; - AddonToKodiFuncTable_kodi_gui_dialogYesNo* dialogYesNo; - void* dialog_dummy1; - void* dialog_dummy2; - void* dialog_dummy3; - void* dialog_dummy4; - void* dialog_dummy5; - void* dialog_dummy6; - void* dialog_dummy7; - void* dialog_dummy8; - void* dialog_dummy9; - void* dialog_dummy10; /* This and above used to add new dialogs */ - AddonToKodiFuncTable_kodi_gui_listItem* listItem; - AddonToKodiFuncTable_kodi_gui_window* window; -} AddonToKodiFuncTable_kodi_gui; - -} /* extern "C" */ - -//============================================================================ -/// -/// \ingroup cpp_kodi_gui_CControlRendering_Defs cpp_kodi_gui_CWindow_Defs -/// @{ -/// @brief Handle to use as independent pointer for GUI -typedef void* GUIHANDLE; -/// @} -//---------------------------------------------------------------------------- diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/CMakeLists.txt deleted file mode 100644 index 7227343..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -set(HEADERS ContextMenu.h - ExtendedProgress.h - FileBrowser.h - Keyboard.h - Numeric.h - OK.h - Progress.h - Select.h - TextViewer.h - YesNo.h) - -if(NOT ENABLE_STATIC_LIBS) - core_add_library(addons_kodi-addon-dev-kit_include_kodi_gui_dialogs) -endif() diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/ContextMenu.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/ContextMenu.h deleted file mode 100644 index d545030..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/ContextMenu.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../definitions.h" -#include "../../AddonBase.h" - -namespace kodi -{ -namespace gui -{ -namespace dialogs -{ - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_dialogs_ContextMenu Dialog Context Menu - /// \ingroup cpp_kodi_gui - /// @brief \cpp_namespace{ kodi::gui::dialogs::ContextMenu } - /// **Context menu dialog** - /// - /// The function listed below permits the call of a dialogue as context menu to - /// select of an entry as a key - /// - /// It has the header \ref ContextMenu.h "#include " - /// be included to enjoy it. - /// - /// - namespace ContextMenu - { - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_ContextMenu - /// @brief Show a context menu dialog about given parts. - /// - /// @param[in] heading Dialog heading name - /// @param[in] entries String list about entries - /// @return The selected entry, if return -1 was nothing selected or canceled - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// const std::vector entries - /// { - /// "Test 1", - /// "Test 2", - /// "Test 3", - /// "Test 4", - /// "Test 5" - /// }; - /// - /// int selected = kodi::gui::dialogs::ContextMenu::Show("Test selection", entries); - /// if (selected < 0) - /// fprintf(stderr, "Item selection canceled\n"); - /// else - /// fprintf(stderr, "Selected item is: %i\n", selected); - /// ~~~~~~~~~~~~~ - /// - inline int ATTRIBUTE_HIDDEN Show(const std::string& heading, - const std::vector& entries) - { - using namespace ::kodi::addon; - unsigned int size = static_cast(entries.size()); - const char** cEntries = static_cast(malloc(size * sizeof(const char**))); - for (unsigned int i = 0; i < size; ++i) - { - cEntries[i] = entries[i].c_str(); - } - int ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogContextMenu->open( - CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), cEntries, size); - free(cEntries); - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_ContextMenu - /// @brief Show a context menu dialog about given parts. - /// - /// @param[in] heading Dialog heading name - /// @param[in] entries String list about entries - /// @return The selected entry, if return -1 was nothing selected or canceled - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// const std::vector> entries - /// { - /// { "ID 1", "Test 1" }, - /// { "ID 2", "Test 2" }, - /// { "ID 3", "Test 3" }, - /// { "ID 4", "Test 4" }, - /// { "ID 5", "Test 5" } - /// }; - /// - /// int selected = kodi::gui::dialogs::ContextMenu::Show("Test selection", entries); - /// if (selected < 0) - /// fprintf(stderr, "Item selection canceled\n"); - /// else - /// fprintf(stderr, "Selected item is: %i\n", selected); - /// ~~~~~~~~~~~~~ - /// - inline int ATTRIBUTE_HIDDEN Show( - const std::string& heading, const std::vector>& entries) - { - using namespace ::kodi::addon; - unsigned int size = static_cast(entries.size()); - const char** cEntries = static_cast(malloc(size*sizeof(const char**))); - for (unsigned int i = 0; i < size; ++i) - { - cEntries[i] = entries[i].second.c_str(); - } - int ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogContextMenu->open(CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), cEntries, size); - free(cEntries); - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_ContextMenu - /// @brief Show a context menu dialog about given parts. - /// - /// @param[in] heading Dialog heading name - /// @param[in] entries String list about entries - /// @return The selected entry, if return -1 was nothing selected or canceled - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// const std::vector> entries - /// { - /// { 1, "Test 1" }, - /// { 2, "Test 2" }, - /// { 3, "Test 3" }, - /// { 4, "Test 4" }, - /// { 5, "Test 5" } - /// }; - /// - /// int selected = kodi::gui::dialogs::ContextMenu::Show("Test selection", entries); - /// if (selected < 0) - /// fprintf(stderr, "Item selection canceled\n"); - /// else - /// fprintf(stderr, "Selected item is: %i\n", selected); - /// ~~~~~~~~~~~~~ - /// - inline int ATTRIBUTE_HIDDEN Show(const std::string& heading, - const std::vector>& entries) - { - using namespace ::kodi::addon; - unsigned int size = static_cast(entries.size()); - const char** cEntries = static_cast(malloc(size*sizeof(const char**))); - for (unsigned int i = 0; i < size; ++i) - { - cEntries[i] = entries[i].second.c_str(); - } - int ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogContextMenu->open(CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), cEntries, size); - free(cEntries); - return ret; - } - //-------------------------------------------------------------------------- - }; - -} /* namespace dialogs */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/ExtendedProgress.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/ExtendedProgress.h deleted file mode 100644 index 5a49b70..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/ExtendedProgress.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../definitions.h" -#include "../../AddonBase.h" - -namespace kodi -{ -namespace gui -{ -namespace dialogs -{ - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_dialogs_CExtendedProgress Dialog Extended Progress -/// \ingroup cpp_kodi_gui -/// @brief \cpp_class{ kodi::gui::dialogs::ExtendedProgress } -/// **Progress dialog shown for background work** -/// -/// The with \ref ExtendedProgress.h "#include " -/// given class are basically used to create Kodi's extended progress. -/// -/// -/// -------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// kodi::gui::dialogs::CExtendedProgress *ext_progress = new kodi::gui::dialogs::CExtendedProgress("Test Extended progress"); -/// ext_progress->SetText("Test progress"); -/// for (unsigned int i = 0; i < 50; i += 10) -/// { -/// ext_progress->SetProgress(i, 100); -/// sleep(1); -/// } -/// -/// ext_progress->SetTitle("Test Extended progress - Second round"); -/// ext_progress->SetText("Test progress - Step 2"); -/// -/// for (unsigned int i = 50; i < 100; i += 10) -/// { -/// ext_progress->SetProgress(i, 100); -/// sleep(1); -/// } -/// delete ext_progress; -/// ~~~~~~~~~~~~~ -/// -class ATTRIBUTE_HIDDEN CExtendedProgress -{ -public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CExtendedProgress - /// Construct a new dialog - /// - /// @param[in] title Title string - /// - explicit CExtendedProgress(const std::string& title = "") - { - using namespace ::kodi::addon; - m_DialogHandle = CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->new_dialog( - CAddonBase::m_interface->toKodi->kodiBase, title.c_str()); - if (!m_DialogHandle) - kodi::Log(ADDON_LOG_FATAL, - "kodi::gui::CDialogExtendedProgress can't create window class from Kodi !!!"); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CExtendedProgress - /// Destructor - /// - ~CExtendedProgress() - { - using namespace ::kodi::addon; - if (m_DialogHandle) - CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->delete_dialog( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CExtendedProgress - /// @brief Get the used title - /// - /// @return Title string - /// - std::string Title() const - { - using namespace ::kodi::addon; - std::string text; - char* strMsg = CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->get_title( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); - if (strMsg != nullptr) - { - if (std::strlen(strMsg)) - text = strMsg; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - strMsg); - } - return text; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CExtendedProgress - /// @brief To set the title of dialog - /// - /// @param[in] title Title string - /// - void SetTitle(const std::string& title) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->set_title( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, title.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CExtendedProgress - /// @brief Get the used text information string - /// - /// @return Text string - /// - std::string Text() const - { - using namespace ::kodi::addon; - std::string text; - char* strMsg = CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->get_text( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); - if (strMsg != nullptr) - { - if (std::strlen(strMsg)) - text = strMsg; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - strMsg); - } - return text; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CExtendedProgress - /// @brief To set the used text information string - /// - /// @param[in] text information text to set - /// - void SetText(const std::string& text) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->set_text( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, text.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CExtendedProgress - /// @brief To ask dialog is finished - /// - /// @return True if on end - /// - bool IsFinished() const - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->is_finished( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CExtendedProgress - /// @brief Mark progress finished - /// - void MarkFinished() - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->mark_finished( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CExtendedProgress - /// @brief Get the current progress position as percent - /// - /// @return Position - /// - float Percentage() const - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->get_percentage( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CExtendedProgress - /// @brief To set the current progress position as percent - /// - /// @param[in] percentage Position to use from 0.0 to 100.0 - /// - void SetPercentage(float percentage) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->set_percentage( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, percentage); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CExtendedProgress - /// @brief To set progress position with predefined places - /// - /// @param[in] currentItem Place position to use - /// @param[in] itemCount Amount of used places - /// - void SetProgress(int currentItem, int itemCount) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->set_progress( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, currentItem, itemCount); - } - //-------------------------------------------------------------------------- - -private: - void* m_DialogHandle; -}; - -} /* namespace dialogs */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/FileBrowser.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/FileBrowser.h deleted file mode 100644 index 90da063..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/FileBrowser.h +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../definitions.h" -#include "../../AddonBase.h" - -namespace kodi -{ -namespace gui -{ -namespace dialogs -{ - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_dialogs_FileBrowser Dialog File Browser - /// \ingroup cpp_kodi_gui - /// @brief \cpp_namespace{ kodi::gui::dialogs::FileBrowser } - /// **File browser dialog** - /// - /// The functions listed below of the class "FileBrowser" offer - /// the possibility to select to a file by the user of the add-on. - /// - /// It allows all the options that are possible in Kodi itself and offers all - /// support file types. - /// - /// It has the header \ref FileBrowser.h "#include " - /// be included to enjoy it. - /// - namespace FileBrowser - { - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_FileBrowser - /// @brief Directory selection dialog - /// - /// @param[in] shares With Shares becomes the available start folders - /// be set. - /// @param[in] heading Dialog header name - /// @param[in,out] path As in the path to start and return value about - /// selected directory - /// @param[in] writeOnly If set only writeable folders are shown. - /// @return False if selection becomes canceled. - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// /* - /// * Example show directory selection dialog with on 'share' (first value) - /// * defined directory types. - /// * - /// * If this becomes leaved empty and 'directory' is empty goes it to the - /// * base path of the hard disk. - /// * - /// * Also can be with path written to 'directory' before the dialog forced - /// * to a start place. - /// */ - /// std::string directory; - /// bool ret = kodi::gui::dialogs::FileBrowser::ShowAndGetDirectory("local|network|removable", - /// "Test directory selection", - /// directory, - /// false); - /// fprintf(stderr, "Selected directory is : %s and was %s\n", directory.c_str(), ret ? "OK" : "Canceled"); - /// ~~~~~~~~~~~~~ - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetDirectory(const std::string& shares, - const std::string& heading, - std::string& path, - bool writeOnly = false) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_directory( - CAddonBase::m_interface->toKodi->kodiBase, shares.c_str(), heading.c_str(), path.c_str(), - &retString, writeOnly); - if (retString != nullptr) - { - if (std::strlen(retString)) - path = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_FileBrowser - /// @brief File selection dialog - /// - /// @param[in] shares With Shares becomes the available start - /// folders be set. - /// @param[in] mask The mask to filter visible files, e.g. - /// ".m3u|.pls|.b4s|.wpl". - /// @param[in] heading Dialog header name - /// @param[in,out] path As in the path to start and Return value - /// about selected file - /// @param[in] useThumbs If set show thumbs if possible on dialog. - /// @param[in] useFileDirectories If set also packages (e.g. *.zip) are - /// handled as directories. - /// @return False if selection becomes canceled. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetFile(const std::string& shares, - const std::string& mask, - const std::string& heading, - std::string& path, - bool useThumbs = false, - bool useFileDirectories = false) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_file(CAddonBase::m_interface->toKodi->kodiBase, - shares.c_str(), mask.c_str(), heading.c_str(), path.c_str(), &retString, - useThumbs, useFileDirectories); - if (retString != nullptr) - { - if (std::strlen(retString)) - path = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_FileBrowser - /// @brief File selection from a directory - /// - /// @param[in] directory The directory name where the dialog - /// start, possible are normal names and - /// kodi's special names. - /// @param[in] mask The mask to filter visible files, e.g. - /// ".m3u|.pls|.b4s|.wpl". - /// @param[in] heading Dialog header name - /// @param[in,out] path As in the path to start and Return value - /// about selected file - /// @param[in] useThumbs If set show thumbs if possible on dialog. - /// @param[in] useFileDirectories If set also packages (e.g. *.zip) are - /// handled as directories. - /// @param[in] singleList - /// @return False if selection becomes canceled. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetFileFromDir(const std::string& directory, - const std::string& mask, - const std::string& heading, - std::string& path, - bool useThumbs = false, - bool useFileDirectories = false, - bool singleList = false) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_file_from_dir(CAddonBase::m_interface->toKodi->kodiBase, - directory.c_str(), mask.c_str(), heading.c_str(), - path.c_str(), &retString, useThumbs, - useFileDirectories, singleList); - if (retString != nullptr) - { - if (std::strlen(retString)) - path = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_FileBrowser - /// @brief File selection dialog to get several in to a list - /// - /// @param[in] shares With Shares becomes the available start - /// folders be set. - /// @param[in] mask The mask to filter visible files, e.g. - /// ".m3u|.pls|.b4s|.wpl". - /// @param[in] heading Dialog header name - /// @param[out] fileList Return value about selected files - /// @param[in] useThumbs If set show thumbs if possible on dialog. - /// @param[in] useFileDirectories If set also packages (e.g. *.zip) are - /// handled as directories. - /// @return False if selection becomes canceled. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetFileList(const std::string& shares, - const std::string& mask, - const std::string& heading, - std::vector& fileList, - bool useThumbs = false, - bool useFileDirectories = false) - { - using namespace ::kodi::addon; - char** list = nullptr; - unsigned int listSize = 0; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_file_list(CAddonBase::m_interface->toKodi->kodiBase, - shares.c_str(), mask.c_str(), heading.c_str(), &list, &listSize, - useThumbs, useFileDirectories); - if (ret) - { - for (unsigned int i = 0; i < listSize; ++i) - fileList.emplace_back(list[i]); - CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->clear_file_list(CAddonBase::m_interface->toKodi->kodiBase, &list, listSize); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_FileBrowser - /// @brief Source selection dialog - /// - /// @param[in,out] path As in the path to start and Return value - /// about selected source - /// @param[in] allowNetworkShares Allow also access to network - /// @param[in] additionalShare With additionalShare becomes the available - /// start folders be set (optional). - /// @param[in] type - /// @return False if selection becomes canceled. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetSource(std::string& path, - bool allowNetworkShares, - const std::string& additionalShare = "", - const std::string& type = "") - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_source(CAddonBase::m_interface->toKodi->kodiBase, path.c_str(), &retString, - allowNetworkShares, additionalShare.c_str(), type.c_str()); - if (retString != nullptr) - { - if (std::strlen(retString)) - path = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_FileBrowser - /// @brief Image selection dialog - /// - /// @param[in] shares With Shares becomes the available start folders be - /// set. - /// @param[in] heading Dialog header name - /// @param[out] path Return value about selected image - /// @return False if selection becomes canceled. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetImage(const std::string& shares, - const std::string& heading, - std::string& path) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_image(CAddonBase::m_interface->toKodi->kodiBase, - shares.c_str(), heading.c_str(), path.c_str(), &retString); - if (retString != nullptr) - { - if (std::strlen(retString)) - path = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_FileBrowser - /// @brief Image selection dialog to get several in to a list - /// - /// @param[in] shares With Shares becomes the available start folders - /// be set. - /// @param[in] heading Dialog header name - /// @param[out] file_list Return value about selected images - /// @return False if selection becomes canceled. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetImageList(const std::string& shares, - const std::string& heading, - std::vector& file_list) - { - using namespace ::kodi::addon; - char** list = nullptr; - unsigned int listSize = 0; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_image_list(CAddonBase::m_interface->toKodi->kodiBase, - shares.c_str(), heading.c_str(), &list, &listSize); - if (ret) - { - for (unsigned int i = 0; i < listSize; ++i) - file_list.emplace_back(list[i]); - CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->clear_file_list(CAddonBase::m_interface->toKodi->kodiBase, &list, listSize); - } - return ret; - } - //-------------------------------------------------------------------------- - }; - -} /* namespace dialogs */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Keyboard.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Keyboard.h deleted file mode 100644 index 843bdfa..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Keyboard.h +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../definitions.h" -#include "../../AddonBase.h" - -namespace kodi -{ -namespace gui -{ -namespace dialogs -{ - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_dialogs_Keyboard Dialog Keyboard - /// \ingroup cpp_kodi_gui - /// @brief \cpp_namespace{ kodi::gui::dialogs::Keyboard } - /// **Keyboard dialogs** - /// - /// The functions listed below have to be permitted by the user for the - /// representation of a keyboard around an input. - /// - /// The class supports several kinds, from an easy text choice up to the - /// passport Word production and their confirmation for add-on. - /// - /// It has the header \ref Keyboard.h "#include " - /// be included to enjoy it. - /// - namespace Keyboard - { - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Keyboard - /// @brief Show keyboard with initial value `text` and replace with result - /// string. - /// - /// @param[in,out] text Overwritten with user input if return=true. - /// @param[in] heading String shown on dialog title. - /// @param[in] allowEmptyResult Whether a blank password is valid or not. - /// @param[in] hiddenInput The inserted input is not shown as text. - /// @param[in] autoCloseMs To close the dialog after a specified - /// time, in milliseconds, default is 0 which - /// keeps the dialog open indefinitely. - /// @return true if successful display and user input. - /// false if unsuccessful display, no user - /// input, or canceled editing. - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// /* - /// * The example shows the display of keyboard call dialog at Kodi from the add-on. - /// * Below all values are set, however, can last two (hidden input = false and autoCloseMs = 0) - /// * to be released if not needed. - /// */ - /// std::string text = "Please change me to them want you want"; /*< It can be leaved empty or a - /// entry text added */ - /// bool bRet = ::kodi::gui::dialogs::Keyboard::ShowAndGetInput(text, - /// "Demonstration text entry", - /// true, - /// false, - /// 0); - /// fprintf(stderr, "Written keyboard input is : '%s' and was %s\n", - /// text.c_str(), bRet ? "OK" : "Canceled"); - /// ~~~~~~~~~~~~~ - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetInput(std::string& text, - const std::string& heading, - bool allowEmptyResult, - bool hiddenInput = false, - unsigned int autoCloseMs = 0) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = - CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_get_input_with_head( - CAddonBase::m_interface->toKodi->kodiBase, text.c_str(), &retString, heading.c_str(), - allowEmptyResult, hiddenInput, autoCloseMs); - if (retString != nullptr) - { - text = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, - retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Keyboard - /// @brief The example shows the display of keyboard call dialog at Kodi - /// from the add-on. - /// - /// @param[out] text Overwritten with user input if return=true. - /// @param[in] allowEmptyResult If set to true keyboard can also exited - /// without entered text. - /// @param[in] autoCloseMs To close the dialog after a specified time, - /// in milliseconds, default is 0 which keeps - /// the dialog open indefinitely. - /// @return true if successful display and user input. - /// false if unsuccessful display, no user - /// input, or canceled editing. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetInput(std::string& text, - bool allowEmptyResult, - unsigned int autoCloseMs = 0) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_get_input(CAddonBase::m_interface->toKodi->kodiBase, - text.c_str(), &retString, - allowEmptyResult, autoCloseMs); - if (retString != nullptr) - { - text = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Keyboard - /// @brief Shows keyboard and prompts for a password. Differs from - /// `ShowAndVerifyNewPassword()` in that no second verification - /// - /// @param[in,out] newPassword Overwritten with user input if return=true. - /// @param[in] heading String shown on dialog title. - /// @param[in] allowEmptyResult Whether a blank password is valid or not. - /// @param[in] autoCloseMs To close the dialog after a specified time, - /// in milliseconds, default is 0 which keeps - /// the dialog open indefinitely. - /// @return true if successful display and user input. - /// false if unsuccessful display, no user - /// input, or canceled editing. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetNewPassword(std::string& newPassword, - const std::string& heading, - bool allowEmptyResult, - unsigned int autoCloseMs = 0) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_get_new_password_with_head(CAddonBase::m_interface->toKodi->kodiBase, - newPassword.c_str(), &retString, heading.c_str(), - allowEmptyResult, autoCloseMs); - if (retString != nullptr) - { - newPassword = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Keyboard - /// @brief Shows keyboard and prompts for a password. Differs from - /// `ShowAndVerifyNewPassword()` in that no second verification - /// - /// @param[in,out] newPassword Overwritten with user input if return=true. - /// @param[in] autoCloseMs To close the dialog after a specified time, - /// in milliseconds, default is 0 which keeps - /// the dialog open indefinitely. - /// @return true if successful display and user input. - /// false if unsuccessful display, no user - /// input, or canceled editing. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetNewPassword(std::string& newPassword, - unsigned int autoCloseMs = 0) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_get_new_password(CAddonBase::m_interface->toKodi->kodiBase, - newPassword.c_str(), &retString, autoCloseMs); - if (retString != nullptr) - { - newPassword = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Keyboard - /// @brief Show keyboard twice to get and confirm a user-entered password - /// string. - /// - /// @param[out] newPassword Overwritten with user input if return=true. - /// @param[in] heading String shown on dialog title. - /// @param[in] allowEmptyResult - /// @param[in] autoCloseMs To close the dialog after a specified time, - /// in milliseconds, default is 0 which keeps - /// the dialog open indefinitely. - /// @return true if successful display and user input. - /// false if unsuccessful display, no user - /// input, or canceled editing. - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// #include - /// - /// /* - /// * The example below shows the complete use of keyboard dialog for password - /// * check. If only one check from add-on needed can be function with retries - /// * set to '0' called alone. - /// * - /// * The use of MD5 translated password is always required for the check on Kodi! - /// */ - /// - /// int maxretries = 3; - /// /* - /// * Password names need to be send as md5 sum to kodi. - /// */ - /// std::string password; - /// kodi::GetMD5("kodi", password); - /// - /// /* - /// * To the loop about password checks. - /// */ - /// int ret; - /// for (unsigned int i = 0; i < maxretries; i++) - /// { - /// /* - /// * Ask the user about the password. - /// */ - /// ret = ::kodi::gui::dialogs::Keyboard::ShowAndVerifyPassword(password, "Demo password call for PW 'kodi'", i, 0); - /// if (ret == 0) - /// { - /// fprintf(stderr, "Password successfull confirmed after '%i' tries\n", i+1); - /// break; - /// } - /// else if (ret < 0) - /// { - /// fprintf(stderr, "Canceled editing on try '%i'\n", i+1); - /// break; - /// } - /// else /* if (ret > 0) */ - /// { - /// fprintf(stderr, "Wrong password entered on try '%i'\n", i+1); - /// } - /// } - /// ~~~~~~~~~~~~~ - /// - inline bool ATTRIBUTE_HIDDEN ShowAndVerifyNewPassword(std::string& newPassword, - const std::string& heading, - bool allowEmptyResult, - unsigned int autoCloseMs = 0) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_verify_new_password_with_head(CAddonBase::m_interface->toKodi->kodiBase, - &retString, heading.c_str(), allowEmptyResult, - autoCloseMs); - if (retString != nullptr) - { - newPassword = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Keyboard - /// @brief Show keyboard twice to get and confirm a user-entered password - /// string. - /// - /// @param[out] newPassword Overwritten with user input if return=true. - /// @param[in] autoCloseMs To close the dialog after a specified time, - /// in milliseconds, default is 0 which keeps - /// the dialog open indefinitely. - /// @return true if successful display and user input. - /// false if unsuccessful display, no user - /// input, or canceled editing. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndVerifyNewPassword(std::string& newPassword, - unsigned int autoCloseMs = 0) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_verify_new_password(CAddonBase::m_interface->toKodi->kodiBase, - &retString, autoCloseMs); - if (retString != nullptr) - { - newPassword = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Keyboard - /// @brief Show keyboard and verify user input against `password`. - /// - /// @param[in,out] password Value to compare against user input. - /// @param[in] heading String shown on dialog title. - /// @param[in] retries If greater than 0, shows "Incorrect - /// password, %d retries left" on dialog line 2, - /// else line 2 is blank. - /// @param[in] autoCloseMs To close the dialog after a specified time, - /// in milliseconds, default is 0 which keeps - /// the dialog open indefinitely. - /// @return 0 if successful display and user input. 1 if - /// unsuccessful input. -1 if no user input or - /// canceled editing. - /// - inline int ATTRIBUTE_HIDDEN ShowAndVerifyPassword(std::string& password, - const std::string& heading, - int retries, - unsigned int autoCloseMs = 0) - { - using namespace ::kodi::addon; - char* retString = nullptr; - int ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_verify_password(CAddonBase::m_interface->toKodi->kodiBase, - password.c_str(), &retString, heading.c_str(), - retries, autoCloseMs); - if (retString != nullptr) - { - password = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Keyboard - /// @brief Shows a filter related keyboard - /// - /// @param[in,out] text Overwritten with user input if return=true. - /// @param[in] searching Use dialog for search and send our search - /// message in safe way (only the active window - /// needs it) - /// - header name if true is "Enter search string" - /// - header name if false is "Enter value" - /// @param autoCloseMs To close the dialog after a specified time, - /// in milliseconds, default is 0 which keeps - /// the dialog open indefinitely. - /// @return true if successful display and user input. - /// false if unsuccessful display, no user - /// input, or canceled editing. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetFilter(std::string& text, - bool searching, - unsigned int autoCloseMs = 0) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_get_filter(CAddonBase::m_interface->toKodi->kodiBase, - text.c_str(), &retString, searching, autoCloseMs); - if (retString != nullptr) - { - text = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Keyboard - /// @brief Send a text to a visible keyboard - /// - /// @param[in] text Overwritten with user input if return=true. - /// @param[in] closeKeyboard The open dialog is if also closed on 'true'. - /// @return true if successful done, false if - /// unsuccessful or keyboard not present. - /// - inline bool ATTRIBUTE_HIDDEN SendTextToActiveKeyboard(const std::string& text, - bool closeKeyboard = false) - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->send_text_to_active_keyboard(CAddonBase::m_interface->toKodi->kodiBase, - text.c_str(), closeKeyboard); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Keyboard - /// @brief Check for visible keyboard on GUI - /// - /// @return true if keyboard present, false if not present - /// - inline bool ATTRIBUTE_HIDDEN IsKeyboardActivated() - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->is_keyboard_activated(CAddonBase::m_interface->toKodi->kodiBase); - } - //-------------------------------------------------------------------------- - }; - -} /* namespace dialogs */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Numeric.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Numeric.h deleted file mode 100644 index bff7683..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Numeric.h +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../definitions.h" -#include "../../AddonBase.h" - -namespace kodi -{ -namespace gui -{ -namespace dialogs -{ - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_dialogs_Numeric Dialog Numeric - /// \ingroup cpp_kodi_gui - /// @{ - /// @brief \cpp_namespace{ kodi::gui::dialogs::Numeric } - /// **Numeric dialogs** - /// - /// The functions listed below have to be permitted by the user for the - /// representation of a numeric keyboard around an input. - /// - /// The class supports several kinds, from an easy number choice up to the - /// passport Word production and their confirmation for add-on. - /// - /// It has the header \ref Numeric.h "#include " - /// be included to enjoy it. - /// - namespace Numeric - { - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Numeric - /// @brief Use dialog to get numeric new password - /// - /// @param[out] newPassword String to preload into the keyboard - /// accumulator. Overwritten with user input - /// if return=true. Returned in MD5 format. - /// @return true if successful display and user - /// input entry/re-entry. - /// false if unsuccessful display, no user - /// input, or canceled editing. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndVerifyNewPassword(std::string& newPassword) - { - using namespace ::kodi::addon; - char* pw = nullptr; - bool ret = - CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_verify_new_password( - CAddonBase::m_interface->toKodi->kodiBase, &pw); - if (pw != nullptr) - { - newPassword = pw; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, pw); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Numeric - /// @brief Use dialog to verify numeric password. - /// - /// @param[in] password Password to compare with user input, need - /// in MD5 format. - /// @param[in] heading Heading to display - /// @param[in] retries If greater than 0, shows "Incorrect - /// password, %d retries left" on dialog - /// line 2, else line 2 is blank. - /// @return Possible values: - /// - 0 if successful display and user input. - /// - 1 if unsuccessful input. - /// - -1 if no user input or canceled editing. - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include /* fprintf */ - /// #include - /// #include - /// - /// /* - /// * The example below shows the complete use of keyboard dialog for password - /// * check. If only one check from add-on needed can be function with retries - /// * set to '0' called alone. - /// * - /// * The use of MD5 translated password is always required for the check on Kodi! - /// */ - /// - /// int maxretries = 3; - /// - /// /* - /// * Password names need to be send as md5 sum to kodi. - /// */ - /// std::string password = kodi::GetMD5("1234"); - /// - /// /* - /// * To the loop about password checks. - /// */ - /// int ret; - /// for (unsigned int i = 0; i < maxretries; i++) - /// { - /// /* - /// * Ask the user about the password. - /// */ - /// ret = kodi::gui::dialogs::Numeric::ShowAndVerifyPassword(password, "Demo numeric password call for PW '1234'", i); - /// if (ret == 0) - /// { - /// fprintf(stderr, "Numeric password successfull confirmed after '%i' tries\n", i+1); - /// break; - /// } - /// else if (ret < 0) - /// { - /// fprintf(stderr, "Canceled editing on try '%i'\n", i+1); - /// break; - /// } - /// else /* if (ret > 0) */ - /// { - /// fprintf(stderr, "Wrong numeric password entered on try '%i'\n", i+1); - /// } - /// } - /// ~~~~~~~~~~~~~ - /// - inline int ATTRIBUTE_HIDDEN ShowAndVerifyPassword(const std::string& password, - const std::string& heading, - int retries) - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_verify_password(CAddonBase::m_interface->toKodi->kodiBase, - password.c_str(), heading.c_str(), retries); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Numeric - /// @brief Use dialog to verify numeric password - /// - /// @param[in,out] toVerify Value to compare against user input. - /// @param[in] heading Heading to display - /// @param[in] verifyInput If set as true we verify the users input - /// versus toVerify. - /// @return true if successful display and user - /// input. false if unsuccessful display, no - /// user input, or canceled editing. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndVerifyInput(std::string& toVerify, - const std::string& heading, - bool verifyInput) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_verify_input(CAddonBase::m_interface->toKodi->kodiBase, - toVerify.c_str(), &retString, heading.c_str(), verifyInput); - if (retString != nullptr) - { - toVerify = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Numeric - /// @brief Use dialog to get time value. - /// - /// @param[out] time Overwritten with user input if - /// return=true and time inserted. - /// @param[in] heading Heading to display. - /// @return true if successful display and user - /// input. false if unsuccessful display, no - /// user input, or canceled editing. - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include /* printf */ - /// #include /* time_t, struct tm, time, localtime, strftime */ - /// #include - /// - /// time_t rawtime; - /// struct tm * timeinfo; - /// char buffer [10]; - /// - /// time (&rawtime); - /// timeinfo = localtime(&rawtime); - /// bool bRet = kodi::gui::dialogs::Numeric::ShowAndGetTime(*timeinfo, "Selected time test call"); - /// strftime(buffer, sizeof(buffer), "%H:%M.", timeinfo); - /// printf("Selected time it's %s and was on Dialog %s\n", buffer, bRet ? "OK" : "Canceled"); - /// ~~~~~~~~~~~~~ - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetTime(tm& time, const std::string& heading) - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_get_time(CAddonBase::m_interface->toKodi->kodiBase, &time, heading.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Numeric - /// @brief Use dialog to get date value. - /// - /// @param[in,out] date Overwritten with user input if - /// return=true and date inserted. - /// @param[in] heading Heading to display - /// @return true if successful display and user - /// input. false if unsuccessful display, no - /// user input, or canceled editing. - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include /* printf */ - /// #include /* time_t, struct tm, time, localtime, strftime */ - /// #include - /// - /// time_t rawtime; - /// struct tm * timeinfo; - /// char buffer [20]; - /// - /// time (&rawtime); - /// timeinfo = localtime(&rawtime); - /// bool bRet = kodi::gui::dialogs::Numeric::ShowAndGetDate(*timeinfo, "Selected date test call"); - /// strftime(buffer, sizeof(buffer), "%Y-%m-%d", timeinfo); - /// printf("Selected date it's %s and was on Dialog %s\n", buffer, bRet ? "OK" : "Canceled"); - /// ~~~~~~~~~~~~~ - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetDate(tm& date, const std::string& heading) - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_get_date(CAddonBase::m_interface->toKodi->kodiBase, &date, heading.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Numeric - /// @brief Use dialog to get a IP - /// - /// @param[in,out] ipAddress Overwritten with user input if - /// return=true and IP address inserted. - /// @param[in] heading Heading to display. - /// @return true if successful display and - /// user input. false if unsuccessful - /// display, no user input, or canceled - /// editing. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetIPAddress(std::string& ipAddress, - const std::string& heading) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_get_ip_address(CAddonBase::m_interface->toKodi->kodiBase, - ipAddress.c_str(), &retString, heading.c_str()); - if (retString != nullptr) - { - ipAddress = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Numeric - /// @brief Use dialog to get normal number. - /// - /// @param[in,out] input Overwritten with user input if - /// return=true and time in seconds inserted - /// @param[in] heading Heading to display - /// @param[in] autoCloseTimeoutMs To close the dialog after a specified - /// time, in milliseconds, default is 0 - /// which keeps the dialog open - /// indefinitely. - /// @return true if successful display and user - /// input. false if unsuccessful display, no - /// user input, or canceled editing. - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include /* printf */ - /// #include /* strtoull (C++11) */ - /// #include - /// - /// std::string number; - /// bool bRet = kodi::gui::dialogs::Numeric::ShowAndGetNumber(number, "Number test call"); - /// printf("Written number input is : %llu and was %s\n", - /// strtoull(number.c_str(), nullptr, 0), bRet ? "OK" : "Canceled"); - /// ~~~~~~~~~~~~~ - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetNumber(std::string& input, - const std::string& heading, - unsigned int autoCloseTimeoutMs = 0) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_get_number(CAddonBase::m_interface->toKodi->kodiBase, - input.c_str(), &retString, heading.c_str(), autoCloseTimeoutMs); - if (retString != nullptr) - { - input = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Numeric - /// @brief Show numeric keypad to get seconds. - /// - /// @param[in,out] time Overwritten with user input if return=true and - /// time in seconds inserted. - /// @param[in] heading Heading to display - /// @return true if successful display and user input. false - /// if unsuccessful display, no user input, or - /// canceled editing. - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetSeconds(std::string& time, const std::string& heading) - { - using namespace ::kodi::addon; - char* retString = nullptr; - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_get_seconds(CAddonBase::m_interface->toKodi->kodiBase, - time.c_str(), &retString, heading.c_str()); - if (retString != nullptr) - { - time = retString; - CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, retString); - } - return ret; - } - //-------------------------------------------------------------------------- - }; - /// @} - -} /* namespace dialogs */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/OK.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/OK.h deleted file mode 100644 index b9a3a0d..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/OK.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" -#include "../definitions.h" - -namespace kodi -{ -namespace gui -{ -namespace dialogs -{ - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_dialogs_OK Dialog OK - /// \ingroup cpp_kodi_gui - /// @{ - /// @brief \cpp_namespace{ kodi::gui::dialogs::OK } - /// **OK dialog** - /// - /// The functions listed below permit the call of a dialogue of information, a - /// confirmation of the user by press from OK required. - /// - /// It has the header \ref OK.h "#include " - /// be included to enjoy it. - /// - namespace OK - { - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_OK - /// @brief Use dialog to inform user with text and confirmation with OK with continued string. - /// - /// @param[in] heading Dialog heading. - /// @param[in] text Multi-line text. - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// ... - /// kodi::gui::dialogs::OK::ShowAndGetInput("Test dialog", "Hello World!\nI'm a call from add-on\n :) :D"); - /// ~~~~~~~~~~~~~ - /// - inline void ATTRIBUTE_HIDDEN ShowAndGetInput(const std::string& heading, const std::string& text) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogOK->show_and_get_input_single_text( - CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), text.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_OK - /// @brief Use dialog to inform user with text and confirmation with OK with strings separated to the lines. - /// - /// @param[in] heading Dialog heading. - /// @param[in] line0 Line #1 text. - /// @param[in] line1 Line #2 text. - /// @param[in] line2 Line #3 text. - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// ... - /// kodi::gui::dialogs::OK::ShowAndGetInput("Test dialog", "Hello World!", "I'm a call from add-on", " :) :D"); - /// ~~~~~~~~~~~~~ - /// - inline void ATTRIBUTE_HIDDEN ShowAndGetInput(const std::string& heading, - const std::string& line0, - const std::string& line1, - const std::string& line2) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogOK->show_and_get_input_line_text(CAddonBase::m_interface->toKodi->kodiBase, - heading.c_str(), line0.c_str(), line1.c_str(), - line2.c_str()); - } - //-------------------------------------------------------------------------- - } - /// @} - -} /* namespace dialogs */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Progress.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Progress.h deleted file mode 100644 index b1f8cc5..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Progress.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../definitions.h" -#include "../../AddonBase.h" - -namespace kodi -{ -namespace gui -{ -namespace dialogs -{ - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_dialogs_CProgress Dialog Progress -/// \ingroup cpp_kodi_gui -/// @brief \cpp_class{ kodi::gui::dialogs::CProgress } -/// **Progress dialog shown in center** -/// -/// The with \ref DialogProgress.h "#include " -/// given class are basically used to create Kodi's progress dialog with named -/// text fields. -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// #include -/// -/// kodi::gui::dialogs::CProgress *progress = new kodi::gui::dialogs::CProgress; -/// progress->SetHeading("Test progress"); -/// progress->SetLine(1, "line 1"); -/// progress->SetLine(2, "line 2"); -/// progress->SetLine(3, "line 3"); -/// progress->SetCanCancel(true); -/// progress->ShowProgressBar(true); -/// progress->Open(); -/// for (unsigned int i = 0; i < 100; i += 10) -/// { -/// progress->SetPercentage(i); -/// sleep(1); -/// } -/// delete progress; -/// ~~~~~~~~~~~~~ -/// -class ATTRIBUTE_HIDDEN CProgress -{ -public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CProgress - /// @brief Construct a new dialog - /// - CProgress() - { - using namespace ::kodi::addon; - m_DialogHandle = CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->new_dialog( - CAddonBase::m_interface->toKodi->kodiBase); - if (!m_DialogHandle) - kodi::Log(ADDON_LOG_FATAL, - "kodi::gui::dialogs::CProgress can't create window class from Kodi !!!"); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CProgress - /// @brief Destructor - /// - ~CProgress() - { - using namespace ::kodi::addon; - if (m_DialogHandle) - CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->delete_dialog( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CProgress - /// @brief To open the dialog - /// - void Open() - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->open( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CProgress - /// @brief Set the heading title of dialog - /// - /// @param[in] heading Title string to use - /// - void SetHeading(const std::string& heading) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->set_heading( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, heading.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CProgress - /// @brief To set the line text field on dialog from 0 - 2 - /// - /// @param[in] iLine Line number - /// @param[in] line Text string - /// - void SetLine(unsigned int iLine, const std::string& line) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->set_line( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, iLine, line.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CProgress - /// @brief To enable and show cancel button on dialog - /// - /// @param[in] canCancel if true becomes it shown - /// - void SetCanCancel(bool canCancel) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->set_can_cancel( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, canCancel); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CProgress - /// @brief To check dialog for clicked cancel button - /// - /// @return True if canceled - /// - bool IsCanceled() const - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->is_canceled( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CProgress - /// @brief Get the current progress position as percent - /// - /// @param[in] percentage Position to use from 0 to 100 - /// - void SetPercentage(int percentage) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->set_percentage( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, percentage); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CProgress - /// @brief To set the current progress position as percent - /// - /// @return Current Position used from 0 to 100 - /// - int GetPercentage() const - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->get_percentage( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CProgress - /// @brief To show or hide progress bar dialog - /// - /// @param[in] onOff If true becomes it shown - /// - void ShowProgressBar(bool onOff) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->show_progress_bar( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, onOff); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CProgress - /// @brief Set the maximum position of progress, needed if `SetProgressAdvance(...)` is used - /// - /// @param[in] max Biggest usable position to use - /// - void SetProgressMax(int max) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->set_progress_max( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, max); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CProgress - /// @brief To increase progress bar by defined step size until reach of maximum position - /// - /// @param[in] steps Step size to increase, default is 1 - /// - void SetProgressAdvance(int steps = 1) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->set_progress_advance( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, steps); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_CProgress - /// @brief To check progress was canceled on work - /// - /// @return True if aborted - /// - bool Abort() - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->abort( - CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); - } - //-------------------------------------------------------------------------- - -private: - void* m_DialogHandle; -}; - -} /* namespace dialogs */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Select.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Select.h deleted file mode 100644 index 39a98fe..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/Select.h +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../definitions.h" -#include "../../AddonBase.h" - -//============================================================================== -/// \defgroup cpp_kodi_vfs_Defs Definitions, structures and enumerators -/// \ingroup cpp_kodi_gui_dialogs_Select -/// @brief **Dialog Select definition values** -//------------------------------------------------------------------------------ - -//============================================================================== -/// \ingroup cpp_kodi_vfs_Defs -/// @brief **Selection entry structure** -/// -typedef struct SSelectionEntry -{ - //============================================================================ - /// Structure constructor - /// - /// There becomes selected always set to false. - /// - SSelectionEntry() = default; - //---------------------------------------------------------------------------- - - /// Entry identfication string - std::string id; - - /// Entry name to show on GUI dialog - std::string name; - - /// Place where entry can be preselected and after return the from user - /// selected is set. - bool selected = false; -} SSelectionEntry; -//------------------------------------------------------------------------------ - -namespace kodi -{ -namespace gui -{ -namespace dialogs -{ - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_dialogs_Select Dialog Select - /// \ingroup cpp_kodi_gui - /// @{ - /// @brief \cpp_namespace{ kodi::gui::dialogs::Select } - /// **Selection dialog** - /// - /// The function listed below permits the call of a dialogue to select of an - /// entry as a key - /// - /// It has the header \ref Select.h "#include " - /// be included to enjoy it. - /// - /// - namespace Select - { - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Select - /// @brief Show a selection dialog about given parts. - /// - /// @param[in] heading Dialog heading name - /// @param[in] entries String list about entries - /// @param[in] selected [opt] Predefined selection (default is - /// -1 for the first) - /// @param[in] autoclose [opt] To close dialog automatic after the given - /// time in ms. As '0' it stays open. - /// @return The selected entry, if return -1 was - /// nothing selected or canceled - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// const std::vector entries - /// { - /// "Test 1", - /// "Test 2", - /// "Test 3", - /// "Test 4", - /// "Test 5" - /// }; - /// - /// int selected = kodi::gui::dialogs::Select::Show("Test selection", entries, -1); - /// if (selected < 0) - /// fprintf(stderr, "Item selection canceled\n"); - /// else - /// fprintf(stderr, "Selected item is: %i\n", selected); - /// ~~~~~~~~~~~~~ - /// - inline int ATTRIBUTE_HIDDEN Show(const std::string& heading, - const std::vector& entries, - int selected = -1, - unsigned int autoclose = 0) - { - using namespace ::kodi::addon; - unsigned int size = static_cast(entries.size()); - const char** cEntries = (const char**)malloc(size * sizeof(const char**)); - for (unsigned int i = 0; i < size; ++i) - { - cEntries[i] = entries[i].c_str(); - } - int ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogSelect->open( - CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), cEntries, size, selected, - autoclose); - free(cEntries); - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Select - /// @brief Show a selection dialog about given parts. - /// - /// This function is mostly equal to the other, only becomes the string list - /// here done by a SSelectionEntry, where a ID string can be defined. - /// - /// @param[in] heading Dialog heading name - /// @param[in] entries SSelectionEntry list about entries - /// @param[in] selected [opt] Predefined selection (default is - /// -1 for the first) - /// @param[in] autoclose [opt] To close dialog automatic after the given - /// time in ms. As '0' it stays open. - /// @return The selected entry, if return -1 was - /// nothing selected or canceled - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// std::vector entries - /// { - /// { "ID 1", "Test 1", false }, - /// { "ID 2", "Test 2", false }, - /// { "ID 3", "Test 3", false }, - /// { "ID 4", "Test 4", false }, - /// { "ID 5", "Test 5", false } - /// }; - /// - /// int selected = kodi::gui::dialogs::Select::Show("Test selection", entries, -1); - /// if (selected < 0) - /// fprintf(stderr, "Item selection canceled\n"); - /// else - /// fprintf(stderr, "Selected item is: %i\n", selected); - /// ~~~~~~~~~~~~~ - /// - inline int ATTRIBUTE_HIDDEN Show(const std::string& heading, - std::vector& entries, - int selected = -1, - unsigned int autoclose = 0) - { - using namespace ::kodi::addon; - unsigned int size = static_cast(entries.size()); - const char** cEntries = static_cast(malloc(size*sizeof(const char*))); - for (unsigned int i = 0; i < size; ++i) - { - cEntries[i] = entries[i].name.c_str(); - if (selected == -1 && entries[i].selected) - selected = i; - } - int ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogSelect->open(CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), - cEntries, size, selected, autoclose); - if (ret >= 0) - { - entries[ret].selected = true; - } - free(cEntries); - return ret; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_Select - /// @brief Show a multiple selection dialog about given parts. - /// - /// @param[in] heading Dialog heading name - /// @param[in] entries SSelectionEntry list about entries - /// @param[in] autoclose [opt] To close dialog automatic after the given - /// time in ms. As '0' it stays open. - /// @return The selected entries, if return empty was - /// nothing selected or canceled - /// - /// With selected on SSelectionEntry can be a pre selection defined. - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// std::vector entries - /// { - /// { "ID 1", "Test 1", false }, - /// { "ID 2", "Test 2", false }, - /// { "ID 3", "Test 3", false }, - /// { "ID 4", "Test 4", false }, - /// { "ID 5", "Test 5", false } - /// }; - /// - /// bool ret = kodi::gui::dialogs::Select::ShowMultiSelect("Test selection", entries); - /// if (!ret) - /// fprintf(stderr, "Selection canceled\n"); - /// else - /// { - /// fprintf(stderr, "Selected items:\n"); - /// for (const auto& entry : entries) - /// { - /// if (entry.selected) - /// fprintf(stderr, " - %s\n", entry.selected.id.c_str()); - /// } - /// } - /// ~~~~~~~~~~~~~ - /// - inline bool ATTRIBUTE_HIDDEN ShowMultiSelect(const std::string& heading, - std::vector& entries, - int autoclose = 0) - { - using namespace ::kodi::addon; - unsigned int size = static_cast(entries.size()); - const char** cEntryIDs = static_cast(malloc(size*sizeof(const char*))); - const char** cEntryNames = static_cast(malloc(size*sizeof(const char*))); - bool* cEntriesSelected = static_cast(malloc(size*sizeof(bool))); - for (unsigned int i = 0; i < size; ++i) - { - cEntryIDs[i] = entries[i].id.c_str(); - cEntryNames[i] = entries[i].name.c_str(); - cEntriesSelected[i] = entries[i].selected; - } - bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogSelect->open_multi_select(CAddonBase::m_interface->toKodi->kodiBase, - heading.c_str(), cEntryIDs, cEntryNames, - cEntriesSelected, size, autoclose); - if (ret) - { - for (unsigned int i = 0; i < size; ++i) - entries[i].selected = cEntriesSelected[i]; - } - free(cEntryNames); - free(cEntryIDs); - free(cEntriesSelected); - return ret; - } - //-------------------------------------------------------------------------- - }; - /// @} - -} /* namespace dialogs */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/TextViewer.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/TextViewer.h deleted file mode 100644 index 5c81837..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/TextViewer.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2015-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../definitions.h" -#include "../../AddonBase.h" - -namespace kodi -{ -namespace gui -{ -namespace dialogs -{ - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_dialogs_TextViewer Dialog Text Viewer - /// \ingroup cpp_kodi_gui - /// @{ - /// @brief \cpp_namespace{ kodi::gui::dialogs::TextViewer } - /// **Text viewer dialog** - /// - /// The text viewer dialog can be used to display descriptions, help texts or - /// other larger texts. - /// - /// In order to achieve a line break is a \\n directly in the text or - /// in the "./resources/language/resource.language.??_??/strings.po" - /// to call with std::string kodi::general::GetLocalizedString(...);. - /// - /// It has the header \ref TextViewer.h "#include " - /// be included to enjoy it. - /// - namespace TextViewer - { - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_TextViewer - /// @brief Show info text dialog - /// - /// @param[in] heading Small heading text - /// @param[in] text Showed text on dialog - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// kodi::gui::dialogs::TextViewer::Show("The Wizard of Oz (1939 film)", - /// "The Wizard of Oz is a 1939 American musical comedy-drama fantasy film " - /// "produced by Metro-Goldwyn-Mayer, and the most well-known and commercially " - /// "successful adaptation based on the 1900 novel The Wonderful Wizard of Oz " - /// "by L. Frank Baum. The film stars Judy Garland as Dorothy Gale. The film" - /// "co-stars Terry the dog, billed as Toto; Ray Bolger, Jack Haley, Bert Lahr, " - /// "Frank Morgan, Billie Burke, Margaret Hamilton, with Charley Grapewin and " - /// "Clara Blandick, and the Singer Midgets as the Munchkins.\n" - /// "\n" - /// "Notable for its use of Technicolor, fantasy storytelling, musical score and " - /// "unusual characters, over the years it has become an icon of American popular " - /// "culture. It was nominated for six Academy Awards, including Best Picture but " - /// "lost to Gone with the Wind. It did win in two other categories including Best " - /// "Original Song for \"Over the Rainbow\". However, the film was a box office " - /// "disappointment on its initial release, earning only $3,017,000 on a $2,777,000 " - /// "budget, despite receiving largely positive reviews. It was MGM's most " - /// "expensive production at that time, and did not completely recoup the studio's " - /// "investment and turn a profit until theatrical re-releases starting in 1949.\n" - /// "\n" - /// "The 1956 broadcast television premiere of the film on CBS re-introduced the " - /// "film to the wider public and eventually made the presentation an annual " - /// "tradition, making it one of the most known films in cinema history. The " - /// "film was named the most-viewed motion picture on television syndication by " - /// "the Library of Congress who also included the film in its National Film " - /// "Registry in its inaugural year in 1989. Designation on the registry calls " - /// "for efforts to preserve it for being \"culturally, historically, and " - /// "aesthetically significant\". It is also one of the few films on UNESCO's " - /// "Memory of the World Register.\n" - /// "\n" - /// "The Wizard of Oz is often ranked on best-movie lists in critics' and public " - /// "polls. It is the source of many quotes referenced in modern popular culture. " - /// "It was directed primarily by Victor Fleming (who left production to take " - /// "over direction on the troubled Gone with the Wind production). Noel Langley, " - /// "Florence Ryerson and Edgar Allan Woolf received credit for the screenplay, " - /// "but there were uncredited contributions by others. The songs were written " - /// "by Edgar \"Yip\" Harburg (lyrics) and Harold Arlen (music). The incidental " - /// "music, based largely on the songs, was composed by Herbert Stothart, with " - /// "interspersed renderings from classical composers.\n"); - /// ~~~~~~~~~~~~~ - /// - inline void ATTRIBUTE_HIDDEN Show(const std::string& heading, const std::string& text) - { - using namespace ::kodi::addon; - CAddonBase::m_interface->toKodi->kodi_gui->dialogTextViewer->open( - CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), text.c_str()); - } - //-------------------------------------------------------------------------- - }; - /// @} - -} /* namespace dialogs */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/YesNo.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/YesNo.h deleted file mode 100644 index 67c2fc4..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/dialogs/YesNo.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../definitions.h" -#include "../../AddonBase.h" - -namespace kodi -{ -namespace gui -{ -namespace dialogs -{ - - //============================================================================ - /// - /// \defgroup cpp_kodi_gui_dialogs_YesNo Dialog Yes/No - /// \ingroup cpp_kodi_gui - /// @{ - /// @brief \cpp_namespace{ kodi::gui::dialogs::YesNo } - /// **Yes / No dialog** - /// - /// The Yes / No dialog can be used to inform the user about questions and get - /// the answer. - /// - /// In order to achieve a line break is a \\n directly in the text or - /// in the "./resources/language/resource.language.??_??/strings.po" - /// to call with std::string kodi::general::GetLocalizedString(...);. - /// - /// It has the header \ref YesNo.h "#include " - /// be included to enjoy it. - /// - /// - namespace YesNo - { - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_YesNo - /// @brief Use dialog to get numeric new password with one text string shown - /// everywhere and cancel return field - /// - /// @param[in] heading Dialog heading - /// @param[in] text Multi-line text - /// @param[out] canceled Return value about cancel button - /// @param[in] noLabel [opt] label to put on the no button - /// @param[in] yesLabel [opt] label to put on the yes button - /// @return Returns True if 'Yes' was pressed, else False - /// - /// @note It is preferred to only use this as it is actually a multi-line text. - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// bool canceled; - /// bool ret = kodi::gui::dialogs::YesNo::ShowAndGetInput( - /// "Yes / No test call", /* The Header */ - /// "You has opened Yes / No dialog for test\n\nIs this OK for you?", - /// canceled, /* return value about cancel button */ - /// "Not really", /* No label, is optional and if empty "No" */ - /// "Ohhh yes"); /* Yes label, also optional and if empty "Yes" */ - /// fprintf(stderr, "You has called Yes/No, returned '%s' and was %s\n", - /// ret ? "yes" : "no", - /// canceled ? "canceled" : "not canceled"); - /// ~~~~~~~~~~~~~ - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetInput(const std::string& heading, - const std::string& text, - bool& canceled, - const std::string& noLabel = "", - const std::string& yesLabel = "") - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->dialogYesNo->show_and_get_input_single_text( - CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), text.c_str(), &canceled, - noLabel.c_str(), yesLabel.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_YesNo - /// @brief Use dialog to get numeric new password with separated line strings - /// - /// @param[in] heading Dialog heading - /// @param[in] line0 Line #0 text - /// @param[in] line1 Line #1 text - /// @param[in] line2 Line #2 text - /// @param[in] noLabel [opt] label to put on the no button. - /// @param[in] yesLabel [opt] label to put on the yes button. - /// @return Returns True if 'Yes' was pressed, else False. - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// bool ret = kodi::gui::dialogs::YesNo::ShowAndGetInput( - /// "Yes / No test call", // The Header - /// "You has opened Yes / No dialog for test", - /// "", - /// "Is this OK for you?", - /// "Not really", // No label, is optional and if empty "No" - /// "Ohhh yes"); // Yes label, also optional and if empty "Yes" - /// fprintf(stderr, "You has called Yes/No, returned '%s'\n", - /// ret ? "yes" : "no"); - /// ~~~~~~~~~~~~~ - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetInput(const std::string& heading, - const std::string& line0, - const std::string& line1, - const std::string& line2, - const std::string& noLabel = "", - const std::string& yesLabel = "") - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->dialogYesNo->show_and_get_input_line_text(CAddonBase::m_interface->toKodi->kodiBase, - heading.c_str(), line0.c_str(), line1.c_str(), line2.c_str(), - noLabel.c_str(), yesLabel.c_str()); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_dialogs_YesNo - /// @brief Use dialog to get numeric new password with separated line strings and cancel return field - /// - /// @param[in] heading Dialog heading - /// @param[in] line0 Line #0 text - /// @param[in] line1 Line #1 text - /// @param[in] line2 Line #2 text - /// @param[out] canceled Return value about cancel button - /// @param[in] noLabel [opt] label to put on the no button - /// @param[in] yesLabel [opt] label to put on the yes button - /// @return Returns True if 'Yes' was pressed, else False - /// - /// - ///------------------------------------------------------------------------- - /// - /// **Example:** - /// ~~~~~~~~~~~~~{.cpp} - /// #include - /// - /// bool canceled; - /// bool ret = kodi::gui::dialogs::YesNo::ShowAndGetInput( - /// "Yes / No test call", // The Header - /// "You has opened Yes / No dialog for test", - /// "", - /// "Is this OK for you?", - /// canceled, // return value about cancel button - /// "Not really", // No label, is optional and if empty "No" - /// "Ohhh yes"); // Yes label, also optional and if empty "Yes" - /// fprintf(stderr, "You has called Yes/No, returned '%s' and was %s\n", - /// ret ? "yes" : "no", - /// canceled ? "canceled" : "not canceled"); - /// ~~~~~~~~~~~~~ - /// - inline bool ATTRIBUTE_HIDDEN ShowAndGetInput(const std::string& heading, - const std::string& line0, - const std::string& line1, - const std::string& line2, - bool& canceled, - const std::string& noLabel = "", - const std::string& yesLabel = "") - { - using namespace ::kodi::addon; - return CAddonBase::m_interface->toKodi->kodi_gui->dialogYesNo->show_and_get_input_line_button_text(CAddonBase::m_interface->toKodi->kodiBase, - heading.c_str(), line0.c_str(), line1.c_str(), line2.c_str(), - &canceled, noLabel.c_str(), yesLabel.c_str()); - } - //-------------------------------------------------------------------------- - }; - /// @} - -} /* namespace dialogs */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/CMakeLists.txt deleted file mode 100644 index a9ab70c..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -set(HEADERS GL.h - GLonDX.h - Shader.h) - -if(NOT ENABLE_STATIC_LIBS) - core_add_library(addons_kodi-addon-dev-kit_include_kodi_gui_gl) -endif() diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GL.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GL.h deleted file mode 100644 index 943c7d0..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GL.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2005-2019 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -//============================================================================== -/// -/// \defgroup cpp_kodi_gui_gl OpenGL helpers -/// \ingroup cpp_kodi_gui -/// \brief Auxiliary functions for Open GL -/// -/// This group includes help for definitions, functions, and classes for -/// OpenGL. -/// -/// To use OpenGL for your system, add the \ref GL.h "#include ". -/// -/// -///----------------------------------------------------------------------------- -/// -/// The \ref HAS_GL is declared if Open GL is required and \ref HAS_GLES if Open GL -/// Embedded Systems (ES) is required, with ES the version is additionally given -/// in the definition, this can be "2" or "3". -/// -/// -///----------------------------------------------------------------------------- -/// -/// Following \ref GL_TYPE_STRING define can be used, for example, to manage -/// different folders for GL and GLES and make the selection easier. -/// This are on OpenGL "GL" and on Open GL|ES "GLES". -/// -/// **Example:** -/// ~~~~~~~~~~~~~~~~~{.cpp} -/// kodi::GetAddonPath("resources/shaders/" GL_TYPE_STRING "/frag.glsl"); -/// ~~~~~~~~~~~~~~~~~ -/// -/// -///---------------------------------------------------------------------------- -/// -/// In addition, \ref BUFFER_OFFSET is declared in it which can be used to give an -/// offset on the array to GL. -/// -/// **Example:** -/// ~~~~~~~~~~~~~~~~~{.cpp} -/// const struct PackedVertex { -/// float position[3]; // Position x, y, z -/// float color[4]; // Color r, g, b, a -/// } vertices[3] = { -/// { { -0.5f, -0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } }, -/// { { 0.5f, -0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } }, -/// { { 0.0f, 0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } } -/// }; -/// -/// glVertexAttribPointer(m_aPosition, 3, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), BUFFER_OFFSET(offsetof(PackedVertex, position))); -/// glEnableVertexAttribArray(m_aPosition); -/// -/// glVertexAttribPointer(m_aColor, 4, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), BUFFER_OFFSET(offsetof(PackedVertex, color))); -/// glEnableVertexAttribArray(m_aColor); -/// ~~~~~~~~~~~~~~~~~ - -#if HAS_GL - #define GL_TYPE_STRING "GL" - // always define GL_GLEXT_PROTOTYPES before include gl headers - #if !defined(GL_GLEXT_PROTOTYPES) - #define GL_GLEXT_PROTOTYPES - #endif - #if defined(TARGET_LINUX) - #include - #include - #elif defined(TARGET_FREEBSD) - #include - #elif defined(TARGET_DARWIN) - #include - #include - #elif defined(WIN32) - #error Use of GL under Windows is not possible - #endif -#elif HAS_GLES >= 2 - #define GL_TYPE_STRING "GLES" - #if defined(WIN32) - #if defined(HAS_ANGLE) - #include - #else - #error Use of GLES only be available under Windows by the use of angle - #endif - #elif defined(TARGET_DARWIN) - #if HAS_GLES == 3 - #include - #include - #else - #include - #include - #endif - #else - #if HAS_GLES == 3 - #include - #include - #else - #include - #include - #endif - #endif -#endif - -#ifndef BUFFER_OFFSET -#define BUFFER_OFFSET(i) ((char *)nullptr + (i)) -#endif diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GLonDX.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GLonDX.h deleted file mode 100644 index 7a6a0a1..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GLonDX.h +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (C) 2005-2019 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#pragma comment( lib, "d3dcompiler.lib" ) -#ifndef GL_CLIENT_VERSION -#define GL_CLIENT_VERSION 3 -#endif - -namespace kodi -{ -namespace gui -{ -namespace gl -{ - -class ATTRIBUTE_HIDDEN CGLonDX : public kodi::gui::IRenderHelper -{ -public: - explicit CGLonDX() : m_pContext(reinterpret_cast(kodi::gui::GetHWContext())) {} - ~CGLonDX() override { destruct(); } - - bool Init() override - { - EGLint egl_display_attrs[] = - { - EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, - EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE, - EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE, - EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE, EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE, - EGL_NONE - }; - EGLint egl_config_attrs[] = - { - EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, - EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE, - EGL_RENDERABLE_TYPE, GL_CLIENT_VERSION == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, - EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, - EGL_NONE - }; - EGLint egl_context_attrs[] = - { - EGL_CONTEXT_CLIENT_VERSION, GL_CLIENT_VERSION, EGL_NONE - }; - - m_eglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, egl_display_attrs); - if (m_eglDisplay == EGL_NO_DISPLAY) - { - Log(ADDON_LOG_ERROR, "GLonDX: unable to get EGL display (%s)", eglGetErrorString()); - return false; - } - - if (eglInitialize(m_eglDisplay, nullptr, nullptr) != EGL_TRUE) - { - Log(ADDON_LOG_ERROR, "GLonDX: unable to init EGL display (%s)", eglGetErrorString()); - return false; - } - - EGLint numConfigs = 0; - if (eglChooseConfig(m_eglDisplay, egl_config_attrs, &m_eglConfig, 1, &numConfigs) != EGL_TRUE || numConfigs == 0) - { - Log(ADDON_LOG_ERROR, "GLonDX: unable to get EGL config (%s)", eglGetErrorString()); - return false; - } - - m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, nullptr, egl_context_attrs); - if (m_eglContext == EGL_NO_CONTEXT) - { - Log(ADDON_LOG_ERROR, "GLonDX: unable to create EGL context (%s)", eglGetErrorString()); - return false; - } - - if (!createD3DResources()) - return false; - - if (eglMakeCurrent(m_eglDisplay, m_eglBuffer, m_eglBuffer, m_eglContext) != EGL_TRUE) - { - Log(ADDON_LOG_ERROR, "GLonDX: unable to make current EGL (%s)", eglGetErrorString()); - return false; - } - return true; - } - - void CheckGL(ID3D11DeviceContext* device) - { - if (m_pContext != device) - { - m_pSRView = nullptr; - m_pVShader = nullptr; - m_pPShader = nullptr; - m_pContext = device; - - if (m_eglBuffer != EGL_NO_SURFACE) - { - eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroySurface(m_eglDisplay, m_eglBuffer); - m_eglBuffer = EGL_NO_SURFACE; - } - - // create new resources - if (!createD3DResources()) - return; - - eglMakeCurrent(m_eglDisplay, m_eglBuffer, m_eglBuffer, m_eglContext); - } - } - - void Begin() override - { - // confirm on begin D3D context is correct - CheckGL(reinterpret_cast(kodi::gui::GetHWContext())); - - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - } - - void End() override - { - glFlush(); - - // set our primitive shaders - m_pContext->VSSetShader(m_pVShader.Get(), nullptr, 0); - m_pContext->PSSetShader(m_pPShader.Get(), nullptr, 0); - m_pContext->PSSetShaderResources(0, 1, m_pSRView.GetAddressOf()); - // draw texture - m_pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - m_pContext->IASetVertexBuffers(0, 0, nullptr, nullptr, nullptr); - m_pContext->IASetInputLayout(nullptr); - m_pContext->Draw(4, 0); - // unset shaders - m_pContext->PSSetShader(nullptr, nullptr, 0); - m_pContext->VSSetShader(nullptr, nullptr, 0); - // unbind our view - ID3D11ShaderResourceView* views[1] = {}; - m_pContext->PSSetShaderResources(0, 1, views); - } - -private: - enum ShaderType - { - VERTEX_SHADER, - PIXEL_SHADER - }; - - bool createD3DResources() - { - HANDLE sharedHandle; - Microsoft::WRL::ComPtr pDevice; - Microsoft::WRL::ComPtr pRTView; - Microsoft::WRL::ComPtr pRTResource; - Microsoft::WRL::ComPtr pRTTexture; - Microsoft::WRL::ComPtr pOffScreenTexture; - Microsoft::WRL::ComPtr dxgiResource; - - m_pContext->GetDevice(&pDevice); - m_pContext->OMGetRenderTargets(1, &pRTView, nullptr); - if (!pRTView) - return false; - - pRTView->GetResource(&pRTResource); - if (FAILED(pRTResource.As(&pRTTexture))) - return false; - - D3D11_TEXTURE2D_DESC texDesc; - pRTTexture->GetDesc(&texDesc); - texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; - texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; - if (FAILED(pDevice->CreateTexture2D(&texDesc, nullptr, &pOffScreenTexture))) - { - Log(ADDON_LOG_ERROR, "GLonDX: unable to create intermediate texture"); - return false; - } - - CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(pOffScreenTexture.Get(), D3D11_SRV_DIMENSION_TEXTURE2D); - if (FAILED(pDevice->CreateShaderResourceView(pOffScreenTexture.Get(), &srvDesc, &m_pSRView))) - { - Log(ADDON_LOG_ERROR, "GLonDX: unable to create shader view"); - return false; - } - - if (FAILED(pOffScreenTexture.As(&dxgiResource)) || - FAILED(dxgiResource->GetSharedHandle(&sharedHandle))) - { - Log(ADDON_LOG_ERROR, "GLonDX: unable get shared handle for texture"); - return false; - } - - // initiate simple shaders - if (FAILED(d3dCreateShader(VERTEX_SHADER, vs_out_shader_text, &m_pVShader))) - { - Log(ADDON_LOG_ERROR, "GLonDX: unable to create vertex shader view"); - return false; - } - - if (FAILED(d3dCreateShader(PIXEL_SHADER, ps_out_shader_text, &m_pPShader))) - { - Log(ADDON_LOG_ERROR, "GLonDX: unable to create pixel shader view"); - return false; - } - - // create EGL buffer from D3D shared texture - EGLint egl_buffer_attrs[] = - { - EGL_WIDTH, static_cast(texDesc.Width), - EGL_HEIGHT, static_cast(texDesc.Height), - EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, - EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, - EGL_NONE - }; - - m_eglBuffer = eglCreatePbufferFromClientBuffer(m_eglDisplay, - EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, - sharedHandle, m_eglConfig, egl_buffer_attrs); - - if (m_eglBuffer == EGL_NO_SURFACE) - { - Log(ADDON_LOG_ERROR, "GLonDX: unable to create EGL buffer (%s)", eglGetErrorString()); - return false; - } - return true; - } - - HRESULT d3dCreateShader(ShaderType shaderType, const std::string& source, IUnknown** ppShader) const - { - Microsoft::WRL::ComPtr pBlob; - Microsoft::WRL::ComPtr pErrors; - - auto hr = D3DCompile(source.c_str(), source.length(), nullptr, nullptr, nullptr, "main", - shaderType == PIXEL_SHADER ? "ps_4_0" : "vs_4_0", 0, 0, &pBlob, &pErrors); - - if (SUCCEEDED(hr)) - { - Microsoft::WRL::ComPtr pDevice; - m_pContext->GetDevice(&pDevice); - - if (shaderType == PIXEL_SHADER) - { - hr = pDevice->CreatePixelShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, - reinterpret_cast(ppShader)); - } - else - { - hr = pDevice->CreateVertexShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, - reinterpret_cast(ppShader)); - } - - if (FAILED(hr)) - { - Log(ADDON_LOG_ERROR, "GLonDX: unable to create %s shader", - shaderType == PIXEL_SHADER ? "pixel" : "vertex"); - } - } - else - { - Log(ADDON_LOG_ERROR, "GLonDX: unable to compile shader (%s)", pErrors->GetBufferPointer()); - } - return hr; - } - - static const char* eglGetErrorString() - { -#define CASE_STR( value ) case value: return #value - switch (eglGetError()) - { - CASE_STR(EGL_SUCCESS); - CASE_STR(EGL_NOT_INITIALIZED); - CASE_STR(EGL_BAD_ACCESS); - CASE_STR(EGL_BAD_ALLOC); - CASE_STR(EGL_BAD_ATTRIBUTE); - CASE_STR(EGL_BAD_CONTEXT); - CASE_STR(EGL_BAD_CONFIG); - CASE_STR(EGL_BAD_CURRENT_SURFACE); - CASE_STR(EGL_BAD_DISPLAY); - CASE_STR(EGL_BAD_SURFACE); - CASE_STR(EGL_BAD_MATCH); - CASE_STR(EGL_BAD_PARAMETER); - CASE_STR(EGL_BAD_NATIVE_PIXMAP); - CASE_STR(EGL_BAD_NATIVE_WINDOW); - CASE_STR(EGL_CONTEXT_LOST); - default: - return "Unknown"; - } -#undef CASE_STR - } - - void destruct() - { - if (m_eglDisplay != EGL_NO_DISPLAY) - { - eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - - if (m_eglBuffer != EGL_NO_SURFACE) - { - eglDestroySurface(m_eglDisplay, m_eglBuffer); - m_eglBuffer = EGL_NO_SURFACE; - } - - if (m_eglContext != EGL_NO_CONTEXT) - { - eglDestroyContext(m_eglDisplay, m_eglContext); - m_eglContext = EGL_NO_CONTEXT; - } - - eglTerminate(m_eglDisplay); - m_eglDisplay = EGL_NO_DISPLAY; - } - - m_pSRView = nullptr; - m_pVShader = nullptr; - m_pPShader = nullptr; - m_pContext = nullptr; - } - - EGLConfig m_eglConfig = EGL_NO_CONFIG_KHR; - EGLDisplay m_eglDisplay = EGL_NO_DISPLAY; - EGLContext m_eglContext = EGL_NO_CONTEXT; - EGLSurface m_eglBuffer = EGL_NO_SURFACE; - - ID3D11DeviceContext* m_pContext = nullptr; // don't hold context - Microsoft::WRL::ComPtr m_pSRView = nullptr; - Microsoft::WRL::ComPtr m_pVShader = nullptr; - Microsoft::WRL::ComPtr m_pPShader = nullptr; - -#define TO_STRING(...) #__VA_ARGS__ - std::string vs_out_shader_text = TO_STRING( - void main(uint id : SV_VertexId, out float2 tex : TEXCOORD0, out float4 pos : SV_POSITION) - { - tex = float2(id % 2, (id % 4) >> 1); - pos = float4((tex.x - 0.5f) * 2, -(tex.y - 0.5f) * 2, 0, 1); - }); - - std::string ps_out_shader_text = TO_STRING( - Texture2D texMain : register(t0); - SamplerState Sampler - { - Filter = MIN_MAG_MIP_LINEAR; - AddressU = CLAMP; - AddressV = CLAMP; - Comparison = NEVER; - }; - - float4 main(in float2 tex : TEXCOORD0) : SV_TARGET - { - return texMain.Sample(Sampler, tex); - }); -#undef TO_STRING -}; /* class CGLonDX */ - -} /* namespace gl */ - -using CRenderHelper = gl::CGLonDX; -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/Shader.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/Shader.h deleted file mode 100644 index 209f274..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/Shader.h +++ /dev/null @@ -1,594 +0,0 @@ -/* - * Copyright (C) 2005-2019 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "GL.h" - -#include -#include -#include - -#include -#include - -#define LOG_SIZE 1024 -#define GLchar char - -namespace kodi -{ -namespace gui -{ -namespace gl -{ - -//======================================================================== -/// CShader - base class -class ATTRIBUTE_HIDDEN CShader -{ -public: - CShader() = default; - virtual ~CShader() = default; - virtual bool Compile(const std::string& extraBegin = "", - const std::string& extraEnd = "") = 0; - virtual void Free() = 0; - virtual GLuint Handle() = 0; - - bool LoadSource(const std::string& file) - { - char buffer[16384]; - - kodi::vfs::CFile source; - if (!source.OpenFile(file)) - { - kodi::Log(ADDON_LOG_ERROR, "CShader::%s: Failed to open file '%s'", __FUNCTION__, file.c_str()); - return false; - } - size_t len = source.Read(buffer, sizeof(buffer)); - m_source.assign(buffer); - m_source[len] = 0; - source.Close(); - return true; - } - - bool OK() const { return m_compiled; } - -protected: - std::string m_source; - std::string m_lastLog; - bool m_compiled = false; -}; -//------------------------------------------------------------------------ - -//======================================================================== -/// CVertexShader -class ATTRIBUTE_HIDDEN CVertexShader : public CShader -{ -public: - CVertexShader() = default; - ~CVertexShader() override { Free(); } - - void Free() override - { - if (m_vertexShader) - glDeleteShader(m_vertexShader); - m_vertexShader = 0; - } - - bool Compile(const std::string& extraBegin = "", - const std::string& extraEnd = "") override - { - GLint params[4]; - - Free(); - - m_vertexShader = glCreateShader(GL_VERTEX_SHADER); - - GLsizei count = 0; - const char *sources[3]; - if (!extraBegin.empty()) - sources[count++] = extraBegin.c_str(); - if (!m_source.empty()) - sources[count++] = m_source.c_str(); - if (!extraEnd.empty()) - sources[count++] = extraEnd.c_str(); - - glShaderSource(m_vertexShader, count, sources, nullptr); - glCompileShader(m_vertexShader); - glGetShaderiv(m_vertexShader, GL_COMPILE_STATUS, params); - if (params[0] != GL_TRUE) - { - GLchar log[LOG_SIZE]; - glGetShaderInfoLog(m_vertexShader, LOG_SIZE, nullptr, log); - kodi::Log(ADDON_LOG_ERROR, "CVertexShader::%s: %s", __FUNCTION__, log); - fprintf(stderr, "CVertexShader::%s: %s\n", __FUNCTION__, log); - m_lastLog = log; - m_compiled = false; - } - else - { - GLchar log[LOG_SIZE]; - glGetShaderInfoLog(m_vertexShader, LOG_SIZE, nullptr, log); - m_lastLog = log; - m_compiled = true; - } - return m_compiled; - } - - GLuint Handle() override { return m_vertexShader; } - -protected: - GLuint m_vertexShader = 0; -}; -//------------------------------------------------------------------------ - -//======================================================================== -/// CPixelShader -class ATTRIBUTE_HIDDEN CPixelShader : public CShader -{ -public: - CPixelShader() = default; - ~CPixelShader() { Free(); } - void Free() override - { - if (m_pixelShader) - glDeleteShader(m_pixelShader); - m_pixelShader = 0; - } - - bool Compile(const std::string& extraBegin = "", - const std::string& extraEnd = "") override - { - GLint params[4]; - - Free(); - - m_pixelShader = glCreateShader(GL_FRAGMENT_SHADER); - - GLsizei count = 0; - const char *sources[3]; - if (!extraBegin.empty()) - sources[count++] = extraBegin.c_str(); - if (!m_source.empty()) - sources[count++] = m_source.c_str(); - if (!extraEnd.empty()) - sources[count++] = extraEnd.c_str(); - - glShaderSource(m_pixelShader, count, sources, 0); - glCompileShader(m_pixelShader); - glGetShaderiv(m_pixelShader, GL_COMPILE_STATUS, params); - if (params[0] != GL_TRUE) - { - GLchar log[LOG_SIZE]; - glGetShaderInfoLog(m_pixelShader, LOG_SIZE, nullptr, log); - kodi::Log(ADDON_LOG_ERROR, "CPixelShader::%s: %s", __FUNCTION__, log); - fprintf(stderr, "CPixelShader::%s: %s\n", __FUNCTION__, log); - m_lastLog = log; - m_compiled = false; - } - else - { - GLchar log[LOG_SIZE]; - glGetShaderInfoLog(m_pixelShader, LOG_SIZE, nullptr, log); - m_lastLog = log; - m_compiled = true; - } - return m_compiled; - } - - GLuint Handle() override { return m_pixelShader; } - -protected: - GLuint m_pixelShader = 0; -}; -//------------------------------------------------------------------------ - -//============================================================================ -/// -/// \defgroup cpp_kodi_gui_gl_CShaderProgram GL Shader Program -/// \ingroup cpp_kodi_gui_gl -/// @brief \cpp_class{ kodi::gui::gl::CShaderProgram } -/// **Class to manage an OpenGL shader program** -/// -/// With this class the used GL shader code can be defined on the GPU and -/// its variables can be managed between CPU and GPU. -/// -/// It has the header \ref Shader.h "#include " -/// be included to enjoy it. -/// -/// ---------------------------------------------------------------------------- -/// -/// Example: -/// -/// ~~~~~~~~~~~~~{.cpp} -/// -/// #include -/// ... -/// -/// class ATTRIBUTE_HIDDEN CExample -/// : ..., -/// public kodi::gui::gl::CShaderProgram -/// { -/// public: -/// CExample() = default; -/// -/// bool Start(); -/// void Render(); -/// -/// // override functions for kodi::gui::gl::CShaderProgram -/// void OnCompiledAndLinked() override; -/// bool OnEnabled() override; -/// -/// private: -/// ... -/// GLint m_aPosition = -1; -/// GLint m_aColor = -1; -/// }; -/// -/// bool CExample::Start() -/// { -/// // Define shaders and load -/// std::string fraqShader = kodi::GetAddonPath("resources/shaders/" GL_TYPE_STRING "/glsl.frag"); -/// std::string vertShader = kodi::GetAddonPath("resources/shaders/" GL_TYPE_STRING "/glsl.vert"); -/// if (!LoadShaderFiles(vertShader, fraqShader) || !CompileAndLink()) -/// return false; -/// -/// ... -/// return true; -/// } -/// -/// ... -/// -/// void CExample::Render() -/// { -/// ... -/// -/// EnableShader(); -/// ... -/// DO WORK -/// ... -/// DisableShader(); -/// } -/// -/// void CExample::OnCompiledAndLinked() -/// { -/// ... -/// DO YOUR WORK HERE FOR WHAT IS ONE TIME REQUIRED DURING COMPILE OF SHADER, E.G.: -/// -/// m_aPosition = glGetAttribLocation(ProgramHandle(), "a_position"); -/// m_aColor = glGetAttribLocation(ProgramHandle(), "a_color"); -/// } -/// -/// bool OnEnabled() override -/// { -/// ... -/// DO YOUR WORK HERE FOR WHAT REQUIRED DURING ENABLE OF SHADER -/// ... -/// return true; -/// } -/// -/// ADDONCREATOR(CExample); -/// ~~~~~~~~~~~~~ -/// - -//======================================================================== -/// CShaderProgram -class ATTRIBUTE_HIDDEN CShaderProgram -{ -public: - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram - /// @brief Construct a new shader - /// - /// Load must be done later with \ref LoadShaderFiles. - /// - CShaderProgram() = default; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram - /// @brief Construct a new shader and load defined shader files - /// - /// @param[in] vert Path to used GL vertext shader - /// @param[in] frag Path to used GL fragment shader - /// - CShaderProgram(const std::string& vert, const std::string& frag) - { - LoadShaderFiles(vert, frag); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram - /// @brief Destructor - /// - virtual ~CShaderProgram() - { - ShaderFree(); - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram - /// @brief To load manually the needed shader files - /// - /// @param[in] vert Path to used GL vertext shader - /// @param[in] frag Path to used GL fragment shader - /// - /// - /// @note The use of the files is optional, but it must either be passed over - /// here or via \ref CompileAndLink, or both of the source code. - /// - bool LoadShaderFiles(const std::string& vert, const std::string& frag) - { - if (!kodi::vfs::FileExists(vert) || !m_pVP.LoadSource(vert)) - { - kodi::Log(ADDON_LOG_ERROR, "%s: Failed to load '%s'", __func__, vert.c_str()); - return false; - } - - if (!kodi::vfs::FileExists(frag) || !m_pFP.LoadSource(frag)) - { - kodi::Log(ADDON_LOG_ERROR, "%s: Failed to load '%s'", __func__, frag.c_str()); - return false; - } - - return true; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram - /// @brief To compile and link the shader to the GL interface - /// - /// Optionally, additional source code can be transferred here, or it can be - /// used independently without any files - /// - /// @param[in] vertexExtraBegin [opt] To additionally add vextex source - /// code to the beginning of the loaded file - /// source code - /// @param[in] vertexExtraEnd [opt] To additionally add vextex source - /// code to the end of the loaded file - /// source code - /// @param[in] fragmentExtraBegin [opt] To additionally add fragment source - /// code to the beginning of the loaded file - /// source code - /// @param[in] fragmentExtraEnd [opt] To additionally add fragment source - /// code to the end of the loaded file - /// source code - /// @return true if compile was successed - /// - /// - /// @note In the case of a compile error, it will be written once into the Kodi - /// log and in addition to the console output to quickly detect the errors when - /// writing the damage. - /// - /// - bool CompileAndLink(const std::string& vertexExtraBegin = "", - const std::string& vertexExtraEnd = "", - const std::string& fragmentExtraBegin = "", - const std::string& fragmentExtraEnd = "") - { - GLint params[4]; - - // free resources - ShaderFree(); - m_ok = false; - - // compiled vertex shader - if (!m_pVP.Compile(vertexExtraBegin, vertexExtraEnd)) - { - kodi::Log(ADDON_LOG_ERROR, "GL: Error compiling vertex shader"); - return false; - } - - // compile pixel shader - if (!m_pFP.Compile(fragmentExtraBegin, fragmentExtraEnd)) - { - m_pVP.Free(); - kodi::Log(ADDON_LOG_ERROR, "GL: Error compiling fragment shader"); - return false; - } - - // create program object - m_shaderProgram = glCreateProgram(); - if (!m_shaderProgram) - { - kodi::Log(ADDON_LOG_ERROR, "CShaderProgram::%s: Failed to create GL program", __FUNCTION__); - ShaderFree(); - return false; - } - - // attach the vertex shader - glAttachShader(m_shaderProgram, m_pVP.Handle()); - glAttachShader(m_shaderProgram, m_pFP.Handle()); - - // link the program - glLinkProgram(m_shaderProgram); - glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, params); - if (params[0] != GL_TRUE) - { - GLchar log[LOG_SIZE]; - glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, nullptr, log); - kodi::Log(ADDON_LOG_ERROR, "CShaderProgram::%s: %s", __FUNCTION__, log); - fprintf(stderr, "CShaderProgram::%s: %s\n", __FUNCTION__, log); - ShaderFree(); - return false; - } - - m_validated = false; - m_ok = true; - OnCompiledAndLinked(); - return true; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram - /// @brief To activate the shader and use it on the GPU - /// - /// @return true if enable was successfull done - /// - /// - /// @note During this call, the \ref OnEnabled stored in the child is also - /// called - /// - bool EnableShader() - { - if (ShaderOK()) - { - glUseProgram(m_shaderProgram); - if (OnEnabled()) - { - if (!m_validated) - { - // validate the program - GLint params[4]; - glValidateProgram(m_shaderProgram); - glGetProgramiv(m_shaderProgram, GL_VALIDATE_STATUS, params); - if (params[0] != GL_TRUE) - { - GLchar log[LOG_SIZE]; - glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, nullptr, log); - kodi::Log(ADDON_LOG_ERROR, "CShaderProgram::%s: %s", __FUNCTION__, log); - fprintf(stderr, "CShaderProgram::%s: %s\n", __FUNCTION__, log); - } - m_validated = true; - } - return true; - } - else - { - glUseProgram(0); - return false; - } - return true; - } - return false; - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram - /// @brief To deactivate the shader use on the GPU - /// - void DisableShader() - { - if (ShaderOK()) - { - glUseProgram(0); - OnDisabled(); - } - } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram - /// @brief Used to check if shader has been loaded before. - /// - /// @return true if enable was successfull done - /// - /// @note The CompileAndLink call sets these values - /// - ATTRIBUTE_FORCEINLINE bool ShaderOK() const { return m_ok; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram - /// @brief To get the vertex shader class used by Kodi at the addon - /// - /// @return pointer to vertex shader class - /// - ATTRIBUTE_FORCEINLINE CVertexShader& VertexShader() { return m_pVP; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram - /// @brief To get the fragment shader class used by Kodi at the addon - /// - /// @return pointer to fragment shader class - /// - ATTRIBUTE_FORCEINLINE CPixelShader& PixelShader() { return m_pFP; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram - /// @brief Used to get the definition created in the OpenGL itself - /// - /// @return GLuint of GL shader program handler - /// - ATTRIBUTE_FORCEINLINE GLuint ProgramHandle() { return m_shaderProgram; } - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \defgroup cpp_kodi_gui_gl_CShaderProgram_child Child Functions - /// \ingroup cpp_kodi_gui_gl_CShaderProgram - /// @brief \cpp_class{ kodi::gui::gl::CShaderProgram child functions } - /// - /// Functions that are added by parent in the child - //@{ - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram_child - /// @brief Mandatory child function to set the necessary CPU to GPU data - /// - virtual void OnCompiledAndLinked() {}; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram_child - /// @brief Optional function to exchange data between CPU and GPU while - /// activating the shader - /// - /// @return true if enable was successfull done - /// - virtual bool OnEnabled() { return true; }; - //-------------------------------------------------------------------------- - - //========================================================================== - /// - /// \ingroup cpp_kodi_gui_gl_CShaderProgram_child - /// @brief Optional child function that may have to be performed when - /// switching off the shader - virtual void OnDisabled() {}; - //-------------------------------------------------------------------------- - //@} - -private: - void ShaderFree() - { - if (m_shaderProgram) - glDeleteProgram(m_shaderProgram); - m_shaderProgram = 0; - m_ok = false; - } - - CVertexShader m_pVP; - CPixelShader m_pFP; - GLuint m_shaderProgram = 0; - bool m_ok = false; - bool m_validated = false; -}; -//------------------------------------------------------------------------ - -} /* namespace gl */ -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/renderHelper.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/renderHelper.h deleted file mode 100644 index 2e96d21..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/renderHelper.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2005-2019 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../AddonBase.h" - -namespace kodi -{ -namespace gui -{ -struct ATTRIBUTE_HIDDEN IRenderHelper -{ - virtual ~IRenderHelper() = default; - virtual bool Init() = 0; - virtual void Begin() = 0; - virtual void End() = 0; -}; /* class IRenderHelper */ -} /* namespace gui */ -} /* namespace kodi */ - -#if defined(WIN32) && defined(HAS_ANGLE) -#include "gl/GLonDX.h" -#else -/* - * Default background GUI render helper class - */ -namespace kodi -{ -namespace gui -{ -struct ATTRIBUTE_HIDDEN CRenderHelperStub : public IRenderHelper -{ - bool Init() override { return true; } - void Begin() override { } - void End() override { } -}; /* class CRenderHelperStub */ - -using CRenderHelper = CRenderHelperStub; -} /* namespace gui */ -} /* namespace kodi */ -#endif - -namespace kodi -{ -namespace gui -{ - -/* - * Create render background handler, e.g. becomes on "Windows" Angle used - * to emulate GL. - * - * This only be used internal and not from addon's direct. - * - * Function defines here and not in CAddonBase because of a hen and egg problem. - */ -inline std::shared_ptr ATTRIBUTE_HIDDEN GetRenderHelper() -{ - using namespace ::kodi::addon; - if (static_cast(CAddonBase::m_interface->addonBase)->m_renderHelper) - return static_cast(CAddonBase::m_interface->addonBase)->m_renderHelper; - - const std::shared_ptr renderHelper(new CRenderHelper()); - if (!renderHelper->Init()) - return nullptr; - - static_cast(CAddonBase::m_interface->addonBase)->m_renderHelper = - renderHelper; // Hold on base for other types - return renderHelper; -} - -} /* namespace gui */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/platform/android/System.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/platform/android/System.h deleted file mode 100644 index ef2d728..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/platform/android/System.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "../../AddonBase.h" - -/* - * For interface between add-on and kodi. - * - * This structure defines the addresses of functions stored inside Kodi which - * are then available for the add-on to call - * - * All function pointers there are used by the C++ interface functions below. - * You find the set of them on xbmc/addons/interfaces/General.cpp - * - * Note: For add-on development itself this is not needed - */ - -static const char* INTERFACE_ANDROID_SYSTEM_NAME = "ANDROID_SYSTEM"; -static const char* INTERFACE_ANDROID_SYSTEM_VERSION = "1.0.1"; -static const char* INTERFACE_ANDROID_SYSTEM_VERSION_MIN = "1.0.1"; - -struct AddonToKodiFuncTable_android_system -{ - void* (*get_jni_env)(); - int (*get_sdk_version)(); - const char *(*get_class_name)(); -}; - -//============================================================================== -/// -/// \defgroup cpp_kodi_platform Interface - kodi::platform -/// \ingroup cpp -/// @brief **Android platform specific functions** -/// -/// #include " -/// -//------------------------------------------------------------------------------ - -namespace kodi -{ -namespace platform -{ -class ATTRIBUTE_HIDDEN CInterfaceAndroidSystem -{ -public: - CInterfaceAndroidSystem() - : m_interface(static_cast( - GetInterface(INTERFACE_ANDROID_SYSTEM_NAME, INTERFACE_ANDROID_SYSTEM_VERSION))){}; - - //============================================================================ - /// - /// \ingroup cpp_kodi_platform - /// @brief request an JNI env pointer for the calling thread. - /// JNI env has to be controlled by kodi because of the underlying - /// threading concep. - /// - /// @param[in]: - /// @return JNI env pointer for the calling thread - /// - inline void* GetJNIEnv() - { - if (m_interface) - return m_interface->get_jni_env(); - - return nullptr; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// - /// \ingroup cpp_kodi_platform - /// @brief request the android sdk version to e.g. initialize JNIBase. - /// - /// @param[in]: - /// @return Android SDK version - /// - inline int GetSDKVersion() - { - if (m_interface) - return m_interface->get_sdk_version(); - - return 0; - } - - //============================================================================ - /// - /// \ingroup cpp_kodi_platform - /// @brief request the android main class name e.g. org.xbmc.kodi. - /// - /// @param[in]: - /// @return package class name - /// - inline std::string GetClassName() - { - if (m_interface) - return m_interface->get_class_name(); - - return std::string(); - } - -private: - AddonToKodiFuncTable_android_system* m_interface; -}; -//---------------------------------------------------------------------------- - -} /* namespace platform */ -} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/tools/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/tools/CMakeLists.txt deleted file mode 100644 index 939585c..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/tools/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(HEADERS DllHelper.h ) - -if(NOT ENABLE_STATIC_LIBS) - core_add_library(addons_kodi-addon-dev-kit_include_kodi_tools) -endif() diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/tools/DllHelper.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/tools/DllHelper.h deleted file mode 100644 index 3cc9eea..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/tools/DllHelper.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2005-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#ifdef __cplusplus - -#include - -#include -#include -#include - -//============================================================================== -/// @ingroup cpp_kodi_tools_CDllHelper -/// @brief Macro to translate the given pointer value name of functions to -/// requested function name. -/// -/// @note This should always be used and does the work of -/// @ref kodi::tools::CDllHelper::RegisterSymbol(). -/// -#define REGISTER_DLL_SYMBOL(functionPtr) \ - kodi::tools::CDllHelper::RegisterSymbol(functionPtr, #functionPtr) -//------------------------------------------------------------------------------ - -namespace kodi -{ -namespace tools -{ - -//============================================================================== -/// @defgroup cpp_kodi_tools_CDllHelper class CDllHelper -/// @ingroup cpp_kodi_tools -/// @brief **Class to help with load of shared library functions**\n -/// You can add them as parent to your class and to help with load of shared -/// library functions. -/// -/// @note To use on Windows must you also include [dlfcn-win32](https://github.com/dlfcn-win32/dlfcn-win32) -/// on your addon!\n\n -/// Furthermore, this allows the use of Android where the required library is -/// copied to an EXE useable folder. -/// -/// -/// ---------------------------------------------------------------------------- -/// -/// **Example:** -/// ~~~~~~~~~~~~~{.cpp} -/// -/// #include -/// -/// ... -/// class CMyInstance : public kodi::addon::CInstanceAudioDecoder, -/// private kodi::tools::CDllHelper -/// { -/// public: -/// CMyInstance(KODI_HANDLE instance, const std::string& kodiVersion); -/// bool Start(); -/// -/// ... -/// -/// // The pointers for on shared library exported functions -/// int (*Init)(); -/// void (*Cleanup)(); -/// int (*GetLength)(); -/// }; -/// -/// CMyInstance::CMyInstance(KODI_HANDLE instance, const std::string& kodiVersion) -/// : CInstanceAudioDecoder(instance, kodiVersion) -/// { -/// } -/// -/// bool CMyInstance::Start() -/// { -/// std::string lib = kodi::GetAddonPath("myLib.so"); -/// if (!LoadDll(lib)) return false; -/// if (!REGISTER_DLL_SYMBOL(Init)) return false; -/// if (!REGISTER_DLL_SYMBOL(Cleanup)) return false; -/// if (!REGISTER_DLL_SYMBOL(GetLength)) return false; -/// -/// Init(); -/// return true; -/// } -/// ... -/// ~~~~~~~~~~~~~ -/// -///@{ -class ATTRIBUTE_HIDDEN CDllHelper -{ -public: - //============================================================================ - /// @ingroup cpp_kodi_tools_CDllHelper - /// @brief Class constructor. - /// - CDllHelper() = default; - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_tools_CDllHelper - /// @brief Class destructor. - /// - virtual ~CDllHelper() - { - if (m_dll) - dlclose(m_dll); - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_tools_CDllHelper - /// @brief Function to load requested library. - /// - /// @param[in] path The path with filename of shared library to load - /// @return true if load was successful done - /// - bool LoadDll(std::string path) - { -#if defined(TARGET_ANDROID) - if (kodi::vfs::FileExists(path)) - { - // Check already defined for "xbmcaltbinaddons", if yes no copy necassary. - std::string xbmcaltbinaddons = - kodi::vfs::TranslateSpecialProtocol("special://xbmcaltbinaddons/"); - if (path.compare(0, xbmcaltbinaddons.length(), xbmcaltbinaddons) != 0) - { - bool doCopy = true; - std::string dstfile = xbmcaltbinaddons + kodi::vfs::GetFileName(path); - - kodi::vfs::FileStatus dstFileStat; - if (kodi::vfs::StatFile(dstfile, dstFileStat)) - { - kodi::vfs::FileStatus srcFileStat; - if (kodi::vfs::StatFile(path, srcFileStat)) - { - if (dstFileStat.GetSize() == srcFileStat.GetSize() && - dstFileStat.GetModificationTime() > srcFileStat.GetModificationTime()) - doCopy = false; - } - } - - if (doCopy) - { - kodi::Log(ADDON_LOG_DEBUG, "Caching '%s' to '%s'", path.c_str(), dstfile.c_str()); - if (!kodi::vfs::CopyFile(path, dstfile)) - { - kodi::Log(ADDON_LOG_ERROR, "Failed to cache '%s' to '%s'", path.c_str(), - dstfile.c_str()); - return false; - } - } - - path = dstfile; - } - } - else - { - return false; - } -#endif - - m_dll = dlopen(path.c_str(), RTLD_LAZY); - if (m_dll == nullptr) - { - kodi::Log(ADDON_LOG_ERROR, "Unable to load %s", dlerror()); - return false; - } - return true; - } - //---------------------------------------------------------------------------- - - //============================================================================ - /// @ingroup cpp_kodi_tools_CDllHelper - /// @brief Function to register requested library symbol. - /// - /// @warning This function should not be used, use instead the macro - /// @ref REGISTER_DLL_SYMBOL to register the symbol pointer. - /// - /// - /// Use this always via Macro, e.g.: - /// ~~~~~~~~~~~~~{.cpp} - /// if (!REGISTER_DLL_SYMBOL(Init)) - /// return false; - /// ~~~~~~~~~~~~~ - /// - template - bool RegisterSymbol(T& functionPtr, const char* strFunctionPtr) - { - functionPtr = reinterpret_cast(dlsym(m_dll, strFunctionPtr)); - if (functionPtr == nullptr) - { - kodi::Log(ADDON_LOG_ERROR, "Unable to assign function %s", dlerror()); - return false; - } - return true; - } - //---------------------------------------------------------------------------- - -private: - void* m_dll = nullptr; -}; -///@} -//------------------------------------------------------------------------------ - -} /* namespace tools */ -} /* namespace kodi */ - -#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h deleted file mode 100644 index 041e22b..0000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (C) 2016-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include - -#define STR_HELPER(x) #x -#define STR(x) STR_HELPER(x) - -/* - *------------------------------------------------------------------------------ - * Some parts on headers are only be used for Kodi itself and internally (not - * for add-on development). - * - * For this reason also no doxygen part with "///" defined there. - * ----------------------------------------------------------------------------- - */ - -/* - * Versions of all add-on globals and instances are defined below. - * - * This is added here and not in related header to prevent not - * needed includes during compile. Also have it here a better - * overview. - */ - -// Ignore clang here, as this must be good in overview and as the main reason, -// because cmake uses this area in this form to perform its addon dependency -// check. -// clang-format off -#define ADDON_GLOBAL_VERSION_MAIN "1.2.4" -#define ADDON_GLOBAL_VERSION_MAIN_MIN "1.2.0" -#define ADDON_GLOBAL_VERSION_MAIN_XML_ID "kodi.binary.global.main" -#define ADDON_GLOBAL_VERSION_MAIN_DEPENDS "AddonBase.h" \ - "addon-instance/" \ - "c-api/addon_base.h" - -#define ADDON_GLOBAL_VERSION_GENERAL "1.0.5" -#define ADDON_GLOBAL_VERSION_GENERAL_MIN "1.0.4" -#define ADDON_GLOBAL_VERSION_GENERAL_XML_ID "kodi.binary.global.general" -#define ADDON_GLOBAL_VERSION_GENERAL_DEPENDS "General.h" - -#define ADDON_GLOBAL_VERSION_GUI "5.14.1" -#define ADDON_GLOBAL_VERSION_GUI_MIN "5.14.0" -#define ADDON_GLOBAL_VERSION_GUI_XML_ID "kodi.binary.global.gui" -#define ADDON_GLOBAL_VERSION_GUI_DEPENDS "ActionIDs.h" \ - "gui/" - -#define ADDON_GLOBAL_VERSION_AUDIOENGINE "1.1.1" -#define ADDON_GLOBAL_VERSION_AUDIOENGINE_MIN "1.1.0" -#define ADDON_GLOBAL_VERSION_AUDIOENGINE_XML_ID "kodi.binary.global.audioengine" -#define ADDON_GLOBAL_VERSION_AUDIOENGINE_DEPENDS "AudioEngine.h" \ - "c-api/audio_engine.h" - -#define ADDON_GLOBAL_VERSION_FILESYSTEM "1.1.4" -#define ADDON_GLOBAL_VERSION_FILESYSTEM_MIN "1.1.0" -#define ADDON_GLOBAL_VERSION_FILESYSTEM_XML_ID "kodi.binary.global.filesystem" -#define ADDON_GLOBAL_VERSION_FILESYSTEM_DEPENDS "Filesystem.h" \ - "c-api/filesystem.h" \ - "gui/gl/Shader.h" \ - "tools/DllHelper.h" - -#define ADDON_GLOBAL_VERSION_NETWORK "1.0.4" -#define ADDON_GLOBAL_VERSION_NETWORK_MIN "1.0.0" -#define ADDON_GLOBAL_VERSION_NETWORK_XML_ID "kodi.binary.global.network" -#define ADDON_GLOBAL_VERSION_NETWORK_DEPENDS "Network.h" \ - "c-api/network.h" - -#define ADDON_GLOBAL_VERSION_TOOLS "1.0.1" -#define ADDON_GLOBAL_VERSION_TOOLS_MIN "1.0.0" -#define ADDON_GLOBAL_VERSION_TOOLS_XML_ID "kodi.binary.global.tools" -#define ADDON_GLOBAL_VERSION_TOOLS_DEPENDS "tools/DllHelper.h" - -#define ADDON_INSTANCE_VERSION_AUDIODECODER "2.0.2" -#define ADDON_INSTANCE_VERSION_AUDIODECODER_MIN "2.0.1" -#define ADDON_INSTANCE_VERSION_AUDIODECODER_XML_ID "kodi.binary.instance.audiodecoder" -#define ADDON_INSTANCE_VERSION_AUDIODECODER_DEPENDS "addon-instance/AudioDecoder.h" - -#define ADDON_INSTANCE_VERSION_AUDIOENCODER "2.0.2" -#define ADDON_INSTANCE_VERSION_AUDIOENCODER_MIN "2.0.1" -#define ADDON_INSTANCE_VERSION_AUDIOENCODER_XML_ID "kodi.binary.instance.audioencoder" -#define ADDON_INSTANCE_VERSION_AUDIOENCODER_DEPENDS "addon-instance/AudioEncoder.h" - -#define ADDON_INSTANCE_VERSION_GAME "2.0.2" -#define ADDON_INSTANCE_VERSION_GAME_MIN "2.0.1" -#define ADDON_INSTANCE_VERSION_GAME_XML_ID "kodi.binary.instance.game" -#define ADDON_INSTANCE_VERSION_GAME_DEPENDS "addon-instance/Game.h" - -#define ADDON_INSTANCE_VERSION_IMAGEDECODER "2.1.1" -#define ADDON_INSTANCE_VERSION_IMAGEDECODER_MIN "2.1.0" -#define ADDON_INSTANCE_VERSION_IMAGEDECODER_XML_ID "kodi.binary.instance.imagedecoder" -#define ADDON_INSTANCE_VERSION_IMAGEDECODER_DEPENDS "addon-instance/ImageDecoder.h" - -#define ADDON_INSTANCE_VERSION_INPUTSTREAM "2.3.3" -#define ADDON_INSTANCE_VERSION_INPUTSTREAM_MIN "2.3.1" -#define ADDON_INSTANCE_VERSION_INPUTSTREAM_XML_ID "kodi.binary.instance.inputstream" -#define ADDON_INSTANCE_VERSION_INPUTSTREAM_DEPENDS "addon-instance/Inputstream.h" - -#define ADDON_INSTANCE_VERSION_PERIPHERAL "1.3.9" -#define ADDON_INSTANCE_VERSION_PERIPHERAL_MIN "1.3.8" -#define ADDON_INSTANCE_VERSION_PERIPHERAL_XML_ID "kodi.binary.instance.peripheral" -#define ADDON_INSTANCE_VERSION_PERIPHERAL_DEPENDS "addon-instance/Peripheral.h" \ - "addon-instance/PeripheralUtils.h" - -#define ADDON_INSTANCE_VERSION_PVR "7.0.1" -#define ADDON_INSTANCE_VERSION_PVR_MIN "7.0.0" -#define ADDON_INSTANCE_VERSION_PVR_XML_ID "kodi.binary.instance.pvr" -#define ADDON_INSTANCE_VERSION_PVR_DEPENDS "c-api/addon-instance/pvr.h" \ - "c-api/addon-instance/pvr/pvr_channel_groups.h" \ - "c-api/addon-instance/pvr/pvr_channels.h" \ - "c-api/addon-instance/pvr/pvr_defines.h" \ - "c-api/addon-instance/pvr/pvr_edl.h" \ - "c-api/addon-instance/pvr/pvr_epg.h" \ - "c-api/addon-instance/pvr/pvr_general.h" \ - "c-api/addon-instance/pvr/pvr_menu_hook.h" \ - "c-api/addon-instance/pvr/pvr_recordings.h" \ - "c-api/addon-instance/pvr/pvr_stream.h" \ - "c-api/addon-instance/pvr/pvr_timers.h" \ - "addon-instance/PVR.h" \ - "addon-instance/pvr/ChannelGroups.h" \ - "addon-instance/pvr/Channels.h" \ - "addon-instance/pvr/EDL.h" \ - "addon-instance/pvr/EPG.h" \ - "addon-instance/pvr/General.h" \ - "addon-instance/pvr/MenuHook.h" \ - "addon-instance/pvr/Recordings.h" \ - "addon-instance/pvr/Stream.h" \ - "addon-instance/pvr/Timers.h" - -#define ADDON_INSTANCE_VERSION_SCREENSAVER "2.0.2" -#define ADDON_INSTANCE_VERSION_SCREENSAVER_MIN "2.0.1" -#define ADDON_INSTANCE_VERSION_SCREENSAVER_XML_ID "kodi.binary.instance.screensaver" -#define ADDON_INSTANCE_VERSION_SCREENSAVER_DEPENDS "addon-instance/Screensaver.h" - -#define ADDON_INSTANCE_VERSION_VFS "2.3.2" -#define ADDON_INSTANCE_VERSION_VFS_MIN "2.3.1" -#define ADDON_INSTANCE_VERSION_VFS_XML_ID "kodi.binary.instance.vfs" -#define ADDON_INSTANCE_VERSION_VFS_DEPENDS "addon-instance/VFS.h" - -#define ADDON_INSTANCE_VERSION_VISUALIZATION "2.0.4" -#define ADDON_INSTANCE_VERSION_VISUALIZATION_MIN "2.0.3" -#define ADDON_INSTANCE_VERSION_VISUALIZATION_XML_ID "kodi.binary.instance.visualization" -#define ADDON_INSTANCE_VERSION_VISUALIZATION_DEPENDS "addon-instance/Visualization.h" - -#define ADDON_INSTANCE_VERSION_VIDEOCODEC "1.0.3" -#define ADDON_INSTANCE_VERSION_VIDEOCODEC_MIN "1.0.2" -#define ADDON_INSTANCE_VERSION_VIDEOCODEC_XML_ID "kodi.binary.instance.videocodec" -#define ADDON_INSTANCE_VERSION_VIDEOCODEC_DEPENDS "addon-instance/VideoCodec.h" \ - "StreamCodec.h" \ - "StreamCrypto.h" -// clang-format on - -//============================================================================== -/// -/// @ingroup cpp_kodi_addon_addonbase -/// The currently available instance types for Kodi add-ons -/// -/// \internal -/// @note For add of new types take a new number on end. To change -/// existing numbers can be make problems on already compiled add-ons. -/// \endinternal -/// -typedef enum ADDON_TYPE -{ - /* addon global parts */ - ADDON_GLOBAL_MAIN = 0, - ADDON_GLOBAL_GUI = 1, - ADDON_GLOBAL_AUDIOENGINE = 2, - ADDON_GLOBAL_GENERAL = 3, - ADDON_GLOBAL_NETWORK = 4, - ADDON_GLOBAL_FILESYSTEM = 5, - ADDON_GLOBAL_TOOLS = 6, - // Last used global id, used in loops to check versions. - // Need to change if new global type becomes added! - ADDON_GLOBAL_MAX = 6, - - /* addon type instances */ - - /// Audio decoder instance, see \ref cpp_kodi_addon_audiodecoder "kodi::addon::CInstanceAudioDecoder" - ADDON_INSTANCE_AUDIODECODER = 102, - - /// Audio encoder instance, see \ref cpp_kodi_addon_audioencoder "kodi::addon::CInstanceAudioEncoder" - ADDON_INSTANCE_AUDIOENCODER = 103, - - /// Game instance, see \ref cpp_kodi_addon_game "kodi::addon::CInstanceGame" - ADDON_INSTANCE_GAME = 104, - - /// Input stream instance, see \ref cpp_kodi_addon_inputstream "kodi::addon::CInstanceInputStream" - ADDON_INSTANCE_INPUTSTREAM = 105, - - /// Peripheral instance, see \ref cpp_kodi_addon_peripheral "kodi::addon::CInstancePeripheral" - ADDON_INSTANCE_PERIPHERAL = 106, - - /// Game instance, see \ref cpp_kodi_addon_pvr "kodi::addon::CInstancePVRClient" - ADDON_INSTANCE_PVR = 107, - - /// PVR client instance, see \ref cpp_kodi_addon_screensaver "kodi::addon::CInstanceScreensaver" - ADDON_INSTANCE_SCREENSAVER = 108, - - /// Music visualization instance, see \ref cpp_kodi_addon_visualization "kodi::addon::CInstanceVisualization" - ADDON_INSTANCE_VISUALIZATION = 109, - - /// Virtual Filesystem (VFS) instance, see \ref cpp_kodi_addon_vfs "kodi::addon::CInstanceVFS" - ADDON_INSTANCE_VFS = 110, - - /// Image Decoder instance, see \ref cpp_kodi_addon_imagedecoder "kodi::addon::CInstanceImageDecoder" - ADDON_INSTANCE_IMAGEDECODER = 111, - - /// Video Decoder instance, see \ref cpp_kodi_addon_videocodec "kodi::addon::CInstanceVideoCodec" - ADDON_INSTANCE_VIDEOCODEC = 112, -} ADDON_TYPE; -//------------------------------------------------------------------------------ - -#ifdef __cplusplus -extern "C" { -namespace kodi { -namespace addon { -#endif - -/// -/// This is used from Kodi to get the active version of add-on parts. -/// It is compiled in add-on and also in Kodi itself, with this can be Kodi -/// compare the version from him with them on add-on. -/// -/// @param[in] type The with 'enum ADDON_TYPE' type to ask -/// @return version The current version of asked type -/// -inline const char* GetTypeVersion(int type) -{ - /* - * #ifdef's below becomes set by cmake, no set by hand needed. - */ - switch (type) - { - /* addon global parts */ - case ADDON_GLOBAL_MAIN: - return ADDON_GLOBAL_VERSION_MAIN; -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_GENERAL_USED) - case ADDON_GLOBAL_GENERAL: - return ADDON_GLOBAL_VERSION_GENERAL; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_GUI_USED) - case ADDON_GLOBAL_GUI: - return ADDON_GLOBAL_VERSION_GUI; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_AUDIOENGINE_USED) - case ADDON_GLOBAL_AUDIOENGINE: - return ADDON_GLOBAL_VERSION_AUDIOENGINE; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_FILESYSTEM_USED) - case ADDON_GLOBAL_FILESYSTEM: - return ADDON_GLOBAL_VERSION_FILESYSTEM; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_NETWORK_USED) - case ADDON_GLOBAL_NETWORK: - return ADDON_GLOBAL_VERSION_NETWORK; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_TOOLS_USED) - case ADDON_GLOBAL_TOOLS: - return ADDON_GLOBAL_VERSION_TOOLS; -#endif - - /* addon type instances */ -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_AUDIODECODER_USED) - case ADDON_INSTANCE_AUDIODECODER: - return ADDON_INSTANCE_VERSION_AUDIODECODER; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_AUDIOENCODER_USED) - case ADDON_INSTANCE_AUDIOENCODER: - return ADDON_INSTANCE_VERSION_AUDIOENCODER; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_GAME_USED) - case ADDON_INSTANCE_GAME: - return ADDON_INSTANCE_VERSION_GAME; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_IMAGEDECODER_USED) - case ADDON_INSTANCE_IMAGEDECODER: - return ADDON_INSTANCE_VERSION_IMAGEDECODER; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_INPUTSTREAM_USED) - case ADDON_INSTANCE_INPUTSTREAM: - return ADDON_INSTANCE_VERSION_INPUTSTREAM; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_PERIPHERAL_USED) - case ADDON_INSTANCE_PERIPHERAL: - return ADDON_INSTANCE_VERSION_PERIPHERAL; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_PVR_USED) - case ADDON_INSTANCE_PVR: - return ADDON_INSTANCE_VERSION_PVR; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_SCREENSAVER_USED) - case ADDON_INSTANCE_SCREENSAVER: - return ADDON_INSTANCE_VERSION_SCREENSAVER; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_VFS_USED) - case ADDON_INSTANCE_VFS: - return ADDON_INSTANCE_VERSION_VFS; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_VISUALIZATION_USED) - case ADDON_INSTANCE_VISUALIZATION: - return ADDON_INSTANCE_VERSION_VISUALIZATION; -#endif -#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_VIDEOCODEC_USED) - case ADDON_INSTANCE_VIDEOCODEC: - return ADDON_INSTANCE_VERSION_VIDEOCODEC; -#endif - } - return "0.0.0"; -} - -/// -/// This is used from Kodi to get the minimum supported version of add-on parts. -/// It is compiled in add-on and also in Kodi itself, with this can be Kodi -/// compare the version from him with them on add-on. -/// -/// @param[in] type The with 'enum ADDON_TYPE' type to ask -/// @return version The minimum version of asked type -/// -inline const char* GetTypeMinVersion(int type) -{ - switch (type) - { - /* addon global parts */ - case ADDON_GLOBAL_MAIN: - return ADDON_GLOBAL_VERSION_MAIN_MIN; - case ADDON_GLOBAL_GUI: - return ADDON_GLOBAL_VERSION_GUI_MIN; - case ADDON_GLOBAL_GENERAL: - return ADDON_GLOBAL_VERSION_GENERAL_MIN; - case ADDON_GLOBAL_AUDIOENGINE: - return ADDON_GLOBAL_VERSION_AUDIOENGINE_MIN; - case ADDON_GLOBAL_FILESYSTEM: - return ADDON_GLOBAL_VERSION_FILESYSTEM_MIN; - case ADDON_GLOBAL_NETWORK: - return ADDON_GLOBAL_VERSION_NETWORK_MIN; - case ADDON_GLOBAL_TOOLS: - return ADDON_GLOBAL_VERSION_TOOLS_MIN; - - /* addon type instances */ - case ADDON_INSTANCE_AUDIODECODER: - return ADDON_INSTANCE_VERSION_AUDIODECODER_MIN; - case ADDON_INSTANCE_AUDIOENCODER: - return ADDON_INSTANCE_VERSION_AUDIOENCODER_MIN; - case ADDON_INSTANCE_GAME: - return ADDON_INSTANCE_VERSION_GAME_MIN; - case ADDON_INSTANCE_IMAGEDECODER: - return ADDON_INSTANCE_VERSION_IMAGEDECODER_MIN; - case ADDON_INSTANCE_INPUTSTREAM: - return ADDON_INSTANCE_VERSION_INPUTSTREAM_MIN; - case ADDON_INSTANCE_PERIPHERAL: - return ADDON_INSTANCE_VERSION_PERIPHERAL_MIN; - case ADDON_INSTANCE_PVR: - return ADDON_INSTANCE_VERSION_PVR_MIN; - case ADDON_INSTANCE_SCREENSAVER: - return ADDON_INSTANCE_VERSION_SCREENSAVER_MIN; - case ADDON_INSTANCE_VFS: - return ADDON_INSTANCE_VERSION_VFS_MIN; - case ADDON_INSTANCE_VISUALIZATION: - return ADDON_INSTANCE_VERSION_VISUALIZATION_MIN; - case ADDON_INSTANCE_VIDEOCODEC: - return ADDON_INSTANCE_VERSION_VIDEOCODEC_MIN; - } - return "0.0.0"; -} - -/// -/// Function used internally on add-on and in Kodi itself to get name -/// about given type. -/// -/// @param[in] type The with 'enum ADDON_TYPE' defined type to ask -/// @return Name of the asked instance type -/// -inline const char* GetTypeName(int type) -{ - switch (type) - { - /* addon global parts */ - case ADDON_GLOBAL_MAIN: - return "Addon"; - case ADDON_GLOBAL_GUI: - return "GUI"; - case ADDON_GLOBAL_GENERAL: - return "General"; - case ADDON_GLOBAL_AUDIOENGINE: - return "AudioEngine"; - case ADDON_GLOBAL_FILESYSTEM: - return "Filesystem"; - case ADDON_GLOBAL_NETWORK: - return "Network"; - case ADDON_GLOBAL_TOOLS: - return "Tools"; - - /* addon type instances */ - case ADDON_INSTANCE_AUDIODECODER: - return "AudioDecoder"; - case ADDON_INSTANCE_AUDIOENCODER: - return "AudioEncoder"; - case ADDON_INSTANCE_GAME: - return "Game"; - case ADDON_INSTANCE_IMAGEDECODER: - return "ImageDecoder"; - case ADDON_INSTANCE_INPUTSTREAM: - return "Inputstream"; - case ADDON_INSTANCE_PERIPHERAL: - return "Peripheral"; - case ADDON_INSTANCE_PVR: - return "PVR"; - case ADDON_INSTANCE_SCREENSAVER: - return "ScreenSaver"; - case ADDON_INSTANCE_VISUALIZATION: - return "Visualization"; - case ADDON_INSTANCE_VIDEOCODEC: - return "VideoCodec"; - } - return "unknown"; -} - -/// -/// Function used internally on add-on and in Kodi itself to get id number -/// about given type name. -/// -/// @param[in] name The type name string to ask -/// @return Id number of the asked instance type -/// -/// @warning String must be lower case here! -/// -inline int GetTypeId(const char* name) -{ - if (name) - { - if (strcmp(name, "addon") == 0) - return ADDON_GLOBAL_MAIN; - else if (strcmp(name, "general") == 0) - return ADDON_GLOBAL_GENERAL; - else if (strcmp(name, "gui") == 0) - return ADDON_GLOBAL_GUI; - else if (strcmp(name, "audioengine") == 0) - return ADDON_GLOBAL_AUDIOENGINE; - else if (strcmp(name, "filesystem") == 0) - return ADDON_GLOBAL_FILESYSTEM; - else if (strcmp(name, "network") == 0) - return ADDON_GLOBAL_NETWORK; - else if (strcmp(name, "tools") == 0) - return ADDON_GLOBAL_TOOLS; - else if (strcmp(name, "audiodecoder") == 0) - return ADDON_INSTANCE_AUDIODECODER; - else if (strcmp(name, "audioencoder") == 0) - return ADDON_INSTANCE_AUDIOENCODER; - else if (strcmp(name, "game") == 0) - return ADDON_INSTANCE_GAME; - else if (strcmp(name, "imagedecoder") == 0) - return ADDON_INSTANCE_IMAGEDECODER; - else if (strcmp(name, "inputstream") == 0) - return ADDON_INSTANCE_INPUTSTREAM; - else if (strcmp(name, "peripheral") == 0) - return ADDON_INSTANCE_PERIPHERAL; - else if (strcmp(name, "pvr") == 0) - return ADDON_INSTANCE_PVR; - else if (strcmp(name, "screensaver") == 0) - return ADDON_INSTANCE_SCREENSAVER; - else if (strcmp(name, "vfs") == 0) - return ADDON_INSTANCE_VFS; - else if (strcmp(name, "visualization") == 0) - return ADDON_INSTANCE_VISUALIZATION; - else if (strcmp(name, "videocodec") == 0) - return ADDON_INSTANCE_VIDEOCODEC; - } - return -1; -} - -#ifdef __cplusplus -} /* namespace addon */ -} /* namespace kodi */ -} /* extern "C" */ -#endif diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/AddonBase.h b/xbmc/addons/kodi-dev-kit/include/kodi/AddonBase.h new file mode 100644 index 0000000..6ab4159 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/AddonBase.h @@ -0,0 +1,1322 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "c-api/addon_base.h" +#include "versions.h" + +#include /* assert */ +#include /* va_list, va_start, va_arg, va_end */ + +#ifdef __cplusplus + +#include +#include +#include +#include +#include +#include +#include + +#include "tools/StringUtils.h" + +namespace kodi +{ + +namespace gui +{ +struct IRenderHelper; +} // namespace gui + +//============================================================================== +/// @ingroup cpp_kodi_Defs +/// @defgroup cpp_kodi_Defs_HardwareContext using HardwareContext +/// @brief **Hardware specific device context**\n +/// This defines an independent value which is used for hardware and OS specific +/// values. +/// +/// This is basically a simple pointer which has to be changed to the desired +/// format at the corresponding places using `static_cast<...>(...)`. +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// .. +/// // Note: Device() there is used inside addon child class about +/// // kodi::addon::CInstanceVisualization +/// ID3D11DeviceContext1* context = static_cast(kodi::addon::CInstanceVisualization::Device()); +/// .. +/// ~~~~~~~~~~~~~ +/// +///@{ +using HardwareContext = ADDON_HARDWARE_CONTEXT; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_addon_addonbase_Defs +/// @defgroup cpp_kodi_addon_addonbase_Defs_CSettingValue class CSettingValue +/// @brief Inside addon main instance used helper class to give settings value. +/// +/// This is used on @ref addon::CAddonBase::SetSetting() to inform addon about +/// settings change by used. This becomes then used to give the related value +/// name. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_addonbase_Defs_CSettingValue_Help +/// +/// ---------------------------------------------------------------------------- +/// +/// **Here is a code example how this is used:** +/// +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// enum myEnumValue +/// { +/// valueA, +/// valueB, +/// valueC +/// }; +/// +/// std::string m_myStringValue; +/// int m_myIntegerValue; +/// bool m_myBooleanValue; +/// float m_myFloatingPointValue; +/// myEnumValue m_myEnumValue; +/// +/// +/// ADDON_STATUS CMyAddon::SetSetting(const std::string& settingName, const kodi::CSettingValue& settingValue) +/// { +/// if (settingName == "my_string_value") +/// m_myStringValue = settingValue.GetString(); +/// else if (settingName == "my_integer_value") +/// m_myIntegerValue = settingValue.GetInt(); +/// else if (settingName == "my_boolean_value") +/// m_myBooleanValue = settingValue.GetBoolean(); +/// else if (settingName == "my_float_value") +/// m_myFloatingPointValue = settingValue.GetFloat(); +/// else if (settingName == "my_enum_value") +/// m_myEnumValue = settingValue.GetEnum(); +/// } +/// ~~~~~~~~~~~~~ +/// +/// @note The asked type should match the type used on settings.xml. +/// +///@{ +class ATTRIBUTE_HIDDEN CSettingValue +{ +public: + explicit CSettingValue(const void* settingValue) : m_settingValue(settingValue) {} + + bool empty() const { return (m_settingValue == nullptr) ? true : false; } + + /// @defgroup cpp_kodi_addon_addonbase_Defs_CSettingValue_Help Value Help + /// @ingroup cpp_kodi_addon_addonbase_Defs_CSettingValue + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_addonbase_Defs_CSettingValue : + /// | Name | Type | Get call + /// |------|------|---------- + /// | **Settings value as string** | `std::string` | @ref CSettingValue::GetString "GetString" + /// | **Settings value as integer** | `int` | @ref CSettingValue::GetInt "GetInt" + /// | **Settings value as unsigned integer** | `unsigned int` | @ref CSettingValue::GetUInt "GetUInt" + /// | **Settings value as boolean** | `bool` | @ref CSettingValue::GetBoolean "GetBoolean" + /// | **Settings value as floating point** | `float` | @ref CSettingValue::GetFloat "GetFloat" + /// | **Settings value as enum** | `enum` | @ref CSettingValue::GetEnum "GetEnum" + + /// @addtogroup cpp_kodi_addon_addonbase_Defs_CSettingValue + ///@{ + + /// @brief To get settings value as string. + std::string GetString() const { return (const char*)m_settingValue; } + + /// @brief To get settings value as integer. + int GetInt() const { return *(const int*)m_settingValue; } + + /// @brief To get settings value as unsigned integer. + unsigned int GetUInt() const { return *(const unsigned int*)m_settingValue; } + + /// @brief To get settings value as boolean. + bool GetBoolean() const { return *(const bool*)m_settingValue; } + + /// @brief To get settings value as floating point. + float GetFloat() const { return *(const float*)m_settingValue; } + + /// @brief To get settings value as enum. + /// @note Inside settings.xml them stored as integer. + template + enumType GetEnum() const + { + return static_cast(*(const int*)m_settingValue); + } + + ///@} + +private: + const void* m_settingValue; +}; +///@} +//------------------------------------------------------------------------------ + +namespace addon +{ + +//============================================================================== +/* + * Internal class to control various instance types with general parts defined + * here. + * + * Mainly is this currently used to identify requested instance types. + * + * @note This class is not need to know during add-on development thats why + * commented with "*". + */ +class ATTRIBUTE_HIDDEN IAddonInstance +{ +public: + explicit IAddonInstance(ADDON_TYPE type, const std::string& version) + : m_type(type), m_kodiVersion(version) + { + } + virtual ~IAddonInstance() = default; + + virtual ADDON_STATUS CreateInstance(int instanceType, + const std::string& instanceID, + KODI_HANDLE instance, + const std::string& version, + KODI_HANDLE& addonInstance) + { + return ADDON_STATUS_NOT_IMPLEMENTED; + } + + const ADDON_TYPE m_type; + const std::string m_kodiVersion; + std::string m_id; +}; + +/* + * Internally used helper class to manage processing of a "C" structure in "CPP" + * class. + * + * At constant, the "C" structure is copied, otherwise the given pointer is + * superseded and is changeable. + * + * ----------------------------------------------------------------------------- + * + * Example: + * + * ~~~~~~~~~~~~~{.cpp} + * extern "C" typedef struct C_SAMPLE_DATA + * { + * unsigned int iUniqueId; + * } C_SAMPLE_DATA; + * + * class CPPSampleData : public CStructHdl + * { + * public: + * CPPSampleData() = default; + * CPPSampleData(const CPPSampleData& sample) : CStructHdl(sample) { } + * CPPSampleData(const C_SAMPLE_DATA* sample) : CStructHdl(sample) { } + * CPPSampleData(C_SAMPLE_DATA* sample) : CStructHdl(sample) { } + * + * void SetUniqueId(unsigned int uniqueId) { m_cStructure->iUniqueId = uniqueId; } + * unsigned int GetUniqueId() const { return m_cStructure->iUniqueId; } + * }; + * + * ~~~~~~~~~~~~~ + * + * It also works with the following example: + * + * ~~~~~~~~~~~~~{.cpp} + * CPPSampleData test; + * // Some work + * C_SAMPLE_DATA* data = test; + * // Give "data" to Kodi + * ~~~~~~~~~~~~~ + */ +template +class CStructHdl +{ +public: + CStructHdl() : m_cStructure(new C_STRUCT()), m_owner(true) {} + + CStructHdl(const CPP_CLASS& cppClass) + : m_cStructure(new C_STRUCT(*cppClass.m_cStructure)), m_owner(true) + { + } + + CStructHdl(const C_STRUCT* cStructure) : m_cStructure(new C_STRUCT(*cStructure)), m_owner(true) {} + + CStructHdl(C_STRUCT* cStructure) : m_cStructure(cStructure) { assert(cStructure); } + + const CStructHdl& operator=(const CStructHdl& right) + { + assert(&right.m_cStructure); + if (m_cStructure && !m_owner) + { + memcpy(m_cStructure, right.m_cStructure, sizeof(C_STRUCT)); + } + else + { + if (m_owner) + delete m_cStructure; + m_owner = true; + m_cStructure = new C_STRUCT(*right.m_cStructure); + } + return *this; + } + + const CStructHdl& operator=(const C_STRUCT& right) + { + assert(&right); + if (m_cStructure && !m_owner) + { + memcpy(m_cStructure, &right, sizeof(C_STRUCT)); + } + else + { + if (m_owner) + delete m_cStructure; + m_owner = true; + m_cStructure = new C_STRUCT(*right); + } + return *this; + } + + virtual ~CStructHdl() + { + if (m_owner) + delete m_cStructure; + } + + operator C_STRUCT*() { return m_cStructure; } + operator const C_STRUCT*() const { return m_cStructure; } + + const C_STRUCT* GetCStructure() const { return m_cStructure; } + +protected: + C_STRUCT* m_cStructure = nullptr; + +private: + bool m_owner = false; +}; + +/// Add-on main instance class. +class ATTRIBUTE_HIDDEN CAddonBase +{ +public: + CAddonBase() + { + m_interface->toAddon->destroy = ADDONBASE_Destroy; + m_interface->toAddon->get_status = ADDONBASE_GetStatus; + m_interface->toAddon->create_instance = ADDONBASE_CreateInstance; + m_interface->toAddon->destroy_instance = ADDONBASE_DestroyInstance; + m_interface->toAddon->set_setting = ADDONBASE_SetSetting; + } + + virtual ~CAddonBase() = default; + + virtual ADDON_STATUS Create() { return ADDON_STATUS_OK; } + + virtual ADDON_STATUS GetStatus() { return ADDON_STATUS_OK; } + + //============================================================================ + /// @ingroup cpp_kodi_addon_addonbase + /// @brief To inform addon about changed settings values. + /// + /// This becomes called for every entry defined inside his settings.xml and + /// as **last** call the one where last in xml (to identify end of calls). + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_addonbase_Defs_CSettingValue_Help + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Here is a code example how this is used:** + /// + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// enum myEnumValue + /// { + /// valueA, + /// valueB, + /// valueC + /// }; + /// + /// std::string m_myStringValue; + /// int m_myIntegerValue; + /// bool m_myBooleanValue; + /// float m_myFloatingPointValue; + /// myEnumValue m_myEnumValue; + /// + /// + /// ADDON_STATUS CMyAddon::SetSetting(const std::string& settingName, const kodi::CSettingValue& settingValue) + /// { + /// if (settingName == "my_string_value") + /// m_myStringValue = settingValue.GetString(); + /// else if (settingName == "my_integer_value") + /// m_myIntegerValue = settingValue.GetInt(); + /// else if (settingName == "my_boolean_value") + /// m_myBooleanValue = settingValue.GetBoolean(); + /// else if (settingName == "my_float_value") + /// m_myFloatingPointValue = settingValue.GetFloat(); + /// else if (settingName == "my_enum_value") + /// m_myEnumValue = settingValue.GetEnum(); + /// } + /// ~~~~~~~~~~~~~ + /// + /// @note The asked type should match the type used on settings.xml. + /// + virtual ADDON_STATUS SetSetting(const std::string& settingName, + const kodi::CSettingValue& settingValue) + { + return ADDON_STATUS_UNKNOWN; + } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_addon_addonbase + /// @brief Instance created + /// + /// @param[in] instanceType The requested type of required instance, see \ref ADDON_TYPE. + /// @param[in] instanceID An individual identification key string given by Kodi. + /// @param[in] instance The instance handler used by Kodi must be passed to + /// the classes created here. See in the example. + /// @param[in] version The from Kodi used version of instance. This can be + /// used to allow compatibility to older versions of + /// them. Further is this given to the parent instance + /// that it can handle differences. + /// @param[out] addonInstance The pointer to instance class created in addon. + /// Needed to be able to identify them on calls. + /// @return \ref ADDON_STATUS_OK if correct, for possible errors + /// see \ref ADDON_STATUS + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Here is a code example how this is used:** + /// + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// ... + /// + /// /* If you use only one instance in your add-on, can be instanceType and + /// * instanceID ignored */ + /// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, + /// const std::string& instanceID, + /// KODI_HANDLE instance, + /// const std::string& version, + /// KODI_HANDLE& addonInstance) + /// { + /// if (instanceType == ADDON_INSTANCE_SCREENSAVER) + /// { + /// kodi::Log(ADDON_LOG_INFO, "Creating my Screensaver"); + /// addonInstance = new CMyScreensaver(instance); + /// return ADDON_STATUS_OK; + /// } + /// else if (instanceType == ADDON_INSTANCE_VISUALIZATION) + /// { + /// kodi::Log(ADDON_LOG_INFO, "Creating my Visualization"); + /// addonInstance = new CMyVisualization(instance); + /// return ADDON_STATUS_OK; + /// } + /// else if (...) + /// { + /// ... + /// } + /// return ADDON_STATUS_UNKNOWN; + /// } + /// + /// ... + /// + /// ~~~~~~~~~~~~~ + /// + virtual ADDON_STATUS CreateInstance(int instanceType, + const std::string& instanceID, + KODI_HANDLE instance, + const std::string& version, + KODI_HANDLE& addonInstance) + { + return ADDON_STATUS_NOT_IMPLEMENTED; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_addon_addonbase + /// @brief Instance destroy + /// + /// This function is optional and intended to notify addon that the instance + /// is terminating. + /// + /// @param[in] instanceType The requested type of required instance, see \ref ADDON_TYPE. + /// @param[in] instanceID An individual identification key string given by Kodi. + /// @param[in] addonInstance The pointer to instance class created in addon. + /// + /// @warning This call is only used to inform that the associated instance + /// is terminated. The deletion is carried out in the background. + /// + virtual void DestroyInstance(int instanceType, + const std::string& instanceID, + KODI_HANDLE addonInstance) + { + } + //-------------------------------------------------------------------------- + + /* Background helper for GUI render systems, e.g. Screensaver or Visualization */ + std::shared_ptr m_renderHelper; + + /* Global variables of class */ + static AddonGlobalInterface* + m_interface; // Interface function table to hold addresses on add-on and from kodi + + /*private:*/ /* Needed public as long the old call functions becomes used! */ + static inline void ADDONBASE_Destroy() + { + delete static_cast(m_interface->addonBase); + m_interface->addonBase = nullptr; + } + + static inline ADDON_STATUS ADDONBASE_GetStatus() + { + return static_cast(m_interface->addonBase)->GetStatus(); + } + + static inline ADDON_STATUS ADDONBASE_SetSetting(const char* settingName, const void* settingValue) + { + return static_cast(m_interface->addonBase) + ->SetSetting(settingName, CSettingValue(settingValue)); + } + +private: + static inline ADDON_STATUS ADDONBASE_CreateInstance(int instanceType, + const char* instanceID, + KODI_HANDLE instance, + const char* version, + KODI_HANDLE* addonInstance, + KODI_HANDLE parent) + { + CAddonBase* base = static_cast(m_interface->addonBase); + + ADDON_STATUS status = ADDON_STATUS_NOT_IMPLEMENTED; + + /* Check about single instance usage: + * 1. The kodi side instance pointer must be equal to first one + * 2. The addon side instance pointer must be set + * 3. And the requested type must be equal with used add-on class + */ + if (m_interface->firstKodiInstance == instance && m_interface->globalSingleInstance && + static_cast(m_interface->globalSingleInstance)->m_type == instanceType) + { + /* The handling here is intended for the case of the add-on only one + * instance and this is integrated in the add-on base class. + */ + *addonInstance = m_interface->globalSingleInstance; + status = ADDON_STATUS_OK; + } + else + { + /* Here it should use the CreateInstance instance function to allow + * creation of several on one addon. + */ + + /* Check first a parent is defined about (e.g. Codec within inputstream) */ + if (parent != nullptr) + status = static_cast(parent)->CreateInstance( + instanceType, instanceID, instance, version, *addonInstance); + + /* if no parent call the main instance creation function to get it */ + if (status == ADDON_STATUS_NOT_IMPLEMENTED) + { + status = base->CreateInstance(instanceType, instanceID, instance, version, *addonInstance); + } + } + + if (*addonInstance == nullptr) + { + if (status == ADDON_STATUS_OK) + { + m_interface->toKodi->addon_log_msg(m_interface->toKodi->kodiBase, ADDON_LOG_FATAL, + "kodi::addon::CAddonBase CreateInstance returned an " + "empty instance pointer, but reported OK!"); + return ADDON_STATUS_PERMANENT_FAILURE; + } + else + { + return status; + } + } + + if (static_cast(*addonInstance)->m_type != instanceType) + { + m_interface->toKodi->addon_log_msg( + m_interface->toKodi->kodiBase, ADDON_LOG_FATAL, + "kodi::addon::CAddonBase CreateInstance difference between given and returned"); + delete static_cast(*addonInstance); + *addonInstance = nullptr; + return ADDON_STATUS_PERMANENT_FAILURE; + } + + // Store the used ID inside instance, to have on destroy calls by addon to identify + static_cast(*addonInstance)->m_id = instanceID; + + return status; + } + + static inline void ADDONBASE_DestroyInstance(int instanceType, KODI_HANDLE instance) + { + CAddonBase* base = static_cast(m_interface->addonBase); + + if (m_interface->globalSingleInstance == nullptr && instance != base) + { + base->DestroyInstance(instanceType, static_cast(instance)->m_id, instance); + delete static_cast(instance); + } + } +}; + +} /* namespace addon */ + +//============================================================================== +/// @ingroup cpp_kodi_addon +/// @brief To get used version inside Kodi itself about asked type. +/// +/// This thought to allow a addon a handling of newer addon versions within +/// older Kodi until the type min version not changed. +/// +/// @param[in] type The wanted type of @ref ADDON_TYPE to ask +/// @return The version string about type in MAJOR.MINOR.PATCH style. +/// +inline std::string ATTRIBUTE_HIDDEN GetKodiTypeVersion(int type) +{ + using namespace kodi::addon; + + char* str = CAddonBase::m_interface->toKodi->get_type_version( + CAddonBase::m_interface->toKodi->kodiBase, type); + std::string ret = str; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, str); + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// +inline std::string ATTRIBUTE_HIDDEN GetAddonPath(const std::string& append = "") +{ + using namespace kodi::addon; + + char* str = + CAddonBase::m_interface->toKodi->get_addon_path(CAddonBase::m_interface->toKodi->kodiBase); + std::string ret = str; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, str); + if (!append.empty()) + { + if (append.at(0) != '\\' && append.at(0) != '/') +#ifdef TARGET_WINDOWS + ret.append("\\"); +#else + ret.append("/"); +#endif + ret.append(append); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// +inline std::string ATTRIBUTE_HIDDEN GetBaseUserPath(const std::string& append = "") +{ + using namespace kodi::addon; + + char* str = CAddonBase::m_interface->toKodi->get_base_user_path( + CAddonBase::m_interface->toKodi->kodiBase); + std::string ret = str; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, str); + if (!append.empty()) + { + if (append.at(0) != '\\' && append.at(0) != '/') +#ifdef TARGET_WINDOWS + ret.append("\\"); +#else + ret.append("/"); +#endif + ret.append(append); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// +inline std::string ATTRIBUTE_HIDDEN GetLibPath() +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->libBasePath; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi +/// @brief Add a message to Kodi's log. +/// +/// @param[in] loglevel The log level of the message. +/// @param[in] format The format of the message to pass to Kodi. +/// @param[in] ... Additional text to insert in format text +/// +/// +/// @note This method uses limited buffer (16k) for the formatted output. +/// So data, which will not fit into it, will be silently discarded. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// kodi::Log(ADDON_LOG_ERROR, "%s: There is an error occurred!", __func__); +/// +/// ~~~~~~~~~~~~~ +/// +inline void ATTRIBUTE_HIDDEN Log(const AddonLog loglevel, const char* format, ...) +{ + using namespace kodi::addon; + + va_list args; + va_start(args, format); + const std::string str = kodi::tools::StringUtils::FormatV(format, args); + va_end(args); + CAddonBase::m_interface->toKodi->addon_log_msg(CAddonBase::m_interface->toKodi->kodiBase, + loglevel, str.c_str()); +} +//------------------------------------------------------------------------------ + +//############################################################################## +/// @ingroup cpp_kodi +/// @defgroup cpp_kodi_settings 1. Setting control +/// @brief **Functions to handle settings access**\n +/// This can be used to get and set the addon related values inside his +/// settings.xml. +/// +/// The settings style is given with installed part on e.g. +/// `$HOME/.kodi/addons/myspecial.addon/resources/settings.xml`. The +/// related edit becomes then stored inside +/// `$HOME/.kodi/userdata/addon_data/myspecial.addon/settings.xml`. +/// +/*!@{*/ + +//============================================================================== +/// @brief Check the given setting name is set to default value. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of asked setting +/// @return true if setting is the default +/// +inline bool ATTRIBUTE_HIDDEN IsSettingUsingDefault(const std::string& settingName) +{ + using namespace kodi::addon; + return CAddonBase::m_interface->toKodi->is_setting_using_default( + CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Check and get a string setting value. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of asked setting +/// @param[out] settingValue The given setting value +/// @return true if setting was successfully found and "settingValue" is set +/// +/// @note If returns false, the "settingValue" is not changed. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// std::string value; +/// if (!kodi::CheckSettingString("my_string_value", value)) +/// value = "my_default_if_setting_not_work"; +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN CheckSettingString(const std::string& settingName, + std::string& settingValue) +{ + using namespace kodi::addon; + + char* buffer = nullptr; + bool ret = CAddonBase::m_interface->toKodi->get_setting_string( + CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), &buffer); + if (buffer) + { + if (ret) + settingValue = buffer; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, buffer); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Get string setting value. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of asked setting +/// @param[in] defaultValue [opt] Default value if not found +/// @return The value of setting, empty if not found; +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// std::string value = kodi::GetSettingString("my_string_value"); +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN GetSettingString(const std::string& settingName, + const std::string& defaultValue = "") +{ + std::string settingValue = defaultValue; + CheckSettingString(settingName, settingValue); + return settingValue; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Set string setting of addon. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of setting +/// @param[in] settingValue The setting value to write +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// std::string value = "my_new_name for"; +/// kodi::SetSettingString("my_string_value", value); +/// ~~~~~~~~~~~~~ +/// +inline void ATTRIBUTE_HIDDEN SetSettingString(const std::string& settingName, + const std::string& settingValue) +{ + using namespace kodi::addon; + + CAddonBase::m_interface->toKodi->set_setting_string(CAddonBase::m_interface->toKodi->kodiBase, + settingName.c_str(), settingValue.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Check and get a integer setting value. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of asked setting +/// @param[out] settingValue The given setting value +/// @return true if setting was successfully found and "settingValue" is set +/// +/// @note If returns false, the "settingValue" is not changed. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// int value = 0; +/// if (!kodi::CheckSettingInt("my_integer_value", value)) +/// value = 123; // My default of them +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN CheckSettingInt(const std::string& settingName, int& settingValue) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->get_setting_int(CAddonBase::m_interface->toKodi->kodiBase, + settingName.c_str(), &settingValue); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Get integer setting value. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of asked setting +/// @param[in] defaultValue [opt] Default value if not found +/// @return The value of setting, `0` or defaultValue if not found +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// int value = kodi::GetSettingInt("my_integer_value"); +/// ~~~~~~~~~~~~~ +/// +inline int ATTRIBUTE_HIDDEN GetSettingInt(const std::string& settingName, int defaultValue = 0) +{ + int settingValue = defaultValue; + CheckSettingInt(settingName, settingValue); + return settingValue; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Set integer setting of addon. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of setting +/// @param[in] settingValue The setting value to write +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// int value = 123; +/// kodi::SetSettingInt("my_integer_value", value); +/// ~~~~~~~~~~~~~ +/// +inline void ATTRIBUTE_HIDDEN SetSettingInt(const std::string& settingName, int settingValue) +{ + using namespace kodi::addon; + + CAddonBase::m_interface->toKodi->set_setting_int(CAddonBase::m_interface->toKodi->kodiBase, + settingName.c_str(), settingValue); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Check and get a boolean setting value. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of asked setting +/// @param[out] settingValue The given setting value +/// @return true if setting was successfully found and "settingValue" is set +/// +/// @note If returns false, the "settingValue" is not changed. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// bool value = false; +/// if (!kodi::CheckSettingBoolean("my_boolean_value", value)) +/// value = true; // My default of them +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN CheckSettingBoolean(const std::string& settingName, bool& settingValue) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->get_setting_bool( + CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), &settingValue); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Get boolean setting value. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of asked setting +/// @param[in] defaultValue [opt] Default value if not found +/// @return The value of setting, `false` or defaultValue if not found +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// bool value = kodi::GetSettingBoolean("my_boolean_value"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN GetSettingBoolean(const std::string& settingName, + bool defaultValue = false) +{ + bool settingValue = defaultValue; + CheckSettingBoolean(settingName, settingValue); + return settingValue; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Set boolean setting of addon. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of setting +/// @param[in] settingValue The setting value to write +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// bool value = true; +/// kodi::SetSettingBoolean("my_boolean_value", value); +/// ~~~~~~~~~~~~~ +/// +inline void ATTRIBUTE_HIDDEN SetSettingBoolean(const std::string& settingName, bool settingValue) +{ + using namespace kodi::addon; + + CAddonBase::m_interface->toKodi->set_setting_bool(CAddonBase::m_interface->toKodi->kodiBase, + settingName.c_str(), settingValue); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Check and get a floating point setting value. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of asked setting +/// @param[out] settingValue The given setting value +/// @return true if setting was successfully found and "settingValue" is set +/// +/// @note If returns false, the "settingValue" is not changed. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// float value = 0.0f; +/// if (!kodi::CheckSettingBoolean("my_float_value", value)) +/// value = 1.0f; // My default of them +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN CheckSettingFloat(const std::string& settingName, float& settingValue) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->get_setting_float( + CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), &settingValue); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Get floating point setting value. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of asked setting +/// @param[in] defaultValue [opt] Default value if not found +/// @return The value of setting, `0.0` or defaultValue if not found +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// float value = kodi::GetSettingFloat("my_float_value"); +/// ~~~~~~~~~~~~~ +/// +inline float ATTRIBUTE_HIDDEN GetSettingFloat(const std::string& settingName, + float defaultValue = 0.0f) +{ + float settingValue = defaultValue; + CheckSettingFloat(settingName, settingValue); + return settingValue; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Set floating point setting of addon. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of setting +/// @param[in] settingValue The setting value to write +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// float value = 1.0f; +/// kodi::SetSettingFloat("my_float_value", value); +/// ~~~~~~~~~~~~~ +/// +inline void ATTRIBUTE_HIDDEN SetSettingFloat(const std::string& settingName, float settingValue) +{ + using namespace kodi::addon; + + CAddonBase::m_interface->toKodi->set_setting_float(CAddonBase::m_interface->toKodi->kodiBase, + settingName.c_str(), settingValue); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Check and get a enum setting value. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of asked setting +/// @param[out] settingValue The given setting value +/// @return true if setting was successfully found and "settingValue" is set +/// +/// @remark The enums are used as integer inside settings.xml. +/// @note If returns false, the "settingValue" is not changed. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// enum myEnumValue +/// { +/// valueA, +/// valueB, +/// valueC +/// }; +/// +/// myEnumValue value; +/// if (!kodi::CheckSettingEnum("my_enum_value", value)) +/// value = valueA; // My default of them +/// ~~~~~~~~~~~~~ +/// +template +inline bool ATTRIBUTE_HIDDEN CheckSettingEnum(const std::string& settingName, + enumType& settingValue) +{ + using namespace kodi::addon; + + int settingValueInt = static_cast(settingValue); + bool ret = CAddonBase::m_interface->toKodi->get_setting_int( + CAddonBase::m_interface->toKodi->kodiBase, settingName.c_str(), &settingValueInt); + if (ret) + settingValue = static_cast(settingValueInt); + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Get enum setting value. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of asked setting +/// @param[in] defaultValue [opt] Default value if not found +/// @return The value of setting, forced to `0` or defaultValue if not found +/// +/// @remark The enums are used as integer inside settings.xml. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// enum myEnumValue +/// { +/// valueA, +/// valueB, +/// valueC +/// }; +/// +/// myEnumValue value = kodi::GetSettingEnum("my_enum_value"); +/// ~~~~~~~~~~~~~ +/// +template +inline enumType ATTRIBUTE_HIDDEN GetSettingEnum(const std::string& settingName, + enumType defaultValue = static_cast(0)) +{ + enumType settingValue = defaultValue; + CheckSettingEnum(settingName, settingValue); + return settingValue; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief Set enum setting of addon. +/// +/// The setting name relate to names used in his settings.xml file. +/// +/// @param[in] settingName The name of setting +/// @param[in] settingValue The setting value to write +/// +/// @remark The enums are used as integer inside settings.xml. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// enum myEnumValue +/// { +/// valueA, +/// valueB, +/// valueC +/// }; +/// +/// myEnumValue value = valueA; +/// kodi::SetSettingEnum("my_enum_value", value); +/// ~~~~~~~~~~~~~ +/// +template +inline void ATTRIBUTE_HIDDEN SetSettingEnum(const std::string& settingName, enumType settingValue) +{ + using namespace kodi::addon; + + CAddonBase::m_interface->toKodi->set_setting_int(CAddonBase::m_interface->toKodi->kodiBase, + settingName.c_str(), + static_cast(settingValue)); +} +//------------------------------------------------------------------------------ + +/*!@}*/ + +//============================================================================ +/// +inline std::string ATTRIBUTE_HIDDEN TranslateAddonStatus(ADDON_STATUS status) +{ + switch (status) + { + case ADDON_STATUS_OK: + return "OK"; + case ADDON_STATUS_LOST_CONNECTION: + return "Lost Connection"; + case ADDON_STATUS_NEED_RESTART: + return "Need Restart"; + case ADDON_STATUS_NEED_SETTINGS: + return "Need Settings"; + case ADDON_STATUS_UNKNOWN: + return "Unknown error"; + case ADDON_STATUS_PERMANENT_FAILURE: + return "Permanent failure"; + case ADDON_STATUS_NOT_IMPLEMENTED: + return "Not implemented"; + default: + break; + } + return "Unknown"; +} +//---------------------------------------------------------------------------- + +//============================================================================== +/// @ingroup cpp_kodi +/// @brief Returns a function table to a named interface +/// +/// @return pointer to struct containing interface functions +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// #include +/// ... +/// FuncTable_foo *table = kodi::GetPlatformInfo(foo_name, foo_version); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline void* GetInterface(const std::string& name, const std::string& version) +{ + using namespace kodi::addon; + + AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; + + return toKodi->get_interface(toKodi->kodiBase, name.c_str(), version.c_str()); +} +//---------------------------------------------------------------------------- + +} /* namespace kodi */ + +/*! addon creation macro + * @todo cleanup this stupid big macro + * This macro includes now all for add-on's needed functions. This becomes a bigger + * rework after everything is done on Kodi itself, currently is this way needed + * to have compatibility with not reworked interfaces. + * + * Becomes really cleaned up soon :D + */ +#define ADDONCREATOR(AddonClass) \ + extern "C" __declspec(dllexport) ADDON_STATUS ADDON_Create( \ + KODI_HANDLE addonInterface, const char* /*globalApiVersion*/, void* /*unused*/) \ + { \ + kodi::addon::CAddonBase::m_interface = static_cast(addonInterface); \ + kodi::addon::CAddonBase::m_interface->addonBase = new AddonClass; \ + return static_cast(kodi::addon::CAddonBase::m_interface->addonBase) \ + ->Create(); \ + } \ + extern "C" __declspec(dllexport) void ADDON_Destroy() \ + { \ + kodi::addon::CAddonBase::ADDONBASE_Destroy(); \ + } \ + extern "C" __declspec(dllexport) ADDON_STATUS ADDON_GetStatus() \ + { \ + return kodi::addon::CAddonBase::ADDONBASE_GetStatus(); \ + } \ + extern "C" __declspec(dllexport) ADDON_STATUS ADDON_SetSetting(const char* settingName, \ + const void* settingValue) \ + { \ + return kodi::addon::CAddonBase::ADDONBASE_SetSetting(settingName, settingValue); \ + } \ + extern "C" __declspec(dllexport) const char* ADDON_GetTypeVersion(int type) \ + { \ + return kodi::addon::GetTypeVersion(type); \ + } \ + extern "C" __declspec(dllexport) const char* ADDON_GetTypeMinVersion(int type) \ + { \ + return kodi::addon::GetTypeMinVersion(type); \ + } \ + AddonGlobalInterface* kodi::addon::CAddonBase::m_interface = nullptr; + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/AudioEngine.h b/xbmc/addons/kodi-dev-kit/include/kodi/AudioEngine.h new file mode 100644 index 0000000..36d1dd1 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/AudioEngine.h @@ -0,0 +1,619 @@ +/* + * Copyright (C) 2005-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "AddonBase.h" +#include "c-api/audio_engine.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace audioengine +{ + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// Main page text for audio engine group by Doxygen. +//{{{ + +//============================================================================== +/// +/// @defgroup cpp_kodi_audioengine Interface - kodi::audioengine +/// @ingroup cpp +/// @brief **Audio engine functions**\n +/// This interface contains auxiliary functions and classes which allow an addon +/// to play their own individual audio stream in Kodi. +/// +/// Using @ref cpp_kodi_audioengine_CAEStream "kodi::audioengine::CAEStream", +/// a class can be created in this regard, about which the necessary stream data and +/// information are given to Kodi. +/// +/// Via @ref kodi::audioengine::GetCurrentSinkFormat(), the audio formats currently +/// processed in Kodi can be called up beforehand in order to adapt your own stream +/// to them. +/// +/// However, the created stream can also differ from this because Kodi changes +/// it to suit it. +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// +/// #include +/// +/// ... +/// +/// kodi::audioengine::AudioEngineFormat format; +/// if (!kodi::audioengine::GetCurrentSinkFormat(format)) +/// return false; +/// +/// format.SetDataFormat(AUDIOENGINE_FMT_FLOATP); +/// format.SetChannelLayout(std::vector(AUDIOENGINE_CH_FL, AUDIOENGINE_CH_FR)); +/// +/// unsigned int myUsedSampleRate = format.GetSampleRate(); +/// +/// ... +/// +/// kodi::audioengine::CAEStream* stream = new kodi::audioengine::CAEStream(format, AUDIO_STREAM_AUTOSTART); +/// +/// ~~~~~~~~~~~~~ +/// +/// ------------------------------------------------------------------------ +/// +/// It has the header \ref AudioEngine.h "#include " be included +/// to enjoy it. +/// +//------------------------------------------------------------------------------ + +//============================================================================== +/// +/// @defgroup cpp_kodi_audioengine_Defs Definitions, structures and enumerators +/// @ingroup cpp_kodi_audioengine +/// @brief **Library definition values**\n +/// All audio engine functions associated data structures. +/// +//------------------------------------------------------------------------------ + +//}}} + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" related audio engine definitions +//{{{ + +//============================================================================== +/// @defgroup cpp_kodi_audioengine_Defs_AudioEngineFormat class AudioEngineFormat +/// @ingroup cpp_kodi_audioengine_Defs +/// @brief **Audio format structure**\n +/// The audio format structure that fully defines a stream's audio +/// information. +/// +/// With the help of this format information, Kodi adjusts its processing +/// accordingly. +/// +///@{ +class ATTRIBUTE_HIDDEN AudioEngineFormat + : public addon::CStructHdl +{ +public: + /*! \cond PRIVATE */ + AudioEngineFormat() + { + m_cStructure->m_dataFormat = AUDIOENGINE_FMT_INVALID; + m_cStructure->m_sampleRate = 0; + m_cStructure->m_encodedRate = 0; + m_cStructure->m_frames = 0; + m_cStructure->m_frameSize = 0; + m_cStructure->m_channelCount = 0; + + for (size_t ch = 0; ch < AUDIOENGINE_CH_MAX; ++ch) + m_cStructure->m_channels[ch] = AUDIOENGINE_CH_NULL; + } + AudioEngineFormat(const AudioEngineFormat& channel) : CStructHdl(channel) {} + AudioEngineFormat(const AUDIO_ENGINE_FORMAT* channel) : CStructHdl(channel) {} + AudioEngineFormat(AUDIO_ENGINE_FORMAT* channel) : CStructHdl(channel) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_audioengine_Defs_AudioEngineFormat_Help *Value Help* + /// @ingroup cpp_kodi_audioengine_Defs_AudioEngineFormat + /// + /// The following table contains values that can be set with @ref cpp_kodi_audioengine_Defs_AudioEngineFormat : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **Data format**, see @ref AudioEngineDataFormat for available types | enum | @ref AudioEngineFormat::SetDataFormat "SetDataFormat" | @ref AudioEngineFormat::GetDataFormat "GetDataFormat" + /// | **Sample rate** | unsigned int | @ref AudioEngineFormat::SetSampleRate "SetSampleRate" | @ref AudioEngineFormat::GetSampleRate "GetSampleRate" + /// | **Encoded rate** | unsigned int | @ref AudioEngineFormat::SetEncodedRate "SetEncodedRate" | @ref AudioEngineFormat::GetEncodedRate "GetEncodedRate" + /// | **Channel layout**, see @ref AudioEngineChannel for available types | std::vector | @ref AudioEngineFormat::SetChannelLayout "SetChannelLayout" | @ref AudioEngineFormat::GetChannelLayout "GetChannelLayout" + /// | **Frames amount** | unsigned int | @ref AudioEngineFormat::SetFramesAmount "SetFramesAmount" | @ref AudioEngineFormat::GetFramesAmount "GetFramesAmount" + /// | **Frame size** | unsigned int | @ref AudioEngineFormat::SetFrameSize "SetFrameSize" | @ref AudioEngineFormat::GetFrameSize "GetFrameSize" + /// + /// Further is @ref AudioEngineFormat::CompareFormat "CompareFormat" included to compare this class with another. + /// + + /// @addtogroup cpp_kodi_audioengine_Defs_AudioEngineFormat + /// @copydetails cpp_kodi_audioengine_Defs_AudioEngineFormat_Help + ///@{ + + /// @brief The stream's data format (eg, AUDIOENGINE_FMT_S16LE) + void SetDataFormat(enum AudioEngineDataFormat format) { m_cStructure->m_dataFormat = format; } + + /// @brief To get with @ref SetDataFormat changed values. + enum AudioEngineDataFormat GetDataFormat() const { return m_cStructure->m_dataFormat; } + + /// @brief The stream's sample rate (eg, 48000) + void SetSampleRate(unsigned int rate) { m_cStructure->m_sampleRate = rate; } + + /// @brief To get with @ref SetSampleRate changed values. + unsigned int GetSampleRate() const { return m_cStructure->m_sampleRate; } + + /// @brief The encoded streams sample rate if a bitstream, otherwise undefined + void SetEncodedRate(unsigned int rate) { m_cStructure->m_encodedRate = rate; } + + /// @brief To get with @ref SetEncodedRate changed values. + unsigned int GetEncodedRate() const { return m_cStructure->m_encodedRate; } + + /// @brief The stream's channel layout + void SetChannelLayout(const std::vector& layout) + { + // Reset first all to empty values to AUDIOENGINE_CH_NULL, in case given list is empty + m_cStructure->m_channelCount = 0; + for (size_t ch = 0; ch < AUDIOENGINE_CH_MAX; ++ch) + m_cStructure->m_channels[ch] = AUDIOENGINE_CH_NULL; + + for (size_t ch = 0; ch < layout.size() && ch < AUDIOENGINE_CH_MAX; ++ch) + { + m_cStructure->m_channels[ch] = layout[ch]; + m_cStructure->m_channelCount++; + } + } + + /// @brief To get with @ref SetChannelLayout changed values. + std::vector GetChannelLayout() const + { + std::vector channels; + for (size_t ch = 0; ch < AUDIOENGINE_CH_MAX; ++ch) + { + if (m_cStructure->m_channels[ch] == AUDIOENGINE_CH_NULL) + break; + + channels.push_back(m_cStructure->m_channels[ch]); + } + return channels; + } + + /// @brief The number of frames per period + void SetFramesAmount(unsigned int frames) { m_cStructure->m_frames = frames; } + + /// @brief To get with @ref SetFramesAmount changed values. + unsigned int GetFramesAmount() const { return m_cStructure->m_frames; } + + /// @brief The size of one frame in bytes + void SetFrameSize(unsigned int frameSize) { m_cStructure->m_frameSize = frameSize; } + + /// @brief To get with @ref SetFrameSize changed values. + unsigned int GetFrameSize() const { return m_cStructure->m_frameSize; } + + /// @brief Function to compare the format structure with another + bool CompareFormat(const AudioEngineFormat* fmt) + { + if (!fmt) + { + return false; + } + + if (m_cStructure->m_dataFormat != fmt->m_cStructure->m_dataFormat || + m_cStructure->m_sampleRate != fmt->m_cStructure->m_sampleRate || + m_cStructure->m_encodedRate != fmt->m_cStructure->m_encodedRate || + m_cStructure->m_frames != fmt->m_cStructure->m_frames || + m_cStructure->m_frameSize != fmt->m_cStructure->m_frameSize || + m_cStructure->m_channelCount != fmt->m_cStructure->m_channelCount) + { + return false; + } + + for (unsigned int ch = 0; ch < AUDIOENGINE_CH_MAX; ++ch) + { + if (fmt->m_cStructure->m_channels[ch] != m_cStructure->m_channels[ch]) + { + return false; + } + } + + return true; + } + ///@} +}; +///@} +//---------------------------------------------------------------------------- + +//}}} + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" AudioEngine addon interface +//{{{ + +//============================================================================ +/// +/// @defgroup cpp_kodi_audioengine_CAEStream class CAEStream +/// @ingroup cpp_kodi_audioengine +/// @brief **Audio Engine Stream Class**\n +/// Class that can be created by the addon in order to be able to transfer +/// audiostream data processed on the addon to Kodi and output it audibly. +/// +/// This can create individually several times and performed in different +/// processes simultaneously. +/// +/// It has the header @ref AudioEngine.h "#include " be +/// included to enjoy it. +/// +//---------------------------------------------------------------------------- +class ATTRIBUTE_HIDDEN CAEStream +{ +public: + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Contructs new class to an Kodi IAEStream in the format specified. + /// + /// @param[in] format The data format the incoming audio will be in + /// (e.g. \ref AUDIOENGINE_FMT_S16LE) + /// @param[in] options [opt] A bit field of stream options (see: enum \ref AudioEngineStreamOptions) + /// + /// + /// ------------------------------------------------------------------------ + /// + /// @copydetails cpp_kodi_audioengine_Defs_AudioEngineFormat_Help + /// + /// ------------------------------------------------------------------------ + /// + /// **Bit options to pass (on Kodi by IAE::MakeStream)** + /// + /// | enum AEStreamOptions | Value: | Description: + /// |----------------------------:|:------:|:----------------------------------- + /// | AUDIO_STREAM_FORCE_RESAMPLE | 1 << 0 | Force resample even if rates match + /// | AUDIO_STREAM_PAUSED | 1 << 1 | Create the stream paused + /// | AUDIO_STREAM_AUTOSTART | 1 << 2 | Autostart the stream when enough data is buffered + /// + /// + /// ------------------------------------------------------------------------ + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// + /// #include + /// + /// ... + /// + /// kodi::audioengine::AudioEngineFormat format; + /// + /// format.SetDataFormat(AUDIOENGINE_FMT_FLOATP); /* The stream's data format (eg, AUDIOENGINE_FMT_S16LE) */ + /// format.SetChannelLayout(std::vector(AUDIOENGINE_CH_FL, AUDIOENGINE_CH_FR)); /* The stream's channel layout */ + /// format.SetSampleRate(48000); /* The stream's sample rate (eg, 48000) */ + /// format.SetFrameSize(sizeof(float)*2); /* The size of one frame in bytes */ + /// format.SetFramesAmount(882); /* The number of samples in one frame */ + /// + /// kodi::audioengine::CAEStream* stream = new kodi::audioengine::CAEStream(format, AUDIO_STREAM_AUTOSTART); + /// + /// ~~~~~~~~~~~~~ + /// + CAEStream(AudioEngineFormat& format, unsigned int options = 0) + : m_kodiBase(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase), + m_cb(::kodi::addon::CAddonBase::m_interface->toKodi->kodi_audioengine) + { + m_StreamHandle = m_cb->make_stream(m_kodiBase, format, options); + if (m_StreamHandle == nullptr) + { + kodi::Log(ADDON_LOG_FATAL, "CAEStream: make_stream failed!"); + } + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Class destructor. + /// + ~CAEStream() + { + if (m_StreamHandle) + { + m_cb->free_stream(m_kodiBase, m_StreamHandle); + m_StreamHandle = nullptr; + } + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Returns the amount of space available in the stream. + /// + /// @return The number of bytes AddData will consume + /// + unsigned int GetSpace() { return m_cb->aestream_get_space(m_kodiBase, m_StreamHandle); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Add planar or interleaved PCM data to the stream. + /// + /// @param[in] data array of pointers to the planes + /// @param[in] offset to frame in frames + /// @param[in] frames number of frames + /// @param[in] pts [opt] presentation timestamp, default is 0 + /// @param[in] hasDownmix [opt] set true if downmix is present, default is false + /// @param[in] centerMixLevel [opt] level to mix left and right to center default is 1.0 + /// @return The number of frames consumed + /// + unsigned int AddData(uint8_t* const* data, + unsigned int offset, + unsigned int frames, + double pts = 0, + bool hasDownmix = false, + double centerMixLevel = 1.0) + { + return m_cb->aestream_add_data(m_kodiBase, m_StreamHandle, data, offset, frames, pts, + hasDownmix, centerMixLevel); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Returns the time in seconds that it will take for the next added + /// packet to be heard from the speakers. + /// + /// @return seconds + /// + double GetDelay() { return m_cb->aestream_get_delay(m_kodiBase, m_StreamHandle); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Returns if the stream is buffering. + /// + /// @return True if the stream is buffering + /// + bool IsBuffering() { return m_cb->aestream_is_buffering(m_kodiBase, m_StreamHandle); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Returns the time in seconds of the stream's cached audio samples. + /// Engine buffers excluded. + /// + /// @return seconds + /// + double GetCacheTime() { return m_cb->aestream_get_cache_time(m_kodiBase, m_StreamHandle); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Returns the total time in seconds of the cache. + /// + /// @return seconds + /// + double GetCacheTotal() { return m_cb->aestream_get_cache_total(m_kodiBase, m_StreamHandle); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Pauses the stream playback. + /// + void Pause() { return m_cb->aestream_pause(m_kodiBase, m_StreamHandle); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Resumes the stream after pausing + /// + void Resume() { return m_cb->aestream_resume(m_kodiBase, m_StreamHandle); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Start draining the stream. + /// + /// @param[in] wait [opt] Wait until drain is finished if set to true, + /// otherwise it returns direct + /// + /// @note Once called AddData will not consume more data. + /// + void Drain(bool wait = true) { return m_cb->aestream_drain(m_kodiBase, m_StreamHandle, wait); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Returns true if the is stream draining. + /// + bool IsDraining() { return m_cb->aestream_is_draining(m_kodiBase, m_StreamHandle); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Returns true if the is stream has finished draining. + /// + bool IsDrained() { return m_cb->aestream_is_drained(m_kodiBase, m_StreamHandle); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Flush all buffers dropping the audio data. + /// + void Flush() { return m_cb->aestream_flush(m_kodiBase, m_StreamHandle); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Return the stream's current volume level. + /// + /// @return The volume level between 0.0 and 1.0 + /// + float GetVolume() { return m_cb->aestream_get_volume(m_kodiBase, m_StreamHandle); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Set the stream's volume level. + /// + /// @param[in] volume The new volume level between 0.0 and 1.0 + /// + void SetVolume(float volume) + { + return m_cb->aestream_set_volume(m_kodiBase, m_StreamHandle, volume); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Gets the stream's volume amplification in linear units. + /// + /// @return The volume amplification factor between 1.0 and 1000.0 + /// + float GetAmplification() { return m_cb->aestream_get_amplification(m_kodiBase, m_StreamHandle); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Sets the stream's volume amplification in linear units. + /// + /// @param[in] amplify The volume amplification factor between 1.0 and 1000.0 + /// + void SetAmplification(float amplify) + { + return m_cb->aestream_set_amplification(m_kodiBase, m_StreamHandle, amplify); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Returns the size of one audio frame in bytes (channelCount * resolution). + /// + /// @return The size in bytes of one frame + /// + unsigned int GetFrameSize() const + { + return m_cb->aestream_get_frame_size(m_kodiBase, m_StreamHandle); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Returns the number of channels the stream is configured to accept. + /// + /// @return The channel count + /// + unsigned int GetChannelCount() const + { + return m_cb->aestream_get_channel_count(m_kodiBase, m_StreamHandle); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Returns the stream's sample rate, if the stream is using a dynamic + /// sample rate, this value will NOT reflect any changes made by calls to + /// SetResampleRatio(). + /// + /// @return The stream's sample rate (eg, 48000) + /// + unsigned int GetSampleRate() const + { + return m_cb->aestream_get_sample_rate(m_kodiBase, m_StreamHandle); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Return the data format the stream has been configured with. + /// + /// @return The stream's data format (eg, AUDIOENGINE_FMT_S16LE) + /// + AudioEngineDataFormat GetDataFormat() const + { + return m_cb->aestream_get_data_format(m_kodiBase, m_StreamHandle); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Return the resample ratio. + /// + /// @note This will return an undefined value if the stream is not resampling. + /// + /// @return the current resample ratio or undefined if the stream is not resampling + /// + double GetResampleRatio() + { + return m_cb->aestream_get_resample_ratio(m_kodiBase, m_StreamHandle); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_audioengine_CAEStream + /// @brief Sets the resample ratio. + /// + /// @note This function may return false if the stream is not resampling, if + /// you wish to use this be sure to set the AESTREAM_FORCE_RESAMPLE option. + /// + /// @param[in] ratio the new sample rate ratio, calculated by + /// ((double)desiredRate / (double)GetSampleRate()) + /// + void SetResampleRatio(double ratio) + { + m_cb->aestream_set_resample_ratio(m_kodiBase, m_StreamHandle, ratio); + } + //-------------------------------------------------------------------------- + +private: + void* m_kodiBase; + AddonToKodiFuncTable_kodi_audioengine* m_cb; + AEStreamHandle* m_StreamHandle; +}; +//---------------------------------------------------------------------------- + +//============================================================================ +/// @ingroup cpp_kodi_audioengine +/// @brief Get the current sink data format. +/// +/// @param[in] format Current sink data format. For more details see AudioEngineFormat. +/// @return Returns true on success, else false. +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// +/// #include +/// +/// ... +/// +/// kodi::audioengine::AudioEngineFormat format; +/// if (!kodi::audioengine::GetCurrentSinkFormat(format)) +/// return false; +/// +/// std::vector layout = format.GetChannelLayout(); +/// +/// ... +/// return true; +/// +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN GetCurrentSinkFormat(AudioEngineFormat& format) +{ + using namespace kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_audioengine->get_current_sink_format( + CAddonBase::m_interface->toKodi->kodiBase, format); +} +//---------------------------------------------------------------------------- + +//}}} + +} // namespace audioengine +} // namespace kodi + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/CMakeLists.txt new file mode 100644 index 0000000..d37078a --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/CMakeLists.txt @@ -0,0 +1,16 @@ +set(HEADERS AddonBase.h + AudioEngine.h + Filesystem.h + General.h + Network.h + StreamCodec.h + StreamCrypto.h + versions.h) + +if(CORE_SYSTEM_NAME STREQUAL android) + list(APPEND SOURCES platform/android/System.h) +endif() + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/Filesystem.h b/xbmc/addons/kodi-dev-kit/include/kodi/Filesystem.h new file mode 100644 index 0000000..1cf05fe --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/Filesystem.h @@ -0,0 +1,2367 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "AddonBase.h" +#include "c-api/filesystem.h" + +#ifdef __cplusplus + +#include +#include +#include + +namespace kodi +{ +namespace vfs +{ + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// Main page text for filesystem group by Doxygen. +//{{{ + +//============================================================================== +/// +/// @defgroup cpp_kodi_vfs Interface - kodi::vfs +/// @ingroup cpp +/// @brief **Virtual filesystem functions**\n +/// Offers classes and functions for access to the Virtual File Server (VFS) +/// which you can use to manipulate files and folders. +/// +/// This system allow the use of ["Special Protocol"](https://kodi.wiki/view/Special_protocol) +/// where is Kodi's solution to platform dependent directories. Common directory +/// names are assigned a `special://[name]` path which is passed around +/// inside Kodi and then translated to the platform specific path before the +/// operating system sees it. This helps keep most of the platform mess +/// centralized in the code.\n +/// To become a correct path back can be @ref TranslateSpecialProtocol() used. +/// +/// It has the header @ref Filesystem.h "#include " be +/// included to enjoy it. +/// +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_vfs_Defs Definitions, structures and enumerators +/// @ingroup cpp_kodi_vfs +/// @brief **Virtual file Server definition values**\n +/// All to VFS system functions associated data structures. +/// +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_vfs_Directory 1. Directory functions +/// @ingroup cpp_kodi_vfs +/// @brief **Globally available directories related functions**\n +/// Used to perform typical operations with it. +/// +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_vfs_File 2. File functions +/// @ingroup cpp_kodi_vfs +/// @brief **Globally available file related functions**\n +/// Used to perform typical operations with it. +/// +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_vfs_General 3. General functions +/// @ingroup cpp_kodi_vfs +/// @brief **Other globally available functions**\n +/// Used to perform typical operations with it. +/// +//------------------------------------------------------------------------------ + +//}}} + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" related filesystem definitions +//{{{ + +//============================================================================== +/// @defgroup cpp_kodi_vfs_Defs_FileStatus class FileStatus +/// @ingroup cpp_kodi_vfs_Defs +/// @brief **File information status**\n +/// Used on kodi::vfs::StatFile() to get detailed information about a file. +/// +//@{ +class ATTRIBUTE_HIDDEN FileStatus : public kodi::addon::CStructHdl +{ +public: + /*! \cond PRIVATE */ + FileStatus() { memset(m_cStructure, 0, sizeof(STAT_STRUCTURE)); } + FileStatus(const FileStatus& channel) : CStructHdl(channel) {} + FileStatus(const STAT_STRUCTURE* channel) : CStructHdl(channel) {} + FileStatus(STAT_STRUCTURE* channel) : CStructHdl(channel) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_vfs_Defs_FileStatus_Help *Value Help* + /// @ingroup cpp_kodi_vfs_Defs_FileStatus + /// ---------------------------------------------------------------------------- + /// + /// The following table contains values that can be set with @ref cpp_kodi_vfs_Defs_FileStatus : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **ID of device containing file** | `uint32_t` | @ref FileStatus::SetDeviceId "SetDeviceId" | @ref FileStatus::GetDeviceId "GetDeviceId" + /// | **Represent file serial numbers** | `uint64_t` | @ref FileStatus::SetFileSerialNumber "SetFileSerialNumber" | @ref FileStatus::GetFileSerialNumber "GetFileSerialNumber" + /// | **Total size, in bytes** | `uint64_t` | @ref FileStatus::SetSize "SetSize" | @ref FileStatus::GetSize "GetSize" + /// | **Time of last access** | `time_t` | @ref FileStatus::SetAccessTime "SetAccessTime" | @ref FileStatus::GetAccessTime "GetAccessTime" + /// | **Time of last modification** | `time_t` | @ref FileStatus::SetModificationTime "SetModificationTime" | @ref FileStatus::GetModificationTime "GetModificationTime" + /// | **Time of last status change** | `time_t` | @ref FileStatus::SetStatusTime "SetStatusTime" | @ref FileStatus::GetStatusTime "GetStatusTime" + /// | **Stat url is a directory** | `bool` | @ref FileStatus::SetIsDirectory "SetIsDirectory" | @ref FileStatus::GetIsDirectory "GetIsDirectory" + /// | **Stat url as a symbolic link** | `bool` | @ref FileStatus::SetIsSymLink "SetIsSymLink" | @ref FileStatus::GetIsSymLink "GetIsSymLink" + /// | **Stat url as a block special** | `bool` | @ref FileStatus::SetIsBlock "SetIsBlock" | @ref FileStatus::GetIsBlock "GetIsBlock" + /// | **Stat url as a character special** | `bool` | @ref FileStatus::SetIsCharacter "SetIsCharacter" | @ref FileStatus::GetIsCharacter "GetIsCharacter" + /// | **Stat url as a FIFO special** | `bool` | @ref FileStatus::SetIsFifo "SetIsFifo" | @ref FileStatus::GetIsFifo "GetIsFifo" + /// | **Stat url as a regular** | `bool` | @ref FileStatus::SetIsRegular "SetIsRegular" | @ref FileStatus::GetIsRegular "GetIsRegular" + /// | **Stat url as a socket** | `bool` | @ref FileStatus::SetIsSocket "SetIsSocket" | @ref FileStatus::GetIsSocket "GetIsSocket" + /// + + /// @addtogroup cpp_kodi_vfs_Defs_FileStatus + /// @copydetails cpp_kodi_vfs_Defs_FileStatus_Help + //@{ + + /// @brief Set ID of device containing file. + void SetDeviceId(uint32_t deviceId) { m_cStructure->deviceId = deviceId; } + + /// @brief Get ID of device containing file. + uint32_t GetDeviceId() const { return m_cStructure->deviceId; } + + /// @brief Set the file serial number, which distinguishes this file from all other files on the same device. + void SetFileSerialNumber(uint64_t fileSerialNumber) { m_cStructure->fileSerialNumber = fileSerialNumber; } + + /// @brief Get the file serial number, which distinguishes this file from all other files on the same device. + uint64_t GetFileSerialNumber() const { return m_cStructure->fileSerialNumber; } + + /// @brief Set total size, in bytes. + void SetSize(uint64_t size) { m_cStructure->size = size; } + + /// @brief Get total size, in bytes. + uint64_t GetSize() const { return m_cStructure->size; } + + /// @brief Set time of last access. + void SetAccessTime(time_t accessTime) { m_cStructure->accessTime = accessTime; } + + /// @brief Get time of last access. + time_t GetAccessTime() const { return m_cStructure->accessTime; } + + /// @brief Set time of last modification. + void SetModificationTime(time_t modificationTime) + { + m_cStructure->modificationTime = modificationTime; + } + + /// @brief Get time of last modification. + time_t GetModificationTime() const { return m_cStructure->modificationTime; } + + /// @brief Set time of last status change. + void SetStatusTime(time_t statusTime) { m_cStructure->statusTime = statusTime; } + + /// @brief Get time of last status change. + time_t GetStatusTime() const { return m_cStructure->statusTime; } + + /// @brief Set the stat url is a directory. + void SetIsDirectory(bool isDirectory) { m_cStructure->isDirectory = isDirectory; } + + /// @brief The stat url is a directory if returns true. + bool GetIsDirectory() const { return m_cStructure->isDirectory; } + + /// @brief Set stat url as a symbolic link. + void SetIsSymLink(bool isSymLink) { m_cStructure->isSymLink = isSymLink; } + + /// @brief Get stat url is a symbolic link. + bool GetIsSymLink() const { return m_cStructure->isSymLink; } + + /// @brief Set stat url as a block special. + void SetIsBlock(bool isBlock) { m_cStructure->isBlock = isBlock; } + + /// @brief Get stat url is a block special. + bool GetIsBlock() const { return m_cStructure->isBlock; } + + /// @brief Set stat url as a character special. + void SetIsCharacter(bool isCharacter) { m_cStructure->isCharacter = isCharacter; } + + /// @brief Get stat url is a character special. + bool GetIsCharacter() const { return m_cStructure->isCharacter; } + + /// @brief Set stat url as a FIFO special. + void SetIsFifo(bool isFifo) { m_cStructure->isFifo = isFifo; } + + /// @brief Get stat url is a FIFO special. + bool GetIsFifo() const { return m_cStructure->isFifo; } + + /// @brief Set stat url as a regular. + void SetIsRegular(bool isRegular) { m_cStructure->isRegular = isRegular; } + + /// @brief Get stat url is a regular. + bool GetIsRegular() const { return m_cStructure->isRegular; } + + /// @brief Set stat url is a socket. + void SetIsSocket(bool isSocket) { m_cStructure->isSocket = isSocket; } + + /// @brief Get stat url is a regular. + bool GetIsSocket() const { return m_cStructure->isSocket; } + //@} +}; +//@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_vfs_Defs_CacheStatus class CacheStatus +/// @ingroup cpp_kodi_vfs_Defs +/// @brief **Cache information status**\n +/// Used on kodi::vfs::CFile::IoControlGetCacheStatus() to get running cache +/// status of proccessed stream. +/// +//@{ +class ATTRIBUTE_HIDDEN CacheStatus + : public kodi::addon::CStructHdl +{ +public: + /*! \cond PRIVATE */ + CacheStatus() { memset(m_cStructure, 0, sizeof(VFS_CACHE_STATUS_DATA)); } + CacheStatus(const CacheStatus& channel) : CStructHdl(channel) {} + CacheStatus(const VFS_CACHE_STATUS_DATA* channel) : CStructHdl(channel) {} + CacheStatus(VFS_CACHE_STATUS_DATA* channel) : CStructHdl(channel) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_vfs_Defs_CacheStatus_Help *Value Help* + /// @ingroup cpp_kodi_vfs_Defs_CacheStatus + /// ---------------------------------------------------------------------------- + /// + /// The following table contains values that can be set with @ref cpp_kodi_vfs_Defs_CacheStatus : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **Number of bytes cached** | `uint64_t` | @ref CacheStatus::SetForward "SetForward" | @ref CacheStatus::GetForward "GetForward" + /// | **Maximum number of bytes per second** | `unsigned int` | @ref CacheStatus::SetMaxRate "SetMaxRate" | @ref CacheStatus::GetMaxRate "GetMaxRate" + /// | **Average read rate from source file** | `unsigned int` | @ref CacheStatus::SetCurrentRate "SetCurrentRate" | @ref CacheStatus::GetCurrentRate "GetCurrentRate" + /// | **Cache low speed condition detected** | `bool` | @ref CacheStatus::SetLowspeed "SetLowspeed" | @ref CacheStatus::GetLowspeed "GetLowspeed" + /// + + /// @addtogroup cpp_kodi_vfs_Defs_CacheStatus + /// @copydetails cpp_kodi_vfs_Defs_CacheStatus_Help + //@{ + + /// @brief Set number of bytes cached forward of current position. + void SetForward(uint64_t forward) { m_cStructure->forward = forward; } + + /// @brief Get number of bytes cached forward of current position. + uint64_t GetForward() { return m_cStructure->forward; } + + /// @brief Set maximum number of bytes per second cache is allowed to fill. + void SetMaxRate(unsigned int maxrate) { m_cStructure->maxrate = maxrate; } + + /// @brief Set maximum number of bytes per second cache is allowed to fill. + unsigned int GetMaxRate() { return m_cStructure->maxrate; } + + /// @brief Set average read rate from source file since last position change. + void SetCurrentRate(unsigned int currate) { m_cStructure->currate = currate; } + + /// @brief Get average read rate from source file since last position change. + unsigned int GetCurrentRate() { return m_cStructure->currate; } + + /// @brief Set cache low speed condition detected. + void SetLowspeed(bool lowspeed) { m_cStructure->lowspeed = lowspeed; } + + /// @brief Get cache low speed condition detected. + bool GetLowspeed() { return m_cStructure->lowspeed; } + + //@} +}; +//@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_vfs_Defs_HttpHeader class HttpHeader +/// @ingroup cpp_kodi_vfs_Defs +/// @brief **HTTP header information**\n +/// The class used to access HTTP header information and get his information. +/// +/// Used on @ref kodi::vfs::GetHttpHeader(). +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_vfs_Defs_HttpHeader_Help +/// +///@{ +class ATTRIBUTE_HIDDEN HttpHeader +{ +public: + //========================================================================== + /// @brief Http header parser class constructor. + /// + HttpHeader() + { + using namespace ::kodi::addon; + + CAddonBase::m_interface->toKodi->kodi_filesystem->http_header_create( + CAddonBase::m_interface->toKodi->kodiBase, &m_handle); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @brief Class destructor. + /// + ~HttpHeader() + { + using namespace ::kodi::addon; + + CAddonBase::m_interface->toKodi->kodi_filesystem->http_header_free( + CAddonBase::m_interface->toKodi->kodiBase, &m_handle); + } + //-------------------------------------------------------------------------- + + /// @defgroup cpp_kodi_vfs_Defs_HttpHeader_Help *Value Help* + /// @ingroup cpp_kodi_vfs_Defs_HttpHeader + /// + /// The following table contains values that can be get with @ref cpp_kodi_vfs_Defs_HttpHeader : + /// | Description | Type | Get call + /// |-------------|------|------------ + /// | **Get the value associated with this parameter of these HTTP headers** | `std::string` | @ref HttpHeader::GetValue "GetValue" + /// | **Get the values as list associated with this parameter of these HTTP headers** | `std::vector` | @ref HttpHeader::GetValues "GetValues" + /// | **Get the full header string associated with these HTTP headers** | `std::string` | @ref HttpHeader::GetHeader "GetHeader" + /// | **Get the mime type associated with these HTTP headers** | `std::string` | @ref HttpHeader::GetMimeType "GetMimeType" + /// | **Get the charset associated with these HTTP headers** | `std::string` | @ref HttpHeader::GetCharset "GetCharset" + /// | **The protocol line associated with these HTTP headers** | `std::string` | @ref HttpHeader::GetProtoLine "GetProtoLine" + /// + + /// @addtogroup cpp_kodi_vfs_Defs_HttpHeader + ///@{ + + //========================================================================== + /// @brief Get the value associated with this parameter of these HTTP + /// headers. + /// + /// @param[in] param The name of the parameter a value is required for + /// @return The value found + /// + std::string GetValue(const std::string& param) const + { + using namespace ::kodi::addon; + + if (!m_handle.handle) + return ""; + + std::string protoLine; + char* string = m_handle.get_value(CAddonBase::m_interface->toKodi->kodiBase, m_handle.handle, + param.c_str()); + if (string != nullptr) + { + protoLine = string; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + string); + } + return protoLine; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @brief Get the values as list associated with this parameter of these + /// HTTP headers. + /// + /// @param[in] param The name of the parameter values are required for + /// @return The values found + /// + std::vector GetValues(const std::string& param) const + { + using namespace kodi::addon; + + if (!m_handle.handle) + return std::vector(); + + int numValues = 0; + char** res(m_handle.get_values(CAddonBase::m_interface->toKodi->kodiBase, m_handle.handle, + param.c_str(), &numValues)); + if (res) + { + std::vector vecReturn; + for (int i = 0; i < numValues; ++i) + { + vecReturn.emplace_back(res[i]); + } + CAddonBase::m_interface->toKodi->free_string_array(CAddonBase::m_interface->toKodi->kodiBase, + res, numValues); + return vecReturn; + } + return std::vector(); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @brief Get the full header string associated with these HTTP headers. + /// + /// @return The header as a string + /// + std::string GetHeader() const + { + using namespace ::kodi::addon; + + if (!m_handle.handle) + return ""; + + std::string header; + char* string = m_handle.get_header(CAddonBase::m_interface->toKodi->kodiBase, m_handle.handle); + if (string != nullptr) + { + header = string; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + string); + } + return header; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @brief Get the mime type associated with these HTTP headers. + /// + /// @return The mime type + /// + std::string GetMimeType() const + { + using namespace ::kodi::addon; + + if (!m_handle.handle) + return ""; + + std::string protoLine; + char* string = + m_handle.get_mime_type(CAddonBase::m_interface->toKodi->kodiBase, m_handle.handle); + if (string != nullptr) + { + protoLine = string; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + string); + } + return protoLine; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @brief Get the charset associated with these HTTP headers. + /// + /// @return The charset + /// + std::string GetCharset() const + { + using namespace ::kodi::addon; + + if (!m_handle.handle) + return ""; + + std::string protoLine; + char* string = m_handle.get_charset(CAddonBase::m_interface->toKodi->kodiBase, m_handle.handle); + if (string != nullptr) + { + protoLine = string; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + string); + } + return protoLine; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @brief The protocol line associated with these HTTP headers. + /// + /// @return The protocol line + /// + std::string GetProtoLine() const + { + using namespace ::kodi::addon; + + if (!m_handle.handle) + return ""; + + std::string protoLine; + char* string = + m_handle.get_proto_line(CAddonBase::m_interface->toKodi->kodiBase, m_handle.handle); + if (string != nullptr) + { + protoLine = string; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + string); + } + return protoLine; + } + //-------------------------------------------------------------------------- + + ///@} + + KODI_HTTP_HEADER m_handle; +}; +///@} +//---------------------------------------------------------------------------- + +//============================================================================== +/// @defgroup cpp_kodi_vfs_CDirEntry class CDirEntry +/// @ingroup cpp_kodi_vfs_Defs +/// +/// @brief **Virtual file server directory entry**\n +/// This class is used as an entry for files and folders in +/// kodi::vfs::GetDirectory(). +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// ... +/// +/// std::vector items; +/// kodi::vfs::GetDirectory("special://temp", "", items); +/// +/// fprintf(stderr, "Directory have %lu entries\n", items.size()); +/// for (unsigned long i = 0; i < items.size(); i++) +/// { +/// char buff[20]; +/// time_t now = items[i].DateTime(); +/// strftime(buff, 20, "%Y-%m-%d %H:%M:%S", gmtime(&now)); +/// fprintf(stderr, " - %04lu -- Folder: %s -- Name: %s -- Path: %s -- Time: %s\n", +/// i+1, +/// items[i].IsFolder() ? "yes" : "no ", +/// items[i].Label().c_str(), +/// items[i].Path().c_str(), +/// buff); +/// } +/// ~~~~~~~~~~~~~ +/// +/// It has the header @ref Filesystem.h "#include " be included +/// to enjoy it. +/// +//@{ +class ATTRIBUTE_HIDDEN CDirEntry +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_vfs_CDirEntry + /// @brief Constructor for VFS directory entry + /// + /// @param[in] label [opt] Name to use for entry + /// @param[in] path [opt] Used path of the entry + /// @param[in] folder [opt] If set entry used as folder + /// @param[in] size [opt] If used as file, his size defined there + /// @param[in] dateTime [opt] Date time of the entry + /// + CDirEntry(const std::string& label = "", + const std::string& path = "", + bool folder = false, + int64_t size = -1, + time_t dateTime = 0) + : m_label(label), m_path(path), m_folder(folder), m_size(size), m_dateTime(dateTime) + { + } + //---------------------------------------------------------------------------- + + //============================================================================ + // @note Not for addon development itself needed, thats why below is + // disabled for doxygen! + // + // @ingroup cpp_kodi_vfs_CDirEntry + // @brief Constructor to create own copy + // + // @param[in] dirEntry pointer to own class type + // + explicit CDirEntry(const VFSDirEntry& dirEntry) + : m_label(dirEntry.label ? dirEntry.label : ""), + m_path(dirEntry.path ? dirEntry.path : ""), + m_folder(dirEntry.folder), + m_size(dirEntry.size), + m_dateTime(dirEntry.date_time) + { + } + //---------------------------------------------------------------------------- + + /// @defgroup cpp_kodi_vfs_CDirEntry_Help *Value Help* + /// @ingroup cpp_kodi_vfs_CDirEntry + /// -------------------------------------------------------------------------- + /// + /// The following table contains values that can be set with @ref cpp_kodi_vfs_CDirEntry : + /// | Name | Type | Set call | Get call | Clear call | + /// |------|------|----------|----------|------------| + /// | **Directory entry name** | `std::string` | @ref CDirEntry::SetLabel "SetLabel" | @ref CDirEntry::Label "Label" | | + /// | **Title of entry** | `std::string` | @ref CDirEntry::SetTitle "SetTitle" | @ref CDirEntry::Title "Title" | | + /// | **Path of the entry** | `std::string` | @ref CDirEntry::SetPath "SetPath" | @ref CDirEntry::Path "Path" | | + /// | **Entry is folder** | `bool` | @ref CDirEntry::SetFolder "SetFolder" | @ref CDirEntry::IsFolder "IsFolder" | | + /// | **The size of the file** | `int64_t` | @ref CDirEntry::SetSize "SetSize" | @ref CDirEntry::Size "Size" | | + /// | **File time and date** | `time_t` | @ref CDirEntry::SetDateTime "SetDateTime" | @ref CDirEntry::DateTime "DateTime" | | + /// | **Property entries** | `std::string, std::string` | @ref CDirEntry::AddProperty "AddProperty" | @ref CDirEntry::GetProperties "GetProperties" | @ref CDirEntry::ClearProperties "ClearProperties" + /// + + /// @addtogroup cpp_kodi_vfs_CDirEntry + /// @copydetails cpp_kodi_vfs_CDirEntry_Help + //@{ + + //============================================================================ + /// @brief Get the directory entry name. + /// + /// @return Name of the entry + /// + const std::string& Label(void) const { return m_label; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the optional title of entry. + /// + /// @return Title of the entry, if exists + /// + const std::string& Title(void) const { return m_title; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the path of the entry. + /// + /// @return File system path of the entry + /// + const std::string& Path(void) const { return m_path; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Used to check entry is folder. + /// + /// @return true if entry is a folder + /// + bool IsFolder(void) const { return m_folder; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief If file, the size of the file. + /// + /// @return Defined file size + /// + int64_t Size(void) const { return m_size; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get file time and date for a new entry. + /// + /// @return The with time_t defined date and time of file + /// + time_t DateTime() { return m_dateTime; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Set the label name. + /// + /// @param[in] label name of entry + /// + void SetLabel(const std::string& label) { m_label = label; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Set the title name. + /// + /// @param[in] title title name of entry + /// + void SetTitle(const std::string& title) { m_title = title; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Set the path of the entry. + /// + /// @param[in] path path of entry + /// + void SetPath(const std::string& path) { m_path = path; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Set the entry defined as folder. + /// + /// @param[in] folder If true becomes entry defined as folder + /// + void SetFolder(bool folder) { m_folder = folder; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Set a file size for a new entry. + /// + /// @param[in] size Size to set for dir entry + /// + void SetSize(int64_t size) { m_size = size; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Set file time and date for a new entry. + /// + /// @param[in] dateTime The with time_t defined date and time of file + /// + void SetDateTime(time_t dateTime) { m_dateTime = dateTime; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Add a by string defined property entry to directory entry. + /// + /// @note A property can be used to add some special information about a file + /// or directory entry, this can be used on other places to do the right work + /// of them. + /// + /// @param[in] id Identification name of property + /// @param[in] value The property value to add by given id + /// + void AddProperty(const std::string& id, const std::string& value) { m_properties[id] = value; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Clear all present properties. + /// + void ClearProperties() { m_properties.clear(); } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the present properties list on directory entry. + /// + /// @return map with all present properties + /// + const std::map& GetProperties() const { return m_properties; } + //---------------------------------------------------------------------------- + + //@} + +private: + std::string m_label; + std::string m_title; + std::string m_path; + std::map m_properties; + bool m_folder; + int64_t m_size; + time_t m_dateTime; +}; +//@} +//------------------------------------------------------------------------------ + +//}}} + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" Directory related functions +//{{{ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_Directory +/// @brief Make a directory. +/// +/// The kodi::vfs::CreateDirectory() function shall create a +/// new directory with name path. +/// +/// The newly created directory shall be an empty directory. +/// +/// @param[in] path Path to the directory. +/// @return Upon successful completion, CreateDirectory() shall return true. +/// Otherwise false shall be returned, no directory shall be created. +/// +/// +/// ------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string directory = "C:\\my_dir"; +/// bool ret = kodi::vfs::CreateDirectory(directory); +/// fprintf(stderr, "Directory '%s' successfull created: %s\n", directory.c_str(), ret ? "yes" : "no"); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN CreateDirectory(const std::string& path) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->create_directory( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_Directory +/// @brief Verifying the Existence of a Directory. +/// +/// The kodi::vfs::DirectoryExists() method determines whether +/// a specified folder exists. +/// +/// @param[in] path Path to the directory. +/// @return True when it exists, false otherwise. +/// +/// +/// ------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string directory = "C:\\my_dir"; +/// bool ret = kodi::vfs::DirectoryExists(directory); +/// fprintf(stderr, "Directory '%s' present: %s\n", directory.c_str(), ret ? "yes" : "no"); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN DirectoryExists(const std::string& path) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->directory_exists( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_Directory +/// @brief Removes a directory. +/// +/// The kodi::vfs::RemoveDirectory() function shall remove a +/// directory whose name is given by path. +/// +/// @param[in] path Path to the directory. +/// @param[in] recursive [opt] Remove directory recursive (default is false) +/// @return Upon successful completion, the function RemoveDirectory() shall +/// return true. Otherwise, false shall be returned, and errno set +/// to indicate the error. If false is returned, the named directory +/// shall not be changed. +/// +/// +/// ------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// bool ret = kodi::vfs::RemoveDirectory("C:\\my_dir"); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN RemoveDirectory(const std::string& path, bool recursive = false) +{ + using namespace kodi::addon; + + if (!recursive) + return CAddonBase::m_interface->toKodi->kodi_filesystem->remove_directory( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); + else + return CAddonBase::m_interface->toKodi->kodi_filesystem->remove_directory_recursive( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_Directory +/// @brief Lists a directory. +/// +/// Return the list of files and directories which have been found in the +/// specified directory and which respect the given constraint. +/// +/// It can handle the normal OS dependent paths and also the special virtual +/// filesystem from Kodi what starts with \b special://. +/// +/// @param[in] path The path in which the files and directories are located. +/// @param[in] mask Mask to filter out requested files, e.g. "*.avi|*.mpg" to +/// files with this ending. +/// @param[out] items The returned list directory entries. +/// @return True if listing was successful, false otherwise. +/// +/// +/// ------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// std::vector items; +/// kodi::vfs::GetDirectory("special://temp", "", items); +/// +/// fprintf(stderr, "Directory have %lu entries\n", items.size()); +/// for (unsigned long i = 0; i < items.size(); i++) +/// { +/// fprintf(stderr, " - %04lu -- Folder: %s -- Name: %s -- Path: %s\n", +/// i+1, +/// items[i].IsFolder() ? "yes" : "no ", +/// items[i].Label().c_str(), +/// items[i].Path().c_str()); +/// } +/// ~~~~~~~~~~~~~ +inline bool ATTRIBUTE_HIDDEN GetDirectory(const std::string& path, + const std::string& mask, + std::vector& items) +{ + using namespace kodi::addon; + + VFSDirEntry* dir_list = nullptr; + unsigned int num_items = 0; + if (CAddonBase::m_interface->toKodi->kodi_filesystem->get_directory( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str(), mask.c_str(), &dir_list, + &num_items)) + { + if (dir_list) + { + for (unsigned int i = 0; i < num_items; ++i) + items.emplace_back(dir_list[i]); + + CAddonBase::m_interface->toKodi->kodi_filesystem->free_directory( + CAddonBase::m_interface->toKodi->kodiBase, dir_list, num_items); + } + + return true; + } + return false; +} +//------------------------------------------------------------------------------ + +//}}} + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" File related functions +//{{{ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_File +/// @brief Check if a file exists. +/// +/// @param[in] filename The filename to check. +/// @param[in] usecache Check in file cache. +/// @return true if the file exists false otherwise. +/// +/// +/// ------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// bool exists = kodi::vfs::FileExists("special://temp/kodi.log"); +/// fprintf(stderr, "Log file should be always present, is it present? %s\n", exists ? "yes" : "no"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN FileExists(const std::string& filename, bool usecache = false) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->file_exists( + CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), usecache); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_File +/// @brief Get file status. +/// +/// These function return information about a file. Execute (search) +/// permission is required on all of the directories in path that +/// lead to the file. +/// +/// The call return a stat structure, which contains the on +/// @ref cpp_kodi_vfs_Defs_FileStatus defined values. +/// +/// @warning Not all of the OS file systems implement all of the time fields. +/// +/// @param[in] filename The filename to read the status from. +/// @param[out] buffer The file status is written into this buffer. +/// @return On success, trur is returned. On error, false is returned +/// +/// +/// @copydetails cpp_kodi_vfs_Defs_FileStatus_Help +/// +/// ------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// kodi::vfs::FileStatus statFile; +/// int ret = kodi::vfs::StatFile("special://temp/kodi.log", statFile); +/// fprintf(stderr, "deviceId (ID of device containing file) = %u\n" +/// "size (total size, in bytes) = %lu\n" +/// "accessTime (time of last access) = %lu\n" +/// "modificationTime (time of last modification) = %lu\n" +/// "statusTime (time of last status change) = %lu\n" +/// "isDirectory (The stat url is a directory) = %s\n" +/// "isSymLink (The stat url is a symbolic link) = %s\n" +/// "Return value = %i\n", +/// statFile.GetDeviceId(), +/// statFile.GetSize(), +/// statFile.GetAccessTime(), +/// statFile.GetModificationTime(), +/// statFile.GetStatusTime(), +/// statFile.GetIsDirectory() ? "true" : "false", +/// statFile.GetIsSymLink() ? "true" : "false", +/// ret); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN StatFile(const std::string& filename, kodi::vfs::FileStatus& buffer) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->stat_file( + CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), buffer); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_File +/// @brief Deletes a file. +/// +/// @param[in] filename The filename to delete. +/// @return The file was successfully deleted. +/// +/// +/// ------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// #include +/// #include +/// ... +/// std::string filename; +/// if (kodi::gui::DialogFileBrowser::ShowAndGetFile("local", "", +/// "Test File selection and delete of them!", +/// filename)) +/// { +/// bool successed = kodi::vfs::DeleteFile(filename); +/// if (!successed) +/// kodi::gui::DialogOK::ShowAndGetInput("Error", "Delete of File", filename, "failed!"); +/// else +/// kodi::gui::DialogOK::ShowAndGetInput("Information", "Delete of File", filename, "successfull done."); +/// } +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN DeleteFile(const std::string& filename) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->delete_file( + CAddonBase::m_interface->toKodi->kodiBase, filename.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_File +/// @brief Rename a file name. +/// +/// @param[in] filename The filename to copy. +/// @param[in] newFileName The new filename +/// @return true if successfully renamed +/// +/// +inline bool ATTRIBUTE_HIDDEN RenameFile(const std::string& filename, const std::string& newFileName) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->rename_file( + CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), newFileName.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_File +/// @brief Copy a file from source to destination. +/// +/// @param[in] filename The filename to copy. +/// @param[in] destination The destination to copy file to +/// @return true if successfully copied +/// +/// +inline bool ATTRIBUTE_HIDDEN CopyFile(const std::string& filename, const std::string& destination) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->copy_file( + CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), destination.c_str()); +} +//------------------------------------------------------------------------------ + +//}}} + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" General filesystem functions +//{{{ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Retrieve MD5sum of a file. +/// +/// @param[in] path Path to the file to MD5sum +/// @return MD5 sum of the file +/// +/// +/// ------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// #include +/// ... +/// std::string md5; +/// std::string filename; +/// if (kodi::gui::DialogFileBrowser::ShowAndGetFile("local", "*.avi|*.mpg|*.mp4", +/// "Test File selection to get MD5", +/// filename)) +/// { +/// md5 = kodi::vfs::GetFileMD5(filename); +/// fprintf(stderr, "MD5 of file '%s' is %s\n", md5.c_str(), filename.c_str()); +/// } +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN GetFileMD5(const std::string& path) +{ + using namespace kodi::addon; + + std::string strReturn; + char* strMd5 = CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_md5( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); + if (strMd5 != nullptr) + { + if (std::strlen(strMd5)) + strReturn = strMd5; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, strMd5); + } + return strReturn; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Returns a thumb cache filename. +/// +/// @param[in] filename Path to file +/// @return Cache filename +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// #include +/// ... +/// std::string thumb; +/// std::string filename; +/// if (kodi::gui::DialogFileBrowser::ShowAndGetFile("local", "*.avi|*.mpg|*.mp4", +/// "Test File selection to get Thumnail", +/// filename)) +/// { +/// thumb = kodi::vfs::GetCacheThumbName(filename); +/// fprintf(stderr, "Thumb name of file '%s' is %s\n", thumb.c_str(), filename.c_str()); +/// } +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN GetCacheThumbName(const std::string& filename) +{ + using namespace kodi::addon; + + std::string strReturn; + char* strThumbName = CAddonBase::m_interface->toKodi->kodi_filesystem->get_cache_thumb_name( + CAddonBase::m_interface->toKodi->kodiBase, filename.c_str()); + if (strThumbName != nullptr) + { + if (std::strlen(strThumbName)) + strReturn = strThumbName; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + strThumbName); + } + return strReturn; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Make filename valid. +/// +/// Function to replace not valid characters with '_'. It can be also +/// compared with original before in a own loop until it is equal +/// (no invalid characters). +/// +/// @param[in] filename Filename to check and fix +/// @return The legal filename +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string fileName = "///\\jk???lj????.mpg"; +/// std::string legalName = kodi::vfs::MakeLegalFileName(fileName); +/// fprintf(stderr, "Legal name of '%s' is '%s'\n", fileName.c_str(), legalName.c_str()); +/// +/// /* Returns as legal: 'jk___lj____.mpg' */ +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN MakeLegalFileName(const std::string& filename) +{ + using namespace kodi::addon; + + std::string strReturn; + char* strLegalFileName = CAddonBase::m_interface->toKodi->kodi_filesystem->make_legal_filename( + CAddonBase::m_interface->toKodi->kodiBase, filename.c_str()); + if (strLegalFileName != nullptr) + { + if (std::strlen(strLegalFileName)) + strReturn = strLegalFileName; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + strLegalFileName); + } + return strReturn; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Make directory name valid. +/// +/// Function to replace not valid characters with '_'. It can be also +/// compared with original before in a own loop until it is equal +/// (no invalid characters). +/// +/// @param[in] path Directory name to check and fix +/// @return The legal directory name +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string path = "///\\jk???lj????\\hgjkg"; +/// std::string legalPath = kodi::vfs::MakeLegalPath(path); +/// fprintf(stderr, "Legal name of '%s' is '%s'\n", path.c_str(), legalPath.c_str()); +/// +/// /* Returns as legal: '/jk___lj____/hgjkg' */ +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN MakeLegalPath(const std::string& path) +{ + using namespace kodi::addon; + + std::string strReturn; + char* strLegalPath = CAddonBase::m_interface->toKodi->kodi_filesystem->make_legal_path( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); + if (strLegalPath != nullptr) + { + if (std::strlen(strLegalPath)) + strReturn = strLegalPath; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + strLegalPath); + } + return strReturn; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Returns the translated path. +/// +/// @param[in] source String or unicode - Path to format +/// @return A human-readable string suitable for logging +/// +/// @note Only useful if you are coding for both Linux and Windows. e.g. +/// Converts 'special://masterprofile/script_data' -> +/// '/home/user/.kodi/UserData/script_data' on Linux. +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string path = kodi::vfs::TranslateSpecialProtocol("special://masterprofile/script_data"); +/// fprintf(stderr, "Translated path is: %s\n", path.c_str()); +/// ... +/// ~~~~~~~~~~~~~ +/// or +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// fprintf(stderr, "Directory 'special://temp' is '%s'\n", kodi::vfs::TranslateSpecialProtocol("special://temp").c_str()); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN TranslateSpecialProtocol(const std::string& source) +{ + using namespace kodi::addon; + + std::string strReturn; + char* protocol = CAddonBase::m_interface->toKodi->kodi_filesystem->translate_special_protocol( + CAddonBase::m_interface->toKodi->kodiBase, source.c_str()); + if (protocol != nullptr) + { + if (std::strlen(protocol)) + strReturn = protocol; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + protocol); + } + return strReturn; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Retrieves information about the amount of space that is available on +/// a disk volume. +/// +/// Path can be also with Kodi's special protocol. +/// +/// @param[in] path Path for where to check +/// @param[out] capacity The total number of bytes in the file system +/// @param[out] free The total number of free bytes in the file system +/// @param[out] available The total number of free bytes available to a +/// non-privileged process +/// @return true if successfully done and set +/// +/// @warning This only works with paths belonging to OS. If "special://" +/// is used, it must point to a place on your own OS. +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include // for ULLONG_MAX +/// #include +/// ... +/// std::string path = "special://temp"; +/// uint64_t capacity = ULLONG_MAX; +/// uint64_t free = ULLONG_MAX; +/// uint64_t available = ULLONG_MAX; +/// kodi::vfs::GetDiskSpace(path, capacity, free, available); +/// fprintf(stderr, "Path '%s' sizes:\n", path.c_str()); +/// fprintf(stderr, " - capacity: %lu MByte\n", capacity / 1024 / 1024); +/// fprintf(stderr, " - free: %lu MByte\n", free / 1024 / 1024); +/// fprintf(stderr, " - available: %lu MByte\n", available / 1024 / 1024); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN GetDiskSpace(const std::string& path, + uint64_t& capacity, + uint64_t& free, + uint64_t& available) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->get_disk_space( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str(), &capacity, &free, &available); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Return the file name from given complate path string. +/// +/// @param[in] path The complete path include file and directory +/// @return Filename from path +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string fileName = kodi::vfs::GetFileName("special://temp/kodi.log"); +/// fprintf(stderr, "File name is '%s'\n", fileName.c_str()); +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN GetFileName(const std::string& path) +{ + /* find the last slash */ + const size_t slash = path.find_last_of("/\\"); + return path.substr(slash + 1); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Return the directory name from given complate path string. +/// +/// @param[in] path The complete path include file and directory +/// @return Directory name from path +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string dirName = kodi::vfs::GetDirectoryName("special://temp/kodi.log"); +/// fprintf(stderr, "Directory name is '%s'\n", dirName.c_str()); +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN GetDirectoryName(const std::string& path) +{ + // Will from a full filename return the directory the file resides in. + // Keeps the final slash at end and possible |option=foo options. + + size_t iPosSlash = path.find_last_of("/\\"); + if (iPosSlash == std::string::npos) + return ""; // No slash, so no path (ignore any options) + + size_t iPosBar = path.rfind('|'); + if (iPosBar == std::string::npos) + return path.substr(0, iPosSlash + 1); // Only path + + return path.substr(0, iPosSlash + 1) + path.substr(iPosBar); // Path + options +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Remove the slash on given path name. +/// +/// @param[in,out] path The complete path +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string dirName = "special://temp/"; +/// kodi::vfs::RemoveSlashAtEnd(dirName); +/// fprintf(stderr, "Directory name is '%s'\n", dirName.c_str()); +/// ~~~~~~~~~~~~~ +/// +inline void ATTRIBUTE_HIDDEN RemoveSlashAtEnd(std::string& path) +{ + if (!path.empty()) + { + char last = path[path.size() - 1]; + if (last == '/' || last == '\\') + path.erase(path.size() - 1); + } +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Return a size aligned to the chunk size at least as large as the +/// chunk size. +/// +/// @param[in] chunk The chunk size +/// @param[in] minimum The minimum size (or maybe the minimum number of chunks?) +/// @return The aligned size +/// +inline unsigned int ATTRIBUTE_HIDDEN GetChunkSize(unsigned int chunk, unsigned int minimum) +{ + if (chunk) + return chunk * ((minimum + chunk - 1) / chunk); + else + return minimum; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Checks the given path contains a known internet protocol. +/// +/// About following protocols are the path checked: +/// | Protocol | Return true condition | Protocol | Return true condition +/// |----------|-----------------------|----------|----------------------- +/// | **dav** | strictCheck = true | **rtmps** | always +/// | **davs** | strictCheck = true | **rtmpt** | always +/// | **ftp** | strictCheck = true | **rtmpte** | always +/// | **ftps** | strictCheck = true | **rtp** | always +/// | **http** | always | **rtsp** | always +/// | **https**| always | **sdp** | always +/// | **mms** | always | **sftp** | strictCheck = true +/// | **mmsh** | always | **stack** | always +/// | **mmst** | always | **tcp** | always +/// | **rtmp** | always | **udp** | always +/// | **rtmpe**| always | | | +/// +/// @param[in] path To checked path/URL +/// @param[in] strictCheck [opt] If True the set of protocols used will be +/// extended to include ftp, ftps, dav, davs and sftp. +/// @return True if path is to a internet stream, false otherwise +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// // Check should return false +/// fprintf(stderr, "File name 1 is internet stream '%s' (should no)\n", +/// kodi::vfs::IsInternetStream("D:/my-file.mkv") ? "yes" : "no"); +/// +/// // Check should return true +/// fprintf(stderr, "File name 2 is internet stream '%s' (should yes)\n", +/// kodi::vfs::IsInternetStream("http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4") ? "yes" : "no"); +/// +/// // Check should return false +/// fprintf(stderr, "File name 1 is internet stream '%s' (should no)\n", +/// kodi::vfs::IsInternetStream("ftp://do-somewhere.com/the-file.mkv") ? "yes" : "no", false); +/// +/// // Check should return true +/// fprintf(stderr, "File name 1 is internet stream '%s' (should yes)\n", +/// kodi::vfs::IsInternetStream("ftp://do-somewhere.com/the-file.mkv") ? "yes" : "no", true); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN IsInternetStream(const std::string& path, bool strictCheck = false) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->is_internet_stream( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str(), strictCheck); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Checks whether the specified path refers to a local network. +/// +/// In difference to @ref IsHostOnLAN() include this more deeper checks where +/// also handle Kodi's special protocol and stacks. +/// +/// @param[in] path To checked path +/// @return True if path is on LAN, false otherwise +/// +/// @note Check includes @ref IsHostOnLAN() too. +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// // Check should return true +/// bool lan = kodi::vfs::IsOnLAN("smb://path/to/file"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN IsOnLAN(const std::string& path) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->is_on_lan( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Checks specified path for external network. +/// +/// @param[in] path To checked path +/// @return True if path is remote, false otherwise +/// +/// @note This does not apply to the local network. +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// // Check should return true +/// bool remote = kodi::vfs::IsRemote("http://path/to/file"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN IsRemote(const std::string& path) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->is_remote( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Checks whether the given path refers to the own system. +/// +/// @param[in] path To checked path +/// @return True if path is local, false otherwise +/// +inline bool ATTRIBUTE_HIDDEN IsLocal(const std::string& path) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->is_local( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_vfs_General +/// @brief Checks specified path is a regular URL, e.g. "someprotocol://path/to/file" +/// +/// @return True if file item is URL, false otherwise +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// +/// bool isURL; +/// // Check should return true +/// isURL = kodi::vfs::IsURL("someprotocol://path/to/file"); +/// +/// // Check should return false +/// isURL = kodi::vfs::IsURL("/path/to/file"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN IsURL(const std::string& path) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->is_url( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str()); +} +//-------------------------------------------------------------------------- + +//============================================================================ +/// @ingroup cpp_kodi_vfs_General +/// @brief To get HTTP header information. +/// +/// @param[in] url URL source of the data +/// @param[out] header The @ref cpp_kodi_vfs_Defs_HttpHeader +/// @return true if successfully done, otherwise false +/// +/// +/// ------------------------------------------------------------------------ +/// +/// @copydetails cpp_kodi_vfs_Defs_HttpHeader_Help +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// kodi::vfs::HttpHeader header; +/// bool ret = kodi::vfs::GetHttpHeader(url, header); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN GetHttpHeader(const std::string& url, HttpHeader& header) +{ + using namespace ::kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_filesystem->get_http_header( + CAddonBase::m_interface->toKodi->kodiBase, url.c_str(), &header.m_handle); +} +//---------------------------------------------------------------------------- + +//============================================================================ +/// @ingroup cpp_kodi_vfs_General +/// @brief Get file mime type. +/// +/// @param[in] url URL source of the data +/// @param[out] mimeType the mime type of the URL +/// @param[in] useragent to be used when retrieving the MimeType [opt] +/// @return true if successfully done, otherwise false +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string mimeType;. +/// if (kodi::vfs::GetMimeType(url, mimeType)) +/// fprintf(stderr, "The mime type is '%s'\n", mimeType.c_str()); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN GetMimeType(const std::string& url, + std::string& mimeType, + const std::string& useragent = "") +{ + using namespace ::kodi::addon; + + char* cMimeType = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_filesystem->get_mime_type( + CAddonBase::m_interface->toKodi->kodiBase, url.c_str(), &cMimeType, useragent.c_str()); + if (cMimeType != nullptr) + { + mimeType = cMimeType; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + cMimeType); + } + return ret; +} +//---------------------------------------------------------------------------- + +//============================================================================ +/// @ingroup cpp_kodi_vfs_General +/// @brief Get file content-type. +/// +/// @param[in] url URL source of the data +/// @param[out] content The returned type +/// @param[in] useragent to be used when retrieving the MimeType [opt] +/// @return true if successfully done, otherwise false +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string content;. +/// if (kodi::vfs::GetContentType(url, content)) +/// fprintf(stderr, "The content type is '%s'\n", content.c_str()); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN GetContentType(const std::string& url, + std::string& content, + const std::string& useragent = "") +{ + using namespace ::kodi::addon; + + char* cContent = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_filesystem->get_content_type( + CAddonBase::m_interface->toKodi->kodiBase, url.c_str(), &cContent, useragent.c_str()); + if (cContent != nullptr) + { + content = cContent; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + cContent); + } + return ret; +} +//---------------------------------------------------------------------------- + +//============================================================================ +/// @ingroup cpp_kodi_vfs_General +/// @brief Get cookies stored by CURL in RFC 2109 format. +/// +/// @param[in] url URL source of the data +/// @param[out] cookies The text list of available cookies +/// @return true if successfully done, otherwise false +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string url = ""; +/// std::string cookies; +/// bool ret = kodi::vfs::GetCookies(url, cookies); +/// fprintf(stderr, "Cookies from URL '%s' are '%s' (return was %s)\n", +/// url.c_str(), cookies.c_str(), ret ? "true" : "false"); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN GetCookies(const std::string& url, std::string& cookies) +{ + using namespace ::kodi::addon; + + char* cCookies = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_filesystem->get_cookies( + CAddonBase::m_interface->toKodi->kodiBase, url.c_str(), &cCookies); + if (cCookies != nullptr) + { + cookies = cCookies; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + cCookies); + } + return ret; +} +//---------------------------------------------------------------------------- + +//}}} + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" CFile class +//{{{ + +//============================================================================== +/// @defgroup cpp_kodi_vfs_CFile 4. class CFile +/// @ingroup cpp_kodi_vfs +/// +/// @brief **Creatable class for virtual file server control**\n +/// To perform file read/write with Kodi's filesystem parts. +/// +/// CFile is the class used for handling Files in Kodi. This class can be used +/// for creating, reading, writing and modifying files. It directly provides unbuffered, binary disk input/output services +/// +/// It has the header @ref Filesystem.h "#include " be included +/// to enjoy it. +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// ... +/// +/// /* Create the needed file handle class */ +/// kodi::vfs::CFile myFile(); +/// +/// /* In this example we use the user path for the add-on */ +/// std::string file = kodi::GetUserPath() + "/myFile.txt"; +/// +/// /* Now create and open the file or overwrite if present */ +/// myFile.OpenFileForWrite(file, true); +/// +/// const char* str = "I love Kodi!"; +/// +/// /* write string */ +/// myFile.Write(str, sizeof(str)); +/// +/// /* On this way the Close() is not needed to call, becomes done from destructor */ +/// +/// ~~~~~~~~~~~~~ +/// +//@{ +class ATTRIBUTE_HIDDEN CFile +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Construct a new, unopened file. + /// + CFile() = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_vfs_CFile + /// @brief `Close()` is called from the destructor, so explicitly + /// closing the file isn't required. + /// + virtual ~CFile() { Close(); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Open the file with filename via Kodi's @ref cpp_kodi_vfs_CFile + /// "CFile". Needs to be closed by calling Close() when done. + /// + /// @param[in] filename The filename to open. + /// @param[in] flags [opt] The flags to pass, see @ref OpenFileFlags + /// @return True on success or false on failure + /// + bool OpenFile(const std::string& filename, unsigned int flags = 0) + { + using namespace kodi::addon; + + Close(); + m_file = CAddonBase::m_interface->toKodi->kodi_filesystem->open_file( + CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), flags); + return m_file != nullptr; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Open the file with filename via Kodi's @ref cpp_kodi_vfs_CFile + /// "CFile" in write mode. Needs to be closed by calling Close() when + /// done. + /// + /// @note Related folders becomes created if not present. + /// + /// @param[in] filename The filename to open. + /// @param[in] overwrite True to overwrite, false otherwise. + /// @return True on success or false on failure + /// + bool OpenFileForWrite(const std::string& filename, bool overwrite = false) + { + using namespace kodi::addon; + + Close(); + + // Try to open the file. If it fails, check if we need to create the directory first + // This way we avoid checking if the directory exists every time + m_file = CAddonBase::m_interface->toKodi->kodi_filesystem->open_file_for_write( + CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), overwrite); + if (!m_file) + { + std::string cacheDirectory = kodi::vfs::GetDirectoryName(filename); + if (CAddonBase::m_interface->toKodi->kodi_filesystem->directory_exists( + CAddonBase::m_interface->toKodi->kodiBase, cacheDirectory.c_str()) || + CAddonBase::m_interface->toKodi->kodi_filesystem->create_directory( + CAddonBase::m_interface->toKodi->kodiBase, cacheDirectory.c_str())) + m_file = CAddonBase::m_interface->toKodi->kodi_filesystem->open_file_for_write( + CAddonBase::m_interface->toKodi->kodiBase, filename.c_str(), overwrite); + } + return m_file != nullptr; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Check file is opened. + /// + /// @return True on open or false on closed or failure + /// + bool IsOpen() const { return m_file != nullptr; } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Close an open file. + /// + void Close() + { + using namespace kodi::addon; + + if (!m_file) + return; + CAddonBase::m_interface->toKodi->kodi_filesystem->close_file( + CAddonBase::m_interface->toKodi->kodiBase, m_file); + m_file = nullptr; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Create a Curl representation + /// + /// @param[in] url The URL of the Type. + /// @return True on success or false on failure + /// + bool CURLCreate(const std::string& url) + { + using namespace kodi::addon; + + m_file = CAddonBase::m_interface->toKodi->kodi_filesystem->curl_create( + CAddonBase::m_interface->toKodi->kodiBase, url.c_str()); + return m_file != nullptr; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Add options to the curl file created with CURLCreate. + /// + /// @param[in] type Option type to set, see @ref CURLOptiontype + /// @param[in] name Name of the option + /// @param[in] value Value of the option + /// @return True on success or false on failure + /// + bool CURLAddOption(CURLOptiontype type, const std::string& name, const std::string& value) + { + using namespace kodi::addon; + + if (!m_file) + { + kodi::Log(ADDON_LOG_ERROR, "kodi::vfs::CURLCreate(...) needed to call before!"); + return false; + } + return CAddonBase::m_interface->toKodi->kodi_filesystem->curl_add_option( + CAddonBase::m_interface->toKodi->kodiBase, m_file, type, name.c_str(), value.c_str()); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Open the curl file created with CURLCreate. + /// + /// @param[in] flags [opt] The flags to pass, see @ref OpenFileFlags + /// @return True on success or false on failure + /// + bool CURLOpen(unsigned int flags = 0) + { + using namespace kodi::addon; + + if (!m_file) + { + kodi::Log(ADDON_LOG_ERROR, "kodi::vfs::CURLCreate(...) needed to call before!"); + return false; + } + return CAddonBase::m_interface->toKodi->kodi_filesystem->curl_open( + CAddonBase::m_interface->toKodi->kodiBase, m_file, flags); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Read from an open file. + /// + /// @param[in] ptr The buffer to store the data in. + /// @param[in] size The size of the buffer. + /// @return number of successfully read bytes if any bytes were read and + /// stored in buffer, zero if no bytes are available to read (end of + /// file was reached) or undetectable error occur, -1 in case of any + /// explicit error + /// + ssize_t Read(void* ptr, size_t size) + { + using namespace kodi::addon; + + if (!m_file) + return -1; + return CAddonBase::m_interface->toKodi->kodi_filesystem->read_file( + CAddonBase::m_interface->toKodi->kodiBase, m_file, ptr, size); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Read a string from an open file. + /// + /// @param[out] line The buffer to store the data in. + /// @return True when a line was read, false otherwise. + /// + bool ReadLine(std::string& line) + { + using namespace kodi::addon; + + line.clear(); + if (!m_file) + return false; + // TODO: Read 1024 chars into buffer. If file position advanced that many + // chars, we didn't hit a newline. Otherwise, if file position is 1 or 2 + // past the number of bytes read, we read (and skipped) a newline sequence. + char buffer[1025]; + if (CAddonBase::m_interface->toKodi->kodi_filesystem->read_file_string( + CAddonBase::m_interface->toKodi->kodiBase, m_file, buffer, sizeof(buffer))) + { + line = buffer; + return !line.empty(); + } + return false; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Write to a file opened in write mode. + /// + /// @param[in] ptr Pointer to the data to write, converted to a `const void*`. + /// @param[in] size Size of the data to write. + /// @return number of successfully written bytes if any bytes were written, + /// zero if no bytes were written and no detectable error occur,-1 + /// in case of any explicit error + /// + ssize_t Write(const void* ptr, size_t size) + { + using namespace kodi::addon; + + if (!m_file) + return -1; + return CAddonBase::m_interface->toKodi->kodi_filesystem->write_file( + CAddonBase::m_interface->toKodi->kodiBase, m_file, ptr, size); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Flush buffered data. + /// + /// If the given stream was open for writing (or if it was open for updating + /// and the last i/o operation was an output operation) any unwritten data + /// in its output buffer is written to the file. + /// + /// The stream remains open after this call. + /// + /// When a file is closed, either because of a call to close or because the + /// class is destructed, all the buffers associated with it are + /// automatically flushed. + /// + void Flush() + { + using namespace kodi::addon; + + if (!m_file) + return; + CAddonBase::m_interface->toKodi->kodi_filesystem->flush_file( + CAddonBase::m_interface->toKodi->kodiBase, m_file); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Set the file's current position. + /// + /// The whence argument is optional and defaults to SEEK_SET (0) + /// + /// @param[in] position the position that you want to seek to + /// @param[in] whence [optional] offset relative to You can set the value of + /// whence to one of three things: + /// | Value | int | Description | + /// |:--------:|:---:|:----------------------------------------------------| + /// | SEEK_SET | 0 | position is relative to the beginning of the file. This is probably what you had in mind anyway, and is the most commonly used value for whence. + /// | SEEK_CUR | 1 | position is relative to the current file pointer position. So, in effect, you can say, "Move to my current position plus 30 bytes," or, "move to my current position minus 20 bytes." + /// | SEEK_END | 2 | position is relative to the end of the file. Just like SEEK_SET except from the other end of the file. Be sure to use negative values for offset if you want to back up from the end of the file, instead of going past the end into oblivion. + /// + /// @return Returns the resulting offset location as measured in bytes from + /// the beginning of the file. On error, the value -1 is returned. + /// + int64_t Seek(int64_t position, int whence = SEEK_SET) + { + using namespace kodi::addon; + + if (!m_file) + return -1; + return CAddonBase::m_interface->toKodi->kodi_filesystem->seek_file( + CAddonBase::m_interface->toKodi->kodiBase, m_file, position, whence); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Truncate a file to the requested size. + /// + /// @param[in] size The new max size. + /// @return New size? On error, the value -1 is returned. + /// + int Truncate(int64_t size) + { + using namespace kodi::addon; + + if (!m_file) + return -1; + return CAddonBase::m_interface->toKodi->kodi_filesystem->truncate_file( + CAddonBase::m_interface->toKodi->kodiBase, m_file, size); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief The current offset in an open file. + /// + /// @return The requested offset. On error, the value -1 is returned. + /// + int64_t GetPosition() const + { + using namespace kodi::addon; + + if (!m_file) + return -1; + return CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_position( + CAddonBase::m_interface->toKodi->kodiBase, m_file); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Get the file size of an open file. + /// + /// @return The requested size. On error, the value -1 is returned. + /// + int64_t GetLength() const + { + using namespace kodi::addon; + + if (!m_file) + return -1; + return CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_length( + CAddonBase::m_interface->toKodi->kodiBase, m_file); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Checks the file access is on end position. + /// + /// @return If you've reached the end of the file, AtEnd() returns true. + /// + bool AtEnd() const + { + using namespace kodi::addon; + + if (!m_file) + return true; + int64_t length = CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_length( + CAddonBase::m_interface->toKodi->kodiBase, m_file); + int64_t position = CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_position( + CAddonBase::m_interface->toKodi->kodiBase, m_file); + return position >= length; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Get the chunk size for an open file. + /// + /// @return The requested size. On error, the value -1 is returned. + /// + int GetChunkSize() const + { + using namespace kodi::addon; + + if (!m_file) + return -1; + return CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_chunk_size( + CAddonBase::m_interface->toKodi->kodiBase, m_file); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief To check seek possible on current stream by file. + /// + /// @return true if seek possible, false if not + /// + bool IoControlGetSeekPossible() const + { + using namespace kodi::addon; + + if (!m_file) + return false; + return CAddonBase::m_interface->toKodi->kodi_filesystem->io_control_get_seek_possible( + CAddonBase::m_interface->toKodi->kodiBase, m_file); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief To check a running stream on file for state of his cache. + /// + /// @param[in] status Information about current cache status + /// @return true if successfull done, false otherwise + /// + /// + /// @copydetails cpp_kodi_vfs_Defs_CacheStatus_Help + /// + bool IoControlGetCacheStatus(CacheStatus& status) const + { + using namespace kodi::addon; + + if (!m_file) + return false; + return CAddonBase::m_interface->toKodi->kodi_filesystem->io_control_get_cache_status( + CAddonBase::m_interface->toKodi->kodiBase, m_file, status); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Unsigned int with speed limit for caching in bytes per second. + /// + /// @param[in] rate Cache rate size to use + /// @return true if successfull done, false otherwise + /// + bool IoControlSetCacheRate(unsigned int rate) + { + using namespace kodi::addon; + + if (!m_file) + return false; + return CAddonBase::m_interface->toKodi->kodi_filesystem->io_control_set_cache_rate( + CAddonBase::m_interface->toKodi->kodiBase, m_file, rate); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Enable/disable retry within the protocol handler (if supported). + /// + /// @param[in] retry To set the retry, true for use, false for not + /// @return true if successfull done, false otherwise + /// + bool IoControlSetRetry(bool retry) + { + using namespace kodi::addon; + + if (!m_file) + return false; + return CAddonBase::m_interface->toKodi->kodi_filesystem->io_control_set_retry( + CAddonBase::m_interface->toKodi->kodiBase, m_file, retry); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Retrieve a file property. + /// + /// @param[in] type The type of the file property to retrieve the value for + /// @param[in] name The name of a named property value (e.g. Header) + /// @return value of requested property, empty on failure / non-existance + /// + const std::string GetPropertyValue(FilePropertyTypes type, const std::string& name) const + { + using namespace kodi::addon; + + if (!m_file) + { + kodi::Log(ADDON_LOG_ERROR, + "kodi::vfs::CURLCreate(...) needed to call before GetPropertyValue!"); + return ""; + } + std::vector values = GetPropertyValues(type, name); + if (values.empty()) + { + return ""; + } + return values[0]; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Retrieve file property values. + /// + /// @param[in] type The type of the file property values to retrieve the value for + /// @param[in] name The name of the named property (e.g. Header) + /// @return values of requested property, empty vector on failure / non-existance + /// + const std::vector GetPropertyValues(FilePropertyTypes type, + const std::string& name) const + { + using namespace kodi::addon; + + if (!m_file) + { + kodi::Log(ADDON_LOG_ERROR, + "kodi::vfs::CURLCreate(...) needed to call before GetPropertyValues!"); + return std::vector(); + } + int numValues = 0; + char** res(CAddonBase::m_interface->toKodi->kodi_filesystem->get_property_values( + CAddonBase::m_interface->toKodi->kodiBase, m_file, type, name.c_str(), &numValues)); + if (res) + { + std::vector vecReturn; + for (int i = 0; i < numValues; ++i) + { + vecReturn.emplace_back(res[i]); + } + CAddonBase::m_interface->toKodi->free_string_array(CAddonBase::m_interface->toKodi->kodiBase, + res, numValues); + return vecReturn; + } + return std::vector(); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_vfs_CFile + /// @brief Get the current download speed of file if loaded from web. + /// + /// @return The current download speed. + /// + double GetFileDownloadSpeed() const + { + using namespace kodi::addon; + + if (!m_file) + return 0.0; + return CAddonBase::m_interface->toKodi->kodi_filesystem->get_file_download_speed( + CAddonBase::m_interface->toKodi->kodiBase, m_file); + } + //-------------------------------------------------------------------------- + +private: + void* m_file = nullptr; +}; +//@} +//------------------------------------------------------------------------------ + +//}}} + +} /* namespace vfs */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/General.h b/xbmc/addons/kodi-dev-kit/include/kodi/General.h new file mode 100644 index 0000000..3fad5a0 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/General.h @@ -0,0 +1,834 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "AddonBase.h" +#include "c-api/general.h" +#include "tools/StringUtils.h" + +#ifdef __cplusplus + +//============================================================================== +/// \ingroup cpp_kodi_Defs +/// @brief For kodi::Version used structure +/// +typedef struct kodi_version_t +{ + /// Application name, normally 'Kodi' + std::string compile_name; + /// Major code version of Kodi + int major; + /// Minor code version of Kodi + int minor; + /// The Revision contains a id and the build date, e.g. 20170706-c6b22fe217-dirty + std::string revision; + /// The version canditate e.g. alpha, beta or release + std::string tag; + /// The revision of tag before + std::string tag_revision; +} kodi_version_t; +//------------------------------------------------------------------------------ + +namespace kodi +{ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief Returns the value of an addon property as a string +/// +/// @param[in] id id of the property that the module needs to access +/// | | Choices are | | +/// |:------------:|:------------:|:------------:| +/// | author | icon | stars | +/// | changelog | id | summary | +/// | description | name | type | +/// | disclaimer | path | version | +/// | fanart | profile | | +/// +/// @return AddOn property as a string +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string addonName = kodi::GetAddonInfo("name"); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN GetAddonInfo(const std::string& id) +{ + using namespace kodi::addon; + + AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; + + std::string strReturn; + char* strMsg = toKodi->kodi->get_addon_info(toKodi->kodiBase, id.c_str()); + if (strMsg != nullptr) + { + if (std::strlen(strMsg)) + strReturn = strMsg; + toKodi->free_string(toKodi->kodiBase, strMsg); + } + return strReturn; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief Opens this Add-Ons settings dialog. +/// +/// @return true if settings were changed and the dialog confirmed, false otherwise. +/// +/// +/// -------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// .. +/// kodi::OpenSettings(); +/// .. +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN OpenSettings() +{ + using namespace kodi::addon; + return CAddonBase::m_interface->toKodi->kodi->open_settings_dialog( + CAddonBase::m_interface->toKodi->kodiBase); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief Returns an addon's localized 'unicode string'. +/// +/// @param[in] labelId string you want to localize +/// @param[in] defaultStr [opt] The default message, also helps to identify +/// the code that is used (default is +/// empty) +/// @return The localized message, or default if the add-on +/// helper fails to return a message +/// +/// @note Label id's \b 30000 to \b 30999 and \b 32000 to \b 32999 are related +/// to the add-on's own included strings from +/// ./resources/language/resource.language.??_??/strings.po +/// All other strings are from Kodi core language files. +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string str = kodi::GetLocalizedString(30005, "Use me as default"); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN GetLocalizedString(uint32_t labelId, + const std::string& defaultStr = "") +{ + using namespace kodi::addon; + + std::string retString = defaultStr; + char* strMsg = CAddonBase::m_interface->toKodi->kodi->get_localized_string( + CAddonBase::m_interface->toKodi->kodiBase, labelId); + if (strMsg != nullptr) + { + if (std::strlen(strMsg)) + retString = strMsg; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, strMsg); + } + return retString; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief Translate a string with an unknown encoding to UTF8. +/// +/// @param[in] stringSrc The string to translate. +/// @param[out] utf8StringDst The translated string. +/// @param[in] failOnBadChar [opt] returns failed if bad character is inside (default is false) +/// @return true if OK +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string ret; +/// if (!kodi::UnknownToUTF8("test string", ret, true)) +/// fprintf(stderr, "Translation to UTF8 failed!\n"); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN UnknownToUTF8(const std::string& stringSrc, + std::string& utf8StringDst, + bool failOnBadChar = false) +{ + using namespace kodi::addon; + + bool ret = false; + char* retString = CAddonBase::m_interface->toKodi->kodi->unknown_to_utf8( + CAddonBase::m_interface->toKodi->kodiBase, stringSrc.c_str(), &ret, failOnBadChar); + if (retString != nullptr) + { + if (ret) + utf8StringDst = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief Returns the active language as a string. +/// +/// @param[in] format Used format of the returned language string +/// | enum code: | Description: | +/// |----------------------:|------------------------------------------------------------| +/// | LANG_FMT_ENGLISH_NAME | full language name in English (Default) | +/// | LANG_FMT_ISO_639_1 | two letter code as defined in ISO 639-1 | +/// | LANG_FMT_ISO_639_2 | three letter code as defined in ISO 639-2/T or ISO 639-2/B | +/// @param[in] region [opt] append the region delimited by "-" of the language (setting) to the returned language string (default is false) +/// @return active language +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string language = kodi::GetLanguage(LANG_FMT_ISO_639_1, false); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN GetLanguage(LangFormats format = LANG_FMT_ENGLISH_NAME, + bool region = false) +{ + using namespace kodi::addon; + + std::string language; + char* retString = CAddonBase::m_interface->toKodi->kodi->get_language( + CAddonBase::m_interface->toKodi->kodiBase, format, region); + if (retString != nullptr) + { + if (std::strlen(retString)) + language = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return language; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief Writes the C string pointed by format in the GUI. If format includes +/// format specifiers (subsequences beginning with %), the additional arguments +/// following format are formatted and inserted in the resulting string replacing +/// their respective specifiers. +/// +/// After the format parameter, the function expects at least as many additional +/// arguments as specified by format. +/// +/// @param[in] type The message type. +/// | enum code: | Description: | +/// |---------------:|-----------------------------------| +/// | QUEUE_INFO | Show info notification message | +/// | QUEUE_WARNING | Show warning notification message | +/// | QUEUE_ERROR | Show error notification message | +/// @param[in] format The format of the message to pass to display in Kodi. +/// C string that contains the text to be written to the stream. +/// It can optionally contain embedded format specifiers that are +/// replaced by the values specified in subsequent additional +/// arguments and formatted as requested. +/// | specifier | Output | Example +/// |------------|----------------------------------------------------|------------ +/// | d or i | Signed decimal integer | 392 +/// | u | Unsigned decimal integer | 7235 +/// | o | Unsigned octal | 610 +/// | x | Unsigned hexadecimal integer | 7fa +/// | X | Unsigned hexadecimal integer (uppercase) | 7FA +/// | f | Decimal floating point, lowercase | 392.65 +/// | F | Decimal floating point, uppercase | 392.65 +/// | e | Scientific notation (mantissa/exponent), lowercase | 3.9265e+2 +/// | E | Scientific notation (mantissa/exponent), uppercase | 3.9265E+2 +/// | g | Use the shortest representation: %e or %f | 392.65 +/// | G | Use the shortest representation: %E or %F | 392.65 +/// | a | Hexadecimal floating point, lowercase | -0xc.90fep-2 +/// | A | Hexadecimal floating point, uppercase | -0XC.90FEP-2 +/// | c | Character | a +/// | s | String of characters | sample +/// | p | Pointer address | b8000000 +/// | % | A % followed by another % character will write a single % to the stream. | % +/// +/// The length sub-specifier modifies the length of the data type. This is a chart +/// showing the types used to interpret the corresponding arguments with and without +/// length specifier (if a different type is used, the proper type promotion or +/// conversion is performed, if allowed): +/// | length| d i | u o x X | f F e E g G a A | c | s | p | n | +/// |-------|---------------|-----------------------|-----------------|-------|---------|---------|-----------------| +/// | (none)| int | unsigned int | double | int | char* | void* | int* | +/// | hh | signed char | unsigned char | | | | | signed char* | +/// | h | short int | unsigned short int | | | | | short int* | +/// | l | long int | unsigned long int | | wint_t| wchar_t*| | long int* | +/// | ll | long long int | unsigned long long int| | | | | long long int* | +/// | j | intmax_t | uintmax_t | | | | | intmax_t* | +/// | z | size_t | size_t | | | | | size_t* | +/// | t | ptrdiff_t | ptrdiff_t | | | | | ptrdiff_t* | +/// | L | | | long double | | | | | +/// Note: that the c specifier takes an int (or wint_t) as argument, but performs the proper conversion to a char value +/// (or a wchar_t) before formatting it for output. +/// @param[in] ... (additional arguments) Depending on the format string, the function +/// may expect a sequence of additional arguments, each containing a value +/// to be used to replace a format specifier in the format string (or a pointer +/// to a storage location, for n). +/// There should be at least as many of these arguments as the number of values specified +/// in the format specifiers. Additional arguments are ignored by the function. +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// kodi::QueueFormattedNotification(QUEUE_WARNING, "I'm want to inform you, here with a test call to show '%s'", "this"); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline void ATTRIBUTE_HIDDEN QueueFormattedNotification(QueueMsg type, const char* format, ...) +{ + using namespace kodi::addon; + + va_list args; + va_start(args, format); + const std::string str = kodi::tools::StringUtils::FormatV(format, args); + va_end(args); + CAddonBase::m_interface->toKodi->kodi->queue_notification( + CAddonBase::m_interface->toKodi->kodiBase, type, "", str.c_str(), "", 5000, false, 1000); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief Queue a notification in the GUI. +/// +/// @param[in] type The message type. +/// | enum code: | Description: +/// |----------------------:|----------------------------------- +/// | QUEUE_INFO | Show info notification message +/// | QUEUE_WARNING | Show warning notification message +/// | QUEUE_ERROR | Show error notification message +/// | QUEUE_OWN_STYLE | If used can be with imageFile the wanted image set or if leaved empty shown as info, also are the other optional values available then +/// @param[in] header Header Name (if leaved empty becomes addon name used) +/// @param[in] message Message to display on Kodi +/// @param[in] imageFile [opt] The image file to show on message (to use must be type set to QUEUE_OWN_STYLE) +/// @param[in] displayTime [opt] The time how long message is displayed (default 5 sec) (to use must be type set to QUEUE_OWN_STYLE) +/// @param[in] withSound [opt] if true also warning sound becomes played (default with sound) (to use must be type set to QUEUE_OWN_STYLE) +/// @param[in] messageTime [opt] how many milli seconds start show of notification (default 1 sec) (to use must be type set to QUEUE_OWN_STYLE) +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// kodi::QueueNotification(QUEUE_OWN_STYLE, "I'm want to inform you", "Here with a test call", "", 3000, false, 1000); +/// ... +/// ~~~~~~~~~~~~~ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// kodi::QueueNotification(QUEUE_WARNING, "I'm want to inform you", "Here with a test call"); +/// ... +/// ~~~~~~~~~~~~~ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// kodi::QueueNotification(QUEUE_OWN_STYLE, "", "Here with a test call", "./myImage.png"); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline void ATTRIBUTE_HIDDEN QueueNotification(QueueMsg type, + const std::string& header, + const std::string& message, + const std::string& imageFile = "", + unsigned int displayTime = 5000, + bool withSound = true, + unsigned int messageTime = 1000) +{ + using namespace kodi::addon; + + CAddonBase::m_interface->toKodi->kodi->queue_notification( + CAddonBase::m_interface->toKodi->kodiBase, type, header.c_str(), message.c_str(), + imageFile.c_str(), displayTime, withSound, messageTime); +} +//------------------------------------------------------------------------------ + +//============================================================================ +/// \ingroup cpp_kodi +/// @brief Get the MD5 digest of the given text +/// +/// @param[in] text text to compute the MD5 for +/// @return Returned MD5 digest +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string md5 = kodi::GetMD5("Make me as md5"); +/// fprintf(stderr, "My md5 digest is: '%s'\n", md5.c_str()); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN GetMD5(const std::string& text) +{ + using namespace kodi::addon; + + char* md5ret = static_cast(malloc(40 * sizeof(char))); // md5 size normally 32 bytes + CAddonBase::m_interface->toKodi->kodi->get_md5(CAddonBase::m_interface->toKodi->kodiBase, + text.c_str(), md5ret); + std::string md5 = md5ret; + free(md5ret); + return md5; +} +//---------------------------------------------------------------------------- + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief To get a temporary path for the addon +/// +/// This gives a temporary path which the addon can use individually for its things. +/// +/// The content of this folder will be deleted when Kodi is finished! +/// +/// @param[in] append A string to append to returned temporary path +/// @return Individual path for the addon +/// +inline std::string ATTRIBUTE_HIDDEN GetTempAddonPath(const std::string& append = "") +{ + using namespace kodi::addon; + + char* str = CAddonBase::m_interface->toKodi->kodi->get_temp_path( + CAddonBase::m_interface->toKodi->kodiBase); + std::string ret = str; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, str); + if (!append.empty()) + { + if (append.at(0) != '\\' && append.at(0) != '/') +#ifdef TARGET_WINDOWS + ret.append("\\"); +#else + ret.append("/"); +#endif + ret.append(append); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief Returns your regions setting as a string for the specified id +/// +/// @param[in] id id of setting to return +/// | | Choices are | | +/// |:------------:|:------------:|:------------:| +/// | dateshort | time | tempunit | +/// | datelong | meridiem | speedunit | +/// +/// @return settings string +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string timeFormat = kodi::GetRegion("time"); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN GetRegion(const std::string& id) +{ + using namespace kodi::addon; + + AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; + + std::string strReturn; + char* strMsg = toKodi->kodi->get_region(toKodi->kodiBase, id.c_str()); + if (strMsg != nullptr) + { + if (std::strlen(strMsg)) + strReturn = strMsg; + toKodi->free_string(toKodi->kodiBase, strMsg); + } + return strReturn; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief Returns the amount of free memory in MByte (or as bytes) as an long +/// integer +/// +/// @param[out] free free memory +/// @param[out] total total memory +/// @param[in] asBytes [opt] if set to true becomes returned as bytes, otherwise +/// as mega bytes +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// long freeMem; +/// long totalMem; +/// kodi::GetFreeMem(freeMem, totalMem); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline void ATTRIBUTE_HIDDEN GetFreeMem(long& free, long& total, bool asBytes = false) +{ + using namespace kodi::addon; + + free = -1; + total = -1; + AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; + toKodi->kodi->get_free_mem(toKodi->kodiBase, &free, &total, asBytes); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief Returns the elapsed idle time in seconds as an integer +/// +/// @return idle time +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// int time = kodi::GetGlobalIdleTime(); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline int ATTRIBUTE_HIDDEN GetGlobalIdleTime() +{ + using namespace kodi::addon; + + AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; + return toKodi->kodi->get_global_idle_time(toKodi->kodiBase); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief Get the currently used skin identification name from Kodi +/// +/// @return The active skin id name as a string +/// +/// +/// @note This is not the full path like 'special://home/addons/MediaCenter', +/// but only 'MediaCenter'. +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// .. +/// std::string skinid = kodi::GetCurrentSkinId(); +/// .. +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN GetCurrentSkinId() +{ + using namespace kodi::addon; + + AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; + + std::string strReturn; + char* strMsg = toKodi->kodi->get_current_skin_id(toKodi->kodiBase); + if (strMsg != nullptr) + { + if (std::strlen(strMsg)) + strReturn = strMsg; + toKodi->free_string(toKodi->kodiBase, strMsg); + } + return strReturn; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @brief To check another addon is available and usable inside Kodi. +/// +/// @param[in] id The wanted addon identification string to check +/// @param[out] version Version string of addon if **installed** inside Kodi +/// @param[out] enabled Set to true `true* if addon is enabled +/// @return Returns `true* if addon is installed +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// bool enabled = false; +/// std::string version; +/// bool ret = kodi::IsAddonAvailable("inputstream.adaptive", version, enabled); +/// fprintf(stderr, "Available inputstream.adaptive version '%s' and enabled '%s'\n", +/// ret ? version.c_str() : "not installed", enabled ? "yes" : "no"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN IsAddonAvailable(const std::string& id, + std::string& version, + bool& enabled) +{ + using namespace kodi::addon; + + AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; + + char* cVersion = nullptr; + bool ret = toKodi->kodi->is_addon_avilable(toKodi->kodiBase, id.c_str(), &cVersion, &enabled); + if (cVersion) + { + version = cVersion; + toKodi->free_string(toKodi->kodiBase, cVersion); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief Get current Kodi informations and versions, returned data from the following +/// kodi_version_t version; kodi::KodiVersion(version); +/// is e.g.: +/// ~~~~~~~~~~~~~{.cpp} +/// version.compile_name = Kodi +/// version.major = 18 +/// version.minor = 0 +/// version.revision = 20170706-c6b22fe217-di +/// version.tag = alpha +/// version.tag_revision = 1 +/// ~~~~~~~~~~~~~ +/// +/// @param[out] version structure to store data from kodi +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// kodi_version_t version; +/// kodi::KodiVersion(version); +/// fprintf(stderr, +/// "kodi_version_t version;\n" +/// "kodi::KodiVersion(version);\n" +/// " - version.compile_name = %s\n" +/// " - version.major = %i\n" +/// " - version.minor = %i\n" +/// " - version.revision = %s\n" +/// " - version.tag = %s\n" +/// " - version.tag_revision = %s\n", +/// version.compile_name.c_str(), version.major, version.minor, +/// version.revision.c_str(), version.tag.c_str(), version.tag_revision.c_str()); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline void ATTRIBUTE_HIDDEN KodiVersion(kodi_version_t& version) +{ + using namespace kodi::addon; + + char* compile_name = nullptr; + char* revision = nullptr; + char* tag = nullptr; + char* tag_revision = nullptr; + + AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; + toKodi->kodi->kodi_version(toKodi->kodiBase, &compile_name, &version.major, &version.minor, + &revision, &tag, &tag_revision); + if (compile_name != nullptr) + { + version.compile_name = compile_name; + toKodi->free_string(toKodi->kodiBase, compile_name); + } + if (revision != nullptr) + { + version.revision = revision; + toKodi->free_string(toKodi->kodiBase, revision); + } + if (tag != nullptr) + { + version.tag = tag; + toKodi->free_string(toKodi->kodiBase, tag); + } + if (tag_revision != nullptr) + { + version.tag_revision = tag_revision; + toKodi->free_string(toKodi->kodiBase, tag_revision); + } +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief To get keyboard layout characters +/// +/// This is used to get the keyboard layout currently used from Kodi by the +/// there set language. +/// +/// @param[in] modifierKey the key to define the needed layout (uppercase, symbols...) +/// @param[out] layout_name name of used layout +/// @param[out] layout list of selected keyboard layout +/// @return true if request successed +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string layout_name; +/// std::vector> layout; +/// kodi::GetKeyboardLayout(STD_KB_MODIFIER_KEY_SHIFT | STD_KB_MODIFIER_KEY_SYMBOL, layout_name, layout); +/// fprintf(stderr, "Layout: '%s'\n", layout_name.c_str()); +/// for (unsigned int row = 0; row < STD_KB_BUTTONS_MAX_ROWS; row++) +/// { +/// for (unsigned int column = 0; column < STD_KB_BUTTONS_PER_ROW; column++) +/// { +/// fprintf(stderr, " - Row: '%02i'; Column: '%02i'; Text: '%s'\n", row, column, layout[row][column].c_str()); +/// } +/// } +/// ... +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN GetKeyboardLayout(int modifierKey, + std::string& layout_name, + std::vector>& layout) +{ + using namespace kodi::addon; + + AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; + AddonKeyboardKeyTable c_layout; + char* c_layout_name = nullptr; + bool ret = + toKodi->kodi->get_keyboard_layout(toKodi->kodiBase, &c_layout_name, modifierKey, &c_layout); + if (ret) + { + if (c_layout_name) + { + layout_name = c_layout_name; + toKodi->free_string(toKodi->kodiBase, c_layout_name); + } + + layout.resize(STD_KB_BUTTONS_MAX_ROWS); + for (unsigned int row = 0; row < STD_KB_BUTTONS_MAX_ROWS; row++) + { + layout[row].resize(STD_KB_BUTTONS_PER_ROW); + for (unsigned int column = 0; column < STD_KB_BUTTONS_PER_ROW; column++) + { + char* button = c_layout.keys[row][column]; + if (button) + { + layout[row][column] = button; + toKodi->free_string(toKodi->kodiBase, button); + } + } + } + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// \ingroup cpp_kodi +/// @brief To change keyboard layout characters +/// +/// This is used to change the keyboard layout currently used from Kodi +/// +/// @param[out] layout_name new name of used layout (input string not used!) +/// @return true if request successed +/// +/// @note \ref GetKeyboardLayout must be called afterwards. +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string layout_name; +/// kodi::ChangeKeyboardLayout(layout_name); +/// +/// std::vector> layout; +/// kodi::GetKeyboardLayout(STD_KB_MODIFIER_KEY_SHIFT | STD_KB_MODIFIER_KEY_SYMBOL, layout_name, layout); +/// fprintf(stderr, "Layout: '%s'\n", layout_name.c_str()); +/// for (unsigned int row = 0; row < STD_KB_BUTTONS_MAX_ROWS; row++) +/// { +/// for (unsigned int column = 0; column < STD_KB_BUTTONS_PER_ROW; column++) +/// { +/// fprintf(stderr, " - Row: '%02i'; Column: '%02i'; Text: '%s'\n", row, column, layout[row][column].c_str()); +/// } +/// } +/// ... +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN ChangeKeyboardLayout(std::string& layout_name) +{ + using namespace kodi::addon; + + AddonToKodiFuncTable_Addon* toKodi = CAddonBase::m_interface->toKodi; + char* c_layout_name = nullptr; + bool ret = toKodi->kodi->change_keyboard_layout(toKodi->kodiBase, &c_layout_name); + if (c_layout_name) + { + layout_name = c_layout_name; + toKodi->free_string(toKodi->kodiBase, c_layout_name); + } + + return ret; +} +//------------------------------------------------------------------------------ + +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/Network.h b/xbmc/addons/kodi-dev-kit/include/kodi/Network.h new file mode 100644 index 0000000..910385f --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/Network.h @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "AddonBase.h" +#include "c-api/network.h" + +#ifdef __cplusplus + +//============================================================================== +/// @defgroup cpp_kodi_network Interface - kodi::network +/// @ingroup cpp +/// @brief **Network functions**\n +/// The network module offers functions that allow you to control it. +/// +/// It has the header @ref Network.h "#include " be included +/// to enjoy it. +/// +//------------------------------------------------------------------------------ + +namespace kodi +{ +namespace network +{ + +//============================================================================ +/// @ingroup cpp_kodi_network +/// @brief Send WakeOnLan magic packet. +/// +/// @param[in] mac Network address of the host to wake. +/// @return True if the magic packet was successfully sent, false otherwise. +/// +inline bool ATTRIBUTE_HIDDEN WakeOnLan(const std::string& mac) +{ + using namespace ::kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_network->wake_on_lan( + CAddonBase::m_interface->toKodi->kodiBase, mac.c_str()); +} +//---------------------------------------------------------------------------- + +//============================================================================ +/// @ingroup cpp_kodi_network +/// @brief To the current own ip address as a string. +/// +/// @return Own system ip. +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string ipAddress = kodi::network::GetIPAddress(); +/// fprintf(stderr, "My IP is '%s'\n", ipAddress.c_str()); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN GetIPAddress() +{ + using namespace ::kodi::addon; + + std::string ip; + char* string = CAddonBase::m_interface->toKodi->kodi_network->get_ip_address( + CAddonBase::m_interface->toKodi->kodiBase); + if (string != nullptr) + { + ip = string; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, string); + } + return ip; +} +//---------------------------------------------------------------------------- + +//============================================================================ +/// @ingroup cpp_kodi_network +/// @brief Return our hostname. +/// +/// @return String about hostname, empty in case of error +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string hostname = kodi::network::GetHostname(); +/// fprintf(stderr, "My hostname is '%s'\n", hostname.c_str()); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline std::string ATTRIBUTE_HIDDEN GetHostname() +{ + using namespace ::kodi::addon; + + std::string ip; + char* string = CAddonBase::m_interface->toKodi->kodi_network->get_hostname( + CAddonBase::m_interface->toKodi->kodiBase); + if (string != nullptr) + { + ip = string; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, string); + } + return ip; +} +//---------------------------------------------------------------------------- + +//============================================================================ +/// @ingroup cpp_kodi_network +/// @brief Returns Kodi's HTTP UserAgent string. +/// +/// @return HTTP user agent +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.py} +/// .. +/// std::string agent = kodi::network::GetUserAgent() +/// .. +/// ~~~~~~~~~~~~~ +/// +/// example output: +/// Kodi/19.0-ALPHA1 (X11; Linux x86_64) Ubuntu/20.04 App_Bitness/64 Version/19.0-ALPHA1-Git:20200522-0076d136d3-dirty +/// +inline std::string ATTRIBUTE_HIDDEN GetUserAgent() +{ + using namespace ::kodi::addon; + + std::string agent; + char* string = CAddonBase::m_interface->toKodi->kodi_network->get_user_agent( + CAddonBase::m_interface->toKodi->kodiBase); + if (string != nullptr) + { + agent = string; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, string); + } + return agent; +} +//---------------------------------------------------------------------------- + +//============================================================================ +/// @ingroup cpp_kodi_network +/// @brief Check given name or ip address corresponds to localhost. +/// +/// @param[in] hostname Hostname to check +/// @return Return true if given name or ip address corresponds to localhost +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// if (kodi::network::IsLocalHost("127.0.0.1")) +/// fprintf(stderr, "Is localhost\n"); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN IsLocalHost(const std::string& hostname) +{ + using namespace ::kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_network->is_local_host( + CAddonBase::m_interface->toKodi->kodiBase, hostname.c_str()); +} +//---------------------------------------------------------------------------- + +//============================================================================== +/// @ingroup cpp_kodi_network +/// @brief Checks whether the specified path refers to a local network. +/// +/// @param[in] hostname Hostname to check +/// @param[in] offLineCheck Check if in private range, see https://en.wikipedia.org/wiki/Private_network +/// @return True if host is on a LAN, false otherwise +/// +inline bool ATTRIBUTE_HIDDEN IsHostOnLAN(const std::string& hostname, bool offLineCheck = false) +{ + using namespace kodi::addon; + + return CAddonBase::m_interface->toKodi->kodi_network->is_host_on_lan( + CAddonBase::m_interface->toKodi->kodiBase, hostname.c_str(), offLineCheck); +} +//------------------------------------------------------------------------------ + +//============================================================================ +/// @ingroup cpp_kodi_network +/// @brief URL encodes the given string +/// +/// This function converts the given input string to a URL encoded string and +/// returns that as a new allocated string. All input characters that are +/// not a-z, A-Z, 0-9, '-', '.', '_' or '~' are converted to their "URL escaped" +/// version (%NN where NN is a two-digit hexadecimal number). +/// +/// @param[in] url The code of the message to get. +/// @return Encoded URL string +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string encodedUrl = kodi::network::URLEncode("François"); +/// fprintf(stderr, "Encoded URL is '%s'\n", encodedUrl.c_str()); +/// ... +/// ~~~~~~~~~~~~~ +/// For example, the string: François ,would be encoded as: Fran%C3%A7ois +/// +inline std::string ATTRIBUTE_HIDDEN URLEncode(const std::string& url) +{ + using namespace ::kodi::addon; + + std::string retString; + char* string = CAddonBase::m_interface->toKodi->kodi_network->url_encode( + CAddonBase::m_interface->toKodi->kodiBase, url.c_str()); + if (string != nullptr) + { + retString = string; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, string); + } + return retString; +} +//---------------------------------------------------------------------------- + +//============================================================================ +/// @ingroup cpp_kodi_network +/// @brief Lookup URL in DNS cache +/// +/// This test will get DNS record for a domain. The DNS lookup is done directly +/// against the domain's authoritative name server, so changes to DNS Records +/// should show up instantly. By default, the DNS lookup tool will return an +/// IP address if you give it a name (e.g. www.example.com) +/// +/// @param[in] hostName The code of the message to get. +/// @param[out] ipAddress Returned address +/// @return true if successfull +/// +/// +/// ------------------------------------------------------------------------ +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// std::string ipAddress; +/// bool ret = kodi::network::DNSLookup("www.google.com", ipAddress); +/// fprintf(stderr, "DNSLookup returned for www.google.com the IP '%s', call was %s\n", ipAddress.c_str(), ret ? "ok" : "failed"); +/// ... +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN DNSLookup(const std::string& hostName, std::string& ipAddress) +{ + using namespace ::kodi::addon; + + bool ret = false; + char* string = CAddonBase::m_interface->toKodi->kodi_network->dns_lookup( + CAddonBase::m_interface->toKodi->kodiBase, hostName.c_str(), &ret); + if (string != nullptr) + { + ipAddress = string; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, string); + } + return ret; +} +//---------------------------------------------------------------------------- + +} /* namespace network */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/StreamCodec.h b/xbmc/addons/kodi-dev-kit/include/kodi/StreamCodec.h new file mode 100644 index 0000000..e030371 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/StreamCodec.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================== + /// @ingroup cpp_kodi_addon_videocodec_Defs_VIDEOCODEC_INITDATA + /// @brief The standard defines several sets of capabilities, which are referred + /// to as profiles, targeting specific classes of applications. + //@{ + enum STREAMCODEC_PROFILE + { + /// @brief Unknown codec profile + CodecProfileUnknown = 0, + + /// @brief If a codec profile is not required + CodecProfileNotNeeded, + + /// @brief **H264** Baseline Profile (BP, 66) + /// + /// Primarily for low-cost applications that require additional data loss + /// robustness, this profile is used in some videoconferencing and mobile + /// applications. This profile includes all features that are supported + /// in the Constrained Baseline Profile, plus three additional features + /// that can be used for loss robustness (or for other purposes such as + /// low-delay multi-point video stream compositing). The importance of + /// this profile has faded somewhat since the definition of the Constrained + /// Baseline Profile in 2009. All Constrained Baseline Profile bitstreams + /// are also considered to be Baseline Profile bitstreams, as these two + /// profiles share the same profile identifier code value. + H264CodecProfileBaseline, + + /// @brief **H264** Main Profile (MP, 77) + /// + /// This profile is used for standard-definition digital TV broadcasts that + /// use the MPEG-4 format as defined in the + /// [DVB standard](http://www.etsi.org/deliver/etsi_ts/101100_101199/101154/01.09.01_60/ts_101154v010901p.pdf). + /// It is not, however, used for high-definition television broadcasts, as the + /// importance of this profile faded when the High Profile was developed + /// in 2004 for that application. + H264CodecProfileMain, + + /// @brief **H264** Extended Profile (XP, 88) + /// + /// Intended as the streaming video profile, this profile has relatively high + /// compression capability and some extra tricks for robustness to data losses + /// and server stream switching. + H264CodecProfileExtended, + + /// @brief **H264** High Profile (HiP, 100) + /// + /// The primary profile for broadcast and disc storage applications, + /// particularly for high-definition television applications (for example, + /// this is the profile adopted by the [Blu-ray Disc](https://en.wikipedia.org/wiki/Blu-ray_Disc) + /// storage format and the [DVB](https://en.wikipedia.org/wiki/Digital_Video_Broadcasting) + /// HDTV broadcast service). + H264CodecProfileHigh, + + /// @brief **H264** High 10 Profile (Hi10P, 110) + /// + /// Going beyond typical mainstream consumer product capabilities, this + /// profile builds on top of the High Profile, adding support for up to 10 + /// bits per sample of decoded picture precision. + H264CodecProfileHigh10, + + /// @brief **H264** High 4:2:2 Profile (Hi422P, 122) + /// + /// Primarily targeting professional applications that use interlaced video, + /// this profile builds on top of the High 10 Profile, adding support for the + /// 4:2:2 chroma sampling format while using up to 10 bits per sample of + /// decoded picture precision. + H264CodecProfileHigh422, + + /// @brief **H264** High 4:4:4 Predictive Profile (Hi444PP, 244) + /// + /// This profile builds on top of the High 4:2:2 Profile, supporting up to + /// 4:4:4 chroma sampling, up to 14 bits per sample, and additionally + /// supporting efficient lossless region coding and the coding of each + /// picture as three separate color planes. + H264CodecProfileHigh444Predictive, + + /// @brief **VP9** profile 0 + /// + /// There are several variants of the VP9 format (known as "coding profiles"), + /// which successively allow more features; profile 0 is the basic variant, + /// requiring the least from a hardware implementation. + /// + /// [Color depth](https://en.wikipedia.org/wiki/Color_depth): 8 bit/sample, + /// [chroma subsampling](https://en.wikipedia.org/wiki/Chroma_subsampling): 4:2:0 + VP9CodecProfile0 = 20, + + /// @brief **VP9** profile 1 + /// + /// [Color depth](https://en.wikipedia.org/wiki/Color_depth): 8 bit, + /// [chroma subsampling](https://en.wikipedia.org/wiki/Chroma_subsampling): 4:2:0, 4:2:2, 4:4:4 + VP9CodecProfile1, + + /// @brief **VP9** profile 2 + /// + /// [Color depth](https://en.wikipedia.org/wiki/Color_depth): 10–12 bit, + /// [chroma subsampling](https://en.wikipedia.org/wiki/Chroma_subsampling): 4:2:0 + VP9CodecProfile2, + + /// @brief **VP9** profile 3 + /// + /// [Color depth](https://en.wikipedia.org/wiki/Color_depth): 10–12 bit, + /// [chroma subsampling](https://en.wikipedia.org/wiki/Chroma_subsampling): 4:2:0, 4:2:2, 4:4:4, + /// see [VP9 Bitstream & Decoding Process Specification](https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf) + VP9CodecProfile3, + }; + //@} + //------------------------------------------------------------------------------ + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/StreamCrypto.h b/xbmc/addons/kodi-dev-kit/include/kodi/StreamCrypto.h new file mode 100644 index 0000000..8008aa1 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/StreamCrypto.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include + +#define STREAMCRYPTO_VERSION_LEVEL 1 + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct CRYPTO_INFO + { + enum CRYPTO_KEY_SYSTEM : uint8_t + { + CRYPTO_KEY_SYSTEM_NONE = 0, + CRYPTO_KEY_SYSTEM_WIDEVINE, + CRYPTO_KEY_SYSTEM_PLAYREADY, + CRYPTO_KEY_SYSTEM_WISEPLAY, + CRYPTO_KEY_SYSTEM_COUNT + } m_CryptoKeySystem; /*!< @brief keysystem for encrypted media, KEY_SYSTEM_NONE for unencrypted media */ + + static const uint8_t FLAG_SECURE_DECODER = + 1; /*!< @brief is set in flags if decoding has to be done in TEE environment */ + + uint8_t flags; + uint16_t m_CryptoSessionIdSize; /*!< @brief The size of the crypto session key id */ + const char* m_CryptoSessionId; /*!< @brief The crypto session key id */ + } CRYPTO_INFO; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/AudioDecoder.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/AudioDecoder.h new file mode 100644 index 0000000..a6bea7d --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/AudioDecoder.h @@ -0,0 +1,595 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../AddonBase.h" +#include "../AudioEngine.h" +#include "../c-api/addon-instance/audio_decoder.h" + +#ifdef __cplusplus +namespace kodi +{ +namespace addon +{ + +class CInstanceAudioDecoder; + +//============================================================================== +/// @defgroup cpp_kodi_addon_audiodecoder_Defs_AudioDecoderInfoTag class AudioDecoderInfoTag +/// @ingroup cpp_kodi_addon_audiodecoder_Defs +/// @brief **Info tag data structure**\n +/// Representation of available information of processed audio file. +/// +/// This is used to store all the necessary data of audio stream and to have on +/// e.g. GUI for information. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_audiodecoder_Defs_AudioDecoderInfoTag_Help +/// +///@{ +class AudioDecoderInfoTag : public CStructHdl +{ + /*! \cond PRIVATE */ + friend class CInstanceAudioDecoder; + /*! \endcond */ + +public: + /*! \cond PRIVATE */ + AudioDecoderInfoTag() { memset(m_cStructure, 0, sizeof(AUDIO_DECODER_INFO_TAG)); } + AudioDecoderInfoTag(const AudioDecoderInfoTag& tag) : CStructHdl(tag) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_audiodecoder_Defs_AudioDecoderInfoTag_Help Value Help + /// @ingroup cpp_kodi_addon_audiodecoder_Defs_AudioDecoderInfoTag + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_audiodecoder_Defs_AudioDecoderInfoTag : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **Title** | `std::string` | @ref AudioDecoderInfoTag::SetTitle "SetTitle" | @ref AudioDecoderInfoTag::GetTitle "GetTitle" + /// | **Artist** | `std::string` | @ref AudioDecoderInfoTag::SetArtist "SetArtist" | @ref AudioDecoderInfoTag::GetArtist "GetArtist" + /// | **Album** | `std::string` | @ref AudioDecoderInfoTag::SetAlbum "SetAlbum" | @ref AudioDecoderInfoTag::GetAlbum "GetAlbum" + /// | **Album artist** | `std::string` | @ref AudioDecoderInfoTag::SetAlbumArtist "SetAlbumArtist" | @ref AudioDecoderInfoTag::GetAlbumArtist "GetAlbumArtist" + /// | **Media type** | `std::string` | @ref AudioDecoderInfoTag::SetMediaType "SetMediaType" | @ref AudioDecoderInfoTag::GetMediaType "GetMediaType" + /// | **Genre** | `std::string` | @ref AudioDecoderInfoTag::SetGenre "SetGenre" | @ref AudioDecoderInfoTag::GetGenre "GetGenre" + /// | **Duration** | `int` | @ref AudioDecoderInfoTag::SetDuration "SetDuration" | @ref AudioDecoderInfoTag::GetDuration "GetDuration" + /// | **Track number** | `int` | @ref AudioDecoderInfoTag::SetTrack "SetTrack" | @ref AudioDecoderInfoTag::GetTrack "GetTrack" + /// | **Disc number** | `int` | @ref AudioDecoderInfoTag::SetDisc "SetDisc" | @ref AudioDecoderInfoTag::GetDisc "GetDisc" + /// | **Disc subtitle name** | `std::string` | @ref AudioDecoderInfoTag::SetDiscSubtitle "SetDiscSubtitle" | @ref AudioDecoderInfoTag::GetDiscSubtitle "GetDiscSubtitle" + /// | **Disc total amount** | `int` | @ref AudioDecoderInfoTag::SetDiscTotal "SetDiscTotal" | @ref AudioDecoderInfoTag::GetDiscTotal "GetDiscTotal" + /// | **Release date** | `std::string` | @ref AudioDecoderInfoTag::SetReleaseDate "SetReleaseDate" | @ref AudioDecoderInfoTag::GetReleaseDate "GetReleaseDate" + /// | **Lyrics** | `std::string` | @ref AudioDecoderInfoTag::SetLyrics "SetLyrics" | @ref AudioDecoderInfoTag::GetLyrics "GetLyrics" + /// | **Samplerate** | `int` | @ref AudioDecoderInfoTag::SetSamplerate "SetSamplerate" | @ref AudioDecoderInfoTag::GetSamplerate "GetSamplerate" + /// | **Channels amount** | `int` | @ref AudioDecoderInfoTag::SetChannels "SetChannels" | @ref AudioDecoderInfoTag::GetChannels "GetChannels" + /// | **Bitrate** | `int` | @ref AudioDecoderInfoTag::SetBitrate "SetBitrate" | @ref AudioDecoderInfoTag::GetBitrate "GetBitrate" + /// | **Comment text** | `std::string` | @ref AudioDecoderInfoTag::SetComment "SetComment" | @ref AudioDecoderInfoTag::GetComment "GetComment" + /// + + /// @addtogroup cpp_kodi_addon_audiodecoder_Defs_AudioDecoderInfoTag + ///@{ + + /// @brief Set the title from music as string on info tag. + void SetTitle(const std::string& title) + { + strncpy(m_cStructure->title, title.c_str(), sizeof(m_cStructure->title) - 1); + } + + /// @brief Get title name + std::string GetTitle() const { return m_cStructure->title; } + + /// @brief Set artist name + void SetArtist(const std::string& artist) + { + strncpy(m_cStructure->artist, artist.c_str(), sizeof(m_cStructure->artist) - 1); + } + + /// @brief Get artist name + std::string GetArtist() const { return m_cStructure->artist; } + + /// @brief Set album name + void SetAlbum(const std::string& album) + { + strncpy(m_cStructure->album, album.c_str(), sizeof(m_cStructure->album) - 1); + } + + /// @brief Set album name + std::string GetAlbum() const { return m_cStructure->album; } + + /// @brief Set album artist name + void SetAlbumArtist(const std::string& albumArtist) + { + strncpy(m_cStructure->album_artist, albumArtist.c_str(), + sizeof(m_cStructure->album_artist) - 1); + } + + /// @brief Get album artist name + std::string GetAlbumArtist() const { return m_cStructure->album_artist; } + + /// @brief Set the media type of the music item. + /// + /// Available strings about media type for music: + /// | String | Description | + /// |---------------:|:--------------------------------------------------| + /// | artist | If it is defined as an artist + /// | album | If it is defined as an album + /// | music | If it is defined as an music + /// | song | If it is defined as a song + /// + void SetMediaType(const std::string& mediaType) + { + strncpy(m_cStructure->media_type, mediaType.c_str(), sizeof(m_cStructure->media_type) - 1); + } + + /// @brief Get the media type of the music item. + std::string GetMediaType() const { return m_cStructure->media_type; } + + /// @brief Set genre name from music as string if present. + void SetGenre(const std::string& genre) + { + strncpy(m_cStructure->genre, genre.c_str(), sizeof(m_cStructure->genre) - 1); + } + + /// @brief Get genre name from music as string if present. + std::string GetGenre() const { return m_cStructure->genre; } + + /// @brief Set the duration of music as integer from info. + void SetDuration(int duration) { m_cStructure->duration = duration; } + + /// @brief Get the duration of music as integer from info. + int GetDuration() const { return m_cStructure->duration; } + + /// @brief Set track number (if present) from music info as integer. + void SetTrack(int track) { m_cStructure->track = track; } + + /// @brief Get track number (if present). + int GetTrack() const { return m_cStructure->track; } + + /// @brief Set disk number (if present) from music info as integer. + void SetDisc(int disc) { m_cStructure->disc = disc; } + + /// @brief Get disk number (if present) + int GetDisc() const { return m_cStructure->disc; } + + /// @brief Set disk subtitle name (if present) from music info. + void SetDiscSubtitle(const std::string& discSubtitle) + { + strncpy(m_cStructure->disc_subtitle, discSubtitle.c_str(), + sizeof(m_cStructure->disc_subtitle) - 1); + } + + /// @brief Get disk subtitle name (if present) from music info. + std::string GetDiscSubtitle() const { return m_cStructure->disc_subtitle; } + + /// @brief Set disks amount quantity (if present) from music info as integer. + void SetDiscTotal(int discTotal) { m_cStructure->disc_total = discTotal; } + + /// @brief Get disks amount quantity (if present) + int GetDiscTotal() const { return m_cStructure->disc_total; } + + /// @brief Set release date as string from music info (if present).\n + /// [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) date YYYY, YYYY-MM or YYYY-MM-DD + void SetReleaseDate(const std::string& releaseDate) + { + strncpy(m_cStructure->release_date, releaseDate.c_str(), + sizeof(m_cStructure->release_date) - 1); + } + + /// @brief Get release date as string from music info (if present). + std::string GetReleaseDate() const { return m_cStructure->release_date; } + + /// @brief Set string from lyrics. + void SetLyrics(const std::string& lyrics) + { + strncpy(m_cStructure->lyrics, lyrics.c_str(), sizeof(m_cStructure->lyrics) - 1); + } + + /// @brief Get string from lyrics. + std::string GetLyrics() const { return m_cStructure->lyrics; } + + /// @brief Set related stream samplerate. + void SetSamplerate(int samplerate) { m_cStructure->samplerate = samplerate; } + + /// @brief Get related stream samplerate. + int GetSamplerate() const { return m_cStructure->samplerate; } + + /// @brief Set related stream channels amount. + void SetChannels(int channels) { m_cStructure->channels = channels; } + + /// @brief Get related stream channels amount. + int GetChannels() const { return m_cStructure->channels; } + + /// @brief Set related stream bitrate. + void SetBitrate(int bitrate) { m_cStructure->bitrate = bitrate; } + + /// @brief Get related stream bitrate. + int GetBitrate() const { return m_cStructure->bitrate; } + + /// @brief Set additional information comment (if present). + void SetComment(const std::string& comment) + { + strncpy(m_cStructure->comment, comment.c_str(), sizeof(m_cStructure->comment) - 1); + } + + /// @brief Get additional information comment (if present). + std::string GetComment() const { return m_cStructure->comment; } + + ///@} + +private: + AudioDecoderInfoTag(const AUDIO_DECODER_INFO_TAG* tag) : CStructHdl(tag) {} + AudioDecoderInfoTag(AUDIO_DECODER_INFO_TAG* tag) : CStructHdl(tag) {} +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_audiodecoder_Defs Definitions, structures and enumerators +/// @ingroup cpp_kodi_addon_audiodecoder +/// @brief **Audio decoder add-on instance definition values**\n +/// All audio decoder functions associated data structures. +/// +/// Used to exchange the available options between Kodi and addon.\n +/// The groups described here correspond to the groups of functions on audio +/// decoder instance class. +/// + +//============================================================================== +/// +/// \addtogroup cpp_kodi_addon_audiodecoder +/// @brief \cpp_class{ kodi::addon::CInstanceAudioDecoder } +/// **Audio decoder add-on instance** +/// +/// For audio decoders as binary add-ons. This class implements a way to handle +/// special types of audio files. +/// +/// The add-on handles loading of the source file and outputting the audio stream +/// for consumption by the player. +/// +/// The addon.xml defines the capabilities of this add-on. +/// +/// @note The option to have multiple instances is possible with audio-decoder +/// add-ons. This is useful, since some playback engines are riddled by global +/// variables, making decoding of multiple streams using the same instance +/// impossible. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Here's an example on addon.xml:** +/// ~~~~~~~~~~~~~{.xml} +/// +/// +/// @ADDON_DEPENDS@ +/// +/// +/// My audio decoder addon addon +/// My audio decoder addon description +/// @PLATFORM@ +/// +/// +/// ~~~~~~~~~~~~~ +/// +/// Description to audio decoder related addon.xml values: +/// | Name | Description +/// |:------------------------------|---------------------------------------- +/// | `point` | Addon type specification
At all addon types and for this kind always "kodi.audiodecoder". +/// | `library_@PLATFORM@` | Sets the used library name, which is automatically set by cmake at addon build. +/// | `name` | The name of the decoder used in Kodi for display. +/// | `extension` | The file extensions / styles supported by this addon. +/// | `tags` | Boolean to point out that addon can bring own information to replayed file, if `false` only the file name is used as info.
If `true`, \ref CInstanceAudioDecoder::ReadTag is used and must be implemented. +/// +/// -------------------------------------------------------------------------- +/// +/// **Here is a code example how this addon is used:** +/// +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class CMyAudioDecoder : public kodi::addon::CInstanceAudioDecoder +/// { +/// public: +/// CMyAudioDecoder(KODI_HANDLE instance, const std::string& version); +/// +/// bool Init(const std::string& filename, unsigned int filecache, +/// int& channels, int& samplerate, +/// int& bitspersample, int64_t& totaltime, +/// int& bitrate, AudioEngineDataFormat& format, +/// std::vector& channellist) override; +/// int ReadPCM(uint8_t* buffer, int size, int& actualsize) override; +/// }; +/// +/// CMyAudioDecoder::CMyAudioDecoder(KODI_HANDLE instance, const std::string& version) +/// : kodi::addon::CInstanceAudioDecoder(instance, version) +/// { +/// ... +/// } +/// +/// bool CMyAudioDecoder::Init(const std::string& filename, unsigned int filecache, +/// int& channels, int& samplerate, +/// int& bitspersample, int64_t& totaltime, +/// int& bitrate, AudioEngineDataFormat& format, +/// std::vector& channellist) +/// { +/// ... +/// return true; +/// } +/// +/// int CMyAudioDecoder::ReadPCM(uint8_t* buffer, int size, int& actualsize) +/// { +/// ... +/// return 0; +/// } +/// +/// +/// //---------------------------------------------------------------------- +/// +/// class CMyAddon : public kodi::addon::CAddonBase +/// { +/// public: +/// CMyAddon() { } +/// ADDON_STATUS CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) override; +/// }; +/// +/// // If you use only one instance in your add-on, can be instanceType and +/// // instanceID ignored +/// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) +/// { +/// if (instanceType == ADDON_INSTANCE_AUDIODECODER) +/// { +/// kodi::Log(ADDON_LOG_INFO, "Creating my audio decoder"); +/// addonInstance = new CMyAudioDecoder(instance, version); +/// return ADDON_STATUS_OK; +/// } +/// else if (...) +/// { +/// ... +/// } +/// return ADDON_STATUS_UNKNOWN; +/// } +/// +/// ADDONCREATOR(CMyAddon) +/// ~~~~~~~~~~~~~ +/// +/// The destruction of the example class `CMyAudioDecoder` is called from +/// Kodi's header. Manually deleting the add-on instance is not required. +/// +class ATTRIBUTE_HIDDEN CInstanceAudioDecoder : public IAddonInstance +{ +public: + //========================================================================== + /// @ingroup cpp_kodi_addon_audiodecoder + /// @brief Audio decoder class constructor used to support multiple instance + /// types. + /// + /// @param[in] instance The instance value given to + /// `kodi::addon::CAddonBase::CreateInstance(...)`. + /// @param[in] kodiVersion [opt] Version used in Kodi for this instance, to + /// allow compatibility to older Kodi versions. + /// + /// @note Recommended to set `kodiVersion`. + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Here's example about the use of this:** + /// ~~~~~~~~~~~~~{.cpp} + /// class CMyAudioDecoder : public kodi::addon::CInstanceAudioDecoder + /// { + /// public: + /// CMyAudioDecoder(KODI_HANDLE instance, const std::string& kodiVersion) + /// : kodi::addon::CInstanceAudioDecoder(instance, kodiVersion) + /// { + /// ... + /// } + /// + /// ... + /// }; + /// + /// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, + /// const std::string& instanceID, + /// KODI_HANDLE instance, + /// const std::string& version, + /// KODI_HANDLE& addonInstance) + /// { + /// kodi::Log(ADDON_LOG_INFO, "Creating my audio decoder"); + /// addonInstance = new CMyAudioDecoder(instance, version); + /// return ADDON_STATUS_OK; + /// } + /// ~~~~~~~~~~~~~ + /// + explicit CInstanceAudioDecoder(KODI_HANDLE instance, const std::string& kodiVersion = "") + : IAddonInstance(ADDON_INSTANCE_AUDIODECODER, + !kodiVersion.empty() ? kodiVersion + : GetKodiTypeVersion(ADDON_INSTANCE_AUDIODECODER)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceAudioDecoder: Creation of multiple together with single instance way is not allowed!"); + + SetAddonStruct(instance); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_addon_audiodecoder + /// @brief Initialize a decoder. + /// + /// @param[in] filename The file to read + /// @param[in] filecache The file cache size + /// @param[out] channels Number of channels in output stream + /// @param[out] samplerate Samplerate of output stream + /// @param[out] bitspersample Bits per sample in output stream + /// @param[out] totaltime Total time for stream + /// @param[out] bitrate Average bitrate of input stream + /// @param[out] format Data format for output stream, see + /// @ref cpp_kodi_audioengine_Defs_AudioEngineFormat for + /// available values + /// @param[out] channellist Channel mapping for output streamm, see + /// @ref cpp_kodi_audioengine_Defs_AudioEngineChannel + /// for available values + /// @return true if successfully done, otherwise false + /// + virtual bool Init(const std::string& filename, + unsigned int filecache, + int& channels, + int& samplerate, + int& bitspersample, + int64_t& totaltime, + int& bitrate, + AudioEngineDataFormat& format, + std::vector& channellist) = 0; + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_addon_audiodecoder + /// @brief Produce some noise. + /// + /// @param[in] buffer Output buffer + /// @param[in] size Size of output buffer + /// @param[out] actualsize Actual number of bytes written to output buffer + /// @return Return with following possible values: + /// | Value | Description + /// |:-----:|:------------ + /// | 0 | on success + /// | -1 | on end of stream + /// | 1 | on failure + /// + virtual int ReadPCM(uint8_t* buffer, int size, int& actualsize) = 0; + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_addon_audiodecoder + /// @brief Seek in output stream. + /// + /// @param[in] time Time position to seek to in milliseconds + /// @return Time position seek ended up on + /// + virtual int64_t Seek(int64_t time) { return time; } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_addon_audiodecoder + /// @brief Read tag of a file. + /// + /// @param[in] file File to read tag for + /// @param[out] tag Information tag about + /// @return True on success, false on failure + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_audiodecoder_Defs_AudioDecoderInfoTag_Help + /// + virtual bool ReadTag(const std::string& file, kodi::addon::AudioDecoderInfoTag& tag) + { + return false; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_addon_audiodecoder + /// @brief Get number of tracks in a file. + /// + /// @param[in] file File to read tag for + /// @return Number of tracks in file + /// + virtual int TrackCount(const std::string& file) { return 1; } + //-------------------------------------------------------------------------- + +private: + void SetAddonStruct(KODI_HANDLE instance) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstanceAudioDecoder: Creation with empty addon structure not allowed, table must be given from Kodi!"); + + m_instanceData = static_cast(instance); + + m_instanceData->toAddon->addonInstance = this; + m_instanceData->toAddon->init = ADDON_Init; + m_instanceData->toAddon->read_pcm = ADDON_ReadPCM; + m_instanceData->toAddon->seek = ADDON_Seek; + m_instanceData->toAddon->read_tag = ADDON_ReadTag; + m_instanceData->toAddon->track_count = ADDON_TrackCount; + } + + inline static bool ADDON_Init(const AddonInstance_AudioDecoder* instance, + const char* file, + unsigned int filecache, + int* channels, + int* samplerate, + int* bitspersample, + int64_t* totaltime, + int* bitrate, + AudioEngineDataFormat* format, + const AudioEngineChannel** info) + { + CInstanceAudioDecoder* thisClass = + static_cast(instance->toAddon->addonInstance); + + thisClass->m_channelList.clear(); + bool ret = thisClass->Init(file, filecache, *channels, *samplerate, *bitspersample, *totaltime, + *bitrate, *format, thisClass->m_channelList); + if (!thisClass->m_channelList.empty()) + { + if (thisClass->m_channelList.back() != AUDIOENGINE_CH_NULL) + thisClass->m_channelList.push_back(AUDIOENGINE_CH_NULL); + *info = thisClass->m_channelList.data(); + } + else + *info = nullptr; + return ret; + } + + inline static int ADDON_ReadPCM(const AddonInstance_AudioDecoder* instance, uint8_t* buffer, int size, int* actualsize) + { + return static_cast(instance->toAddon->addonInstance) + ->ReadPCM(buffer, size, *actualsize); + } + + inline static int64_t ADDON_Seek(const AddonInstance_AudioDecoder* instance, int64_t time) + { + return static_cast(instance->toAddon->addonInstance)->Seek(time); + } + + inline static bool ADDON_ReadTag(const AddonInstance_AudioDecoder* instance, + const char* file, + struct AUDIO_DECODER_INFO_TAG* tag) + { + kodi::addon::AudioDecoderInfoTag cppTag(tag); + return static_cast(instance->toAddon->addonInstance) + ->ReadTag(file, cppTag); + } + + inline static int ADDON_TrackCount(const AddonInstance_AudioDecoder* instance, const char* file) + { + return static_cast(instance->toAddon->addonInstance)->TrackCount(file); + } + + std::vector m_channelList; + AddonInstance_AudioDecoder* m_instanceData; +}; + +} /* namespace addon */ +} /* namespace kodi */ +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/AudioEncoder.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/AudioEncoder.h new file mode 100644 index 0000000..9a869c1 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/AudioEncoder.h @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../AddonBase.h" +#include "../c-api/addon-instance/audio_encoder.h" + +#ifdef __cplusplus +namespace kodi +{ +namespace addon +{ + +//============================================================================== +/// @addtogroup cpp_kodi_addon_audioencoder +/// @brief \cpp_class{ kodi::addon::CInstanceAudioEncoder } +/// **Audio encoder add-on instance.**\n +/// For audio encoders as binary add-ons. This class implements a way to handle +/// the encode of given stream to a new format. +/// +/// The addon.xml defines the capabilities of this add-on. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Here's an example on addon.xml:** +/// ~~~~~~~~~~~~~{.xml} +/// +/// ~~~~~~~~~~~~~ +/// +/// Description to audio encoder related addon.xml values: +/// | Name | Description +/// |:------------------------------|---------------------------------------- +/// | `point` | Addon type specification
At all addon types and for this kind always "kodi.audioencoder". +/// | `library_@PLATFORM@` | Sets the used library name, which is automatically set by cmake at addon build. +/// | `extension` | The file extensions / styles supported by this addon. +/// +/// -------------------------------------------------------------------------- +/// +/// -------------------------------------------------------------------------- +/// +/// **Here is a code example how this addon is used:** +/// +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class ATTRIBUTE_HIDDEN CMyAudioEncoder : public kodi::addon::CInstanceAudioEncoder +/// { +/// public: +/// CMyAudioEncoder(KODI_HANDLE instance, const std::string& kodiVersion) +/// : kodi::addon::CInstanceAudioEncoder(instance, kodiVersion) +/// +/// bool Init(const std::string& filename, unsigned int filecache, +/// int& channels, int& samplerate, +/// int& bitspersample, int64_t& totaltime, +/// int& bitrate, AEDataFormat& format, +/// std::vector& channellist) override; +/// int Encode(int numBytesRead, const uint8_t* pbtStream) override; +/// bool Finish() override; // Optional +/// }; +/// +/// CMyAudioEncoder::CMyAudioEncoder(KODI_HANDLE instance) +/// : kodi::addon::CInstanceAudioEncoder(instance) +/// { +/// ... +/// } +/// +/// bool CMyAudioEncoder::Start(int inChannels, +/// int inRate, +/// int inBits, +/// const std::string& title, +/// const std::string& artist, +/// const std::string& albumartist, +/// const std::string& album, +/// const std::string& year, +/// const std::string& track, +/// const std::string& genre, +/// const std::string& comment, +/// int trackLength) +/// { +/// ... +/// return true; +/// } +/// +/// int CMyAudioEncoder::Encode(int numBytesRead, const uint8_t* pbtStream) +/// { +/// uint8_t* data = nullptr; +/// int length = 0; +/// ... +/// kodi::addon::CInstanceAudioEncoder::Write(data, length); +/// +/// return 0; +/// } +/// +/// +/// bool CMyAudioEncoder::Finish() +/// { +/// ... +/// return true; +/// } +/// +/// //---------------------------------------------------------------------- +/// +/// class CMyAddon : public kodi::addon::CAddonBase +/// { +/// public: +/// CMyAddon() = default; +/// ADDON_STATUS CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) override; +/// }; +/// +/// // If you use only one instance in your add-on, can be instanceType and +/// // instanceID ignored +/// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) +/// { +/// if (instanceType == ADDON_INSTANCE_AUDIOENCODER) +/// { +/// kodi::Log(ADDON_LOG_INFO, "Creating my audio encoder instance"); +/// addonInstance = new CMyAudioEncoder(instance, version); +/// return ADDON_STATUS_OK; +/// } +/// else if (...) +/// { +/// ... +/// } +/// return ADDON_STATUS_UNKNOWN; +/// } +/// +/// ADDONCREATOR(CMyAddon) +/// ~~~~~~~~~~~~~ +/// +/// The destruction of the example class `CMyAudioEncoder` is called from +/// Kodi's header. Manually deleting the add-on instance is not required. +/// +class ATTRIBUTE_HIDDEN CInstanceAudioEncoder : public IAddonInstance +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_addon_audioencoder + /// @brief Audio encoder class constructor used to support multiple instances. + /// + /// @param[in] instance The instance value given to + /// `kodi::addon::CAddonBase::CreateInstance(...)`. + /// @param[in] kodiVersion [opt] Version used in Kodi for this instance, to + /// allow compatibility to older Kodi versions. + /// + /// @note Recommended to set `kodiVersion`. + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Here's example about the use of this:** + /// ~~~~~~~~~~~~~{.cpp} + /// class CMyAudioEncoder : public kodi::addon::CInstanceAudioEncoder + /// { + /// public: + /// CMyAudioEncoder(KODI_HANDLE instance, const std::string& kodiVersion) + /// : kodi::addon::CInstanceAudioEncoder(instance, kodiVersion) + /// { + /// ... + /// } + /// + /// ... + /// }; + /// + /// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, + /// const std::string& instanceID, + /// KODI_HANDLE instance, + /// const std::string& version, + /// KODI_HANDLE& addonInstance) + /// { + /// kodi::Log(ADDON_LOG_INFO, "Creating my audio encoder instance"); + /// addonInstance = new CMyAudioEncoder(instance, version); + /// return ADDON_STATUS_OK; + /// } + /// ~~~~~~~~~~~~~ + /// + explicit CInstanceAudioEncoder(KODI_HANDLE instance, const std::string& kodiVersion = "") + : IAddonInstance(ADDON_INSTANCE_AUDIOENCODER, + !kodiVersion.empty() ? kodiVersion + : GetKodiTypeVersion(ADDON_INSTANCE_AUDIOENCODER)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceAudioEncoder: Creation of multiple together " + "with single instance way is not allowed!"); + + SetAddonStruct(instance); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_audioencoder + /// @brief Start encoder (**required**) + /// + /// @param[in] inChannels Number of channels + /// @param[in] inRate Sample rate of input data + /// @param[in] inBits Bits per sample in input data + /// @param[in] title The title of the song + /// @param[in] artist The artist of the song + /// @param[in] albumartist The albumartist of the song + /// @param[in] year The year of the song + /// @param[in] track The track number of the song + /// @param[in] genre The genre of the song + /// @param[in] comment A comment to attach to the song + /// @param[in] trackLength Total track length in seconds + /// @return True on success, false on failure. + /// + virtual bool Start(int inChannels, + int inRate, + int inBits, + const std::string& title, + const std::string& artist, + const std::string& albumartist, + const std::string& album, + const std::string& year, + const std::string& track, + const std::string& genre, + const std::string& comment, + int trackLength) = 0; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_audioencoder + /// @brief Encode a chunk of audio (**required**) + /// + /// @param[in] numBytesRead Number of bytes in input buffer + /// @param[in] pbtStream The input buffer + /// @return Number of bytes consumed + /// + virtual int Encode(int numBytesRead, const uint8_t* pbtStream) = 0; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_audioencoder + /// @brief Finalize encoding (**optional**) + /// + /// @return True on success, false on failure. + /// + virtual bool Finish() { return true; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_audioencoder + /// @brief Write block of data + /// + /// @param[in] data Pointer to the array of elements to be written + /// @param[in] length Size in bytes to be written. + /// @return The total number of bytes successfully written is returned. + /// + /// @remarks Only called from addon itself. + /// + int Write(const uint8_t* data, int length) + { + return m_instanceData->toKodi->write(m_instanceData->toKodi->kodiInstance, data, length); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_audioencoder + /// @brief Set the file's current position. + /// + /// The whence argument is optional and defaults to SEEK_SET (0) + /// + /// @param[in] position The position that you want to seek to + /// @param[in] whence [optional] offset relative to\n + /// You can set the value of whence to one + /// of three things: + /// | Value | int | Description | + /// |:--------:|:---:|:---------------------------------------------------| + /// | SEEK_SET | 0 | position is relative to the beginning of the file. This is probably what you had in mind anyway, and is the most commonly used value for whence. + /// | SEEK_CUR | 1 | position is relative to the current file pointer position. So, in effect, you can say, "Move to my current position plus 30 bytes," or, "move to my current position minus 20 bytes." + /// | SEEK_END | 2 | position is relative to the end of the file. Just like SEEK_SET except from the other end of the file. Be sure to use negative values for offset if you want to back up from the end of the file, instead of going past the end into oblivion. + /// + /// @return Returns the resulting offset location as measured in bytes from + /// the beginning of the file. On error, the value -1 is returned. + /// + /// @remarks Only called from addon itself. + /// + int64_t Seek(int64_t position, int whence = SEEK_SET) + { + return m_instanceData->toKodi->seek(m_instanceData->toKodi->kodiInstance, position, whence); + } + //---------------------------------------------------------------------------- + +private: + void SetAddonStruct(KODI_HANDLE instance) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstanceAudioEncoder: Creation with empty addon " + "structure not allowed, table must be given from Kodi!"); + + m_instanceData = static_cast(instance); + m_instanceData->toAddon->addonInstance = this; + m_instanceData->toAddon->start = ADDON_Start; + m_instanceData->toAddon->encode = ADDON_Encode; + m_instanceData->toAddon->finish = ADDON_Finish; + } + + inline static bool ADDON_Start(const AddonInstance_AudioEncoder* instance, + int inChannels, + int inRate, + int inBits, + const char* title, + const char* artist, + const char* albumartist, + const char* album, + const char* year, + const char* track, + const char* genre, + const char* comment, + int trackLength) + { + return static_cast(instance->toAddon->addonInstance) + ->Start(inChannels, inRate, inBits, title, artist, albumartist, album, year, track, genre, + comment, trackLength); + } + + inline static int ADDON_Encode(const AddonInstance_AudioEncoder* instance, + int numBytesRead, + const uint8_t* pbtStream) + { + return static_cast(instance->toAddon->addonInstance) + ->Encode(numBytesRead, pbtStream); + } + + inline static bool ADDON_Finish(const AddonInstance_AudioEncoder* instance) + { + return static_cast(instance->toAddon->addonInstance)->Finish(); + } + + AddonInstance_AudioEncoder* m_instanceData; +}; + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/CMakeLists.txt new file mode 100644 index 0000000..a57def3 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/CMakeLists.txt @@ -0,0 +1,15 @@ +set(HEADERS AudioDecoder.h + AudioEncoder.h + Game.h + ImageDecoder.h + Inputstream.h + Peripheral.h + PVR.h + Screensaver.h + VFS.h + VideoCodec.h + Visualization.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_addon-instance) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Game.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Game.h new file mode 100644 index 0000000..3dca94d --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Game.h @@ -0,0 +1,1190 @@ +/* + * Copyright (C) 2014-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../AddonBase.h" +#include "../c-api/addon-instance/game.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace addon +{ + +//============================================================================== +/// @addtogroup cpp_kodi_addon_game +/// +/// To use on Libretro and for stand-alone games or emulators that does not use +/// the Libretro API. +/// +/// Possible examples could be, Nvidia GameStream via Limelight or WINE capture +/// could possible through the Game API. +/// + +//============================================================================== +/// @defgroup cpp_kodi_addon_game_Defs Definitions, structures and enumerators +/// @ingroup cpp_kodi_addon_game +/// @brief **Game add-on instance definition values** +/// + +//============================================================================== +/// @defgroup cpp_kodi_addon_game_Defs_InputTypes_GameControllerLayout class GameControllerLayout +/// @ingroup cpp_kodi_addon_game_Defs_InputTypes +/// @brief Data of layouts for known controllers. +/// +/// Used on @ref kodi::addon::CInstanceGame::SetControllerLayouts(). +///@{ +class GameControllerLayout +{ +public: + /*! @cond PRIVATE */ + explicit GameControllerLayout() = default; + GameControllerLayout(const game_controller_layout& layout) + { + controller_id = layout.controller_id; + provides_input = layout.provides_input; + for (unsigned int i = 0; i < layout.digital_button_count; ++i) + digital_buttons.push_back(layout.digital_buttons[i]); + for (unsigned int i = 0; i < layout.analog_button_count; ++i) + analog_buttons.push_back(layout.analog_buttons[i]); + for (unsigned int i = 0; i < layout.analog_stick_count; ++i) + analog_sticks.push_back(layout.analog_sticks[i]); + for (unsigned int i = 0; i < layout.accelerometer_count; ++i) + accelerometers.push_back(layout.accelerometers[i]); + for (unsigned int i = 0; i < layout.key_count; ++i) + keys.push_back(layout.keys[i]); + for (unsigned int i = 0; i < layout.rel_pointer_count; ++i) + rel_pointers.push_back(layout.rel_pointers[i]); + for (unsigned int i = 0; i < layout.abs_pointer_count; ++i) + abs_pointers.push_back(layout.abs_pointers[i]); + for (unsigned int i = 0; i < layout.motor_count; ++i) + motors.push_back(layout.motors[i]); + } + /*! @endcond */ + + /// @brief Controller identifier. + std::string controller_id; + + /// @brief Provides input. + /// + /// False for multitaps + bool provides_input; + + /// @brief Digital buttons. + std::vector digital_buttons; + + /// @brief Analog buttons. + std::vector analog_buttons; + + /// @brief Analog sticks. + std::vector analog_sticks; + + /// @brief Accelerometers. + std::vector accelerometers; + + /// @brief Keys. + std::vector keys; + + /// @brief Relative pointers. + std::vector rel_pointers; + + /// @brief Absolute pointers. + std::vector abs_pointers; + + /// @brief Motors. + std::vector motors; +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @addtogroup cpp_kodi_addon_game +/// @brief @cpp_class{ kodi::addon::CInstanceGame } +/// **Game add-on instance**\n +/// This class provides the basic game processing system for use as an add-on in +/// Kodi. +/// +/// This class is created at addon by Kodi. +/// +class ATTRIBUTE_HIDDEN CInstanceGame : public IAddonInstance +{ +public: + //============================================================================ + /// @defgroup cpp_kodi_addon_game_Base 1. Basic functions + /// @ingroup cpp_kodi_addon_game + /// @brief **Functions to manage the addon and get basic information about it** + /// + ///@{ + + //============================================================================ + /// @brief Game class constructor + /// + /// Used by an add-on that only supports only Game and only in one instance. + /// + /// This class is created at addon by Kodi. + /// + /// + /// -------------------------------------------------------------------------- + /// + /// + /// **Here's example about the use of this:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// ... + /// + /// class ATTRIBUTE_HIDDEN CGameExample + /// : public kodi::addon::CAddonBase, + /// public kodi::addon::CInstanceGame + /// { + /// public: + /// CGameExample() + /// { + /// } + /// + /// virtual ~CGameExample(); + /// { + /// } + /// + /// ... + /// }; + /// + /// ADDONCREATOR(CGameExample) + /// ~~~~~~~~~~~~~ + /// + CInstanceGame() : IAddonInstance(ADDON_INSTANCE_GAME, GetKodiTypeVersion(ADDON_INSTANCE_GAME)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceGame: Creation of more as one in single " + "instance way is not allowed!"); + + SetAddonStruct(CAddonBase::m_interface->firstKodiInstance); + CAddonBase::m_interface->globalSingleInstance = this; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Destructor + /// + ~CInstanceGame() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// The path of the game client being loaded. + /// + /// @return the used game client Dll path + /// + /// @remarks Only called from addon itself + /// + std::string GameClientDllPath() const { return m_instanceData->props->game_client_dll_path; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// Paths to proxy DLLs used to load the game client. + /// + /// @param[out] paths vector list to store available dll paths + /// @return true if success and dll paths present + /// + /// @remarks Only called from addon itself + /// + bool ProxyDllPaths(std::vector& paths) + { + for (unsigned int i = 0; i < m_instanceData->props->proxy_dll_count; ++i) + { + if (m_instanceData->props->proxy_dll_paths[i] != nullptr) + paths.push_back(m_instanceData->props->proxy_dll_paths[i]); + } + return !paths.empty(); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// The "system" directories of the frontend. + /// + /// These directories can be used to store system-specific ROMs such as + /// BIOSes, configuration data, etc. + /// + /// @return the used resource directory + /// + /// @remarks Only called from addon itself + /// + bool ResourceDirectories(std::vector& dirs) + { + for (unsigned int i = 0; i < m_instanceData->props->resource_directory_count; ++i) + { + if (m_instanceData->props->resource_directories[i] != nullptr) + dirs.push_back(m_instanceData->props->resource_directories[i]); + } + return !dirs.empty(); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// The writable directory of the frontend. + /// + /// This directory can be used to store SRAM, memory cards, high scores, + /// etc, if the game client cannot use the regular memory interface, + /// GetMemoryData(). + /// + /// @return the used profile directory + /// + /// @remarks Only called from addon itself + /// + std::string ProfileDirectory() const { return m_instanceData->props->profile_directory; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// The value of the property from addon.xml. + /// + /// @return true if VFS is supported + /// + /// @remarks Only called from addon itself + /// + bool SupportsVFS() const { return m_instanceData->props->supports_vfs; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// The extensions in the property from addon.xml. + /// + /// @param[out] extensions vector list to store available extension + /// @return true if success and extensions present + /// + /// @remarks Only called from addon itself + /// + bool Extensions(std::vector& extensions) + { + for (unsigned int i = 0; i < m_instanceData->props->extension_count; ++i) + { + if (m_instanceData->props->extensions[i] != nullptr) + extensions.push_back(m_instanceData->props->extensions[i]); + } + return !extensions.empty(); + } + //---------------------------------------------------------------------------- + + ///@} + +//--==----==----==----==----==----==----==----==----==----==----==----==----==-- + + //============================================================================ + /// + /// @defgroup cpp_kodi_addon_game_Operation 2. Game operations + /// @ingroup cpp_kodi_addon_game + /// @brief **Game operations** + /// + /// These are mandatory functions for using this addon to get the available + /// channels. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Game operation parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_game_Operation_header_addon_auto_check + /// @copydetails cpp_kodi_addon_game_Operation_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Load a game + /// + /// @param[in] url The URL to load + /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was loaded + /// + virtual GAME_ERROR LoadGame(const std::string& url) + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Load a game that requires multiple files + /// + /// @param[in] type The game type + /// @param[in] urls An array of urls + /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was loaded + /// + virtual GAME_ERROR LoadGameSpecial(SPECIAL_GAME_TYPE type, const std::vector& urls) + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Begin playing without a game file + /// + /// If the add-on supports standalone mode, it must add the + /// tag to the extension point in addon.xml: + /// + /// false + /// + /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game add-on was loaded + /// + virtual GAME_ERROR LoadStandalone() + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Unload the current game + /// + /// Unloads a currently loaded game + /// + /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was unloaded + /// + virtual GAME_ERROR UnloadGame() + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get timing information about the loaded game + /// + /// @param[out] timing_info The info structure to fill + /// + /// @return the error, or @ref GAME_ERROR_NO_ERROR if info was filled + /// + virtual GAME_ERROR GetGameTiming(game_system_timing& timing_info) + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get region of the loaded game + /// + /// @return the region, or @ref GAME_REGION_UNKNOWN if unknown or no game is loaded + /// + virtual GAME_REGION GetRegion() + { + return GAME_REGION_UNKNOWN; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Return true if the client requires the frontend to provide a game loop + /// + /// The game loop is a thread that calls RunFrame() in a loop at a rate + /// determined by the playback speed and the client's FPS. + /// + /// @return true if the frontend should provide a game loop, false otherwise + /// + virtual bool RequiresGameLoop() + { + return false; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Run a single frame for add-ons that use a game loop + /// + /// @return the error, or @ref GAME_ERROR_NO_ERROR if there was no error + /// + virtual GAME_ERROR RunFrame() + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Reset the current game + /// + /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was reset + /// + virtual GAME_ERROR Reset() + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief **Callback to Kodi Function**\n + /// Requests the frontend to stop the current game + /// + /// @remarks Only called from addon itself + /// + void CloseGame(void) { m_instanceData->toKodi->CloseGame(m_instanceData->toKodi->kodiInstance); } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_game_Operation_CStream Class: CStream + /// @ingroup cpp_kodi_addon_game_Operation + /// @brief @cpp_class{ kodi::addon::CInstanceGame::CStream } + /// **Game stream handler** + /// + /// This class will be integrated into the addon, which can then open it if + /// necessary for the processing of an audio or video stream. + /// + /// + /// @note Callback to Kodi class + ///@{ + class CStream + { + public: + CStream() = default; + + CStream(const game_stream_properties& properties) + { + Open(properties); + } + + ~CStream() + { + Close(); + } + + //========================================================================== + /// @ingroup cpp_kodi_addon_game_Operation_CStream + /// @brief Create a stream for gameplay data + /// + /// @param[in] properties The stream properties + /// @return A stream handle, or `nullptr` on failure + /// + /// @remarks Only called from addon itself + /// + bool Open(const game_stream_properties& properties) + { + if (!CAddonBase::m_interface->globalSingleInstance) + return false; + + if (m_handle) + { + kodi::Log(ADDON_LOG_INFO, "kodi::addon::CInstanceGame::CStream already becomes reopened"); + Close(); + } + + AddonToKodiFuncTable_Game& cb = + *static_cast(CAddonBase::m_interface->globalSingleInstance) + ->m_instanceData->toKodi; + m_handle = cb.OpenStream(cb.kodiInstance, &properties); + return m_handle != nullptr; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_addon_game_Operation_CStream + /// @brief Free the specified stream + /// + /// @remarks Only called from addon itself + /// + void Close() + { + if (!m_handle || !CAddonBase::m_interface->globalSingleInstance) + return; + + AddonToKodiFuncTable_Game& cb = + *static_cast(CAddonBase::m_interface->globalSingleInstance) + ->m_instanceData->toKodi; + cb.CloseStream(cb.kodiInstance, m_handle); + m_handle = nullptr; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_addon_game_Operation_CStream + /// @brief Get a buffer for zero-copy stream data + /// + /// @param[in] width The framebuffer width, or 0 for no width specified + /// @param[in] height The framebuffer height, or 0 for no height specified + /// @param[out] buffer The buffer, or unmodified if false is returned + /// @return True if buffer was set, false otherwise + /// + /// @note If this returns true, buffer must be freed using @ref ReleaseBuffer(). + /// + /// @remarks Only called from addon itself + /// + bool GetBuffer(unsigned int width, unsigned int height, game_stream_buffer& buffer) + { + if (!m_handle || !CAddonBase::m_interface->globalSingleInstance) + return false; + + AddonToKodiFuncTable_Game& cb = + *static_cast(CAddonBase::m_interface->globalSingleInstance) + ->m_instanceData->toKodi; + return cb.GetStreamBuffer(cb.kodiInstance, m_handle, width, height, &buffer); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_addon_game_Operation_CStream + /// @brief Add a data packet to a stream + /// + /// @param[in] packet The data packet + /// + /// @remarks Only called from addon itself + /// + void AddData(const game_stream_packet& packet) + { + if (!m_handle || !CAddonBase::m_interface->globalSingleInstance) + return; + + AddonToKodiFuncTable_Game& cb = + *static_cast(CAddonBase::m_interface->globalSingleInstance) + ->m_instanceData->toKodi; + cb.AddStreamData(cb.kodiInstance, m_handle, &packet); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_addon_game_Operation_CStream + /// @brief Free an allocated buffer + /// + /// @param[in] buffer The buffer returned from GetStreamBuffer() + /// + /// @remarks Only called from addon itself + /// + void ReleaseBuffer(game_stream_buffer& buffer) + { + if (!m_handle || !CAddonBase::m_interface->globalSingleInstance) + return; + + AddonToKodiFuncTable_Game& cb = + *static_cast(CAddonBase::m_interface->globalSingleInstance) + ->m_instanceData->toKodi; + cb.ReleaseStreamBuffer(cb.kodiInstance, m_handle, &buffer); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_addon_game_Operation_CStream + /// @brief To check stream open was OK, e.g. after use of constructor + /// + /// @return true if stream was successfully opened + /// + /// @remarks Only called from addon itself + /// + bool IsOpen() const { return m_handle != nullptr; } + //-------------------------------------------------------------------------- + + private: + KODI_GAME_STREAM_HANDLE m_handle = nullptr; + }; + ///@} + + ///@} + +//--==----==----==----==----==----==----==----==----==----==----==----==----==-- + + //============================================================================ + /// + /// @defgroup cpp_kodi_addon_game_HardwareRendering 3. Hardware rendering operations + /// @ingroup cpp_kodi_addon_game + /// @brief **Hardware rendering operations** + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Hardware rendering operation parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_game_HardwareRendering_header_addon_auto_check + /// @copydetails cpp_kodi_addon_game_HardwareRendering_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Invalidates the current HW context and reinitializes GPU resources + /// + /// Any GL state is lost, and must not be deinitialized explicitly. + /// + /// @return the error, or @ref GAME_ERROR_NO_ERROR if the HW context was reset + /// + virtual GAME_ERROR HwContextReset() + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Called before the context is destroyed + /// + /// Resources can be deinitialized at this step. + /// + /// @return the error, or @ref GAME_ERROR_NO_ERROR if the HW context was destroyed + /// + virtual GAME_ERROR HwContextDestroy() + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + + //============================================================================ + /// @brief **Callback to Kodi Function**
Get a symbol from the hardware context + /// + /// @param[in] sym The symbol's name + /// + /// @return A function pointer for the specified symbol + /// + /// @remarks Only called from addon itself + /// + game_proc_address_t HwGetProcAddress(const char* sym) + { + return m_instanceData->toKodi->HwGetProcAddress(m_instanceData->toKodi->kodiInstance, sym); + } + //---------------------------------------------------------------------------- + + ///@} + +//--==----==----==----==----==----==----==----==----==----==----==----==----==-- + + //============================================================================ + /// @defgroup cpp_kodi_addon_game_InputOperations 4. Input operations + /// @ingroup cpp_kodi_addon_game + /// @brief **Input operations** + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Hardware rendering operation parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_game_InputOperations_header_addon_auto_check + /// @copydetails cpp_kodi_addon_game_InputOperations_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Check if input is accepted for a feature on the controller + /// + /// If only a subset of the controller profile is used, this can return false + /// for unsupported features to not absorb their input. + /// + /// If the entire controller profile is used, this should always return true. + /// + /// @param[in] controller_id The ID of the controller profile + /// @param[in] feature_name The name of a feature in that profile + /// @return true if input is accepted for the feature, false otherwise + /// + virtual bool HasFeature(const std::string& controller_id, const std::string& feature_name) + { + return false; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the input topology that specifies which controllers can be connected + /// + /// @return The input topology, or null to use the default + /// + /// If this returns non-null, topology must be freed using FreeTopology(). + /// + /// If this returns null, the topology will default to a single port that can + /// accept all controllers imported by addon.xml. The port ID is set to + /// the @ref DEFAULT_PORT_ID constant. + /// + virtual game_input_topology* GetTopology() + { + return nullptr; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Free the topology's resources + /// + /// @param[in] topology The topology returned by GetTopology() + /// + virtual void FreeTopology(game_input_topology* topology) + { + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Set the layouts for known controllers + /// + /// @param[in] controllers The controller layouts + /// + /// After loading the input topology, the frontend will call this with + /// controller layouts for all controllers discovered in the topology. + /// + virtual void SetControllerLayouts(const std::vector& controllers) + { + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Enable/disable keyboard input using the specified controller + /// + /// @param[in] enable True to enable input, false otherwise + /// @param[in] controller_id The controller ID if enabling, or unused if disabling + /// + /// @return True if keyboard input was enabled, false otherwise + /// + virtual bool EnableKeyboard(bool enable, const std::string& controller_id) + { + return false; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Enable/disable mouse input using the specified controller + /// + /// @param[in] enable True to enable input, false otherwise + /// @param[in] controller_id The controller ID if enabling, or unused if disabling + /// + /// @return True if mouse input was enabled, false otherwise + /// + virtual bool EnableMouse(bool enable, const std::string& controller_id) + { + return false; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @brief Connect/disconnect a controller to a port on the virtual game console + /// + /// @param[in] connect True to connect a controller, false to disconnect + /// @param[in] port_address The address of the port + /// @param[in] controller_id The controller ID if connecting, or unused if disconnecting + /// @return True if the \p controller was (dis-)connected to the port, false otherwise + /// + /// The address is a string that allows traversal of the controller topology. + /// It is formed by alternating port IDs and controller IDs separated by "/". + /// + /// For example, assume that the topology represented in XML for Snes9x is: + /// + /// ~~~~~~~~~~~~~{.xml} + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// ... + /// + /// + /// + /// ~~~~~~~~~~~~~ + /// + /// To connect a multitap to the console's first port, the multitap's controller + /// info is set using the port address: + /// + /// 1 + /// + /// To connect a SNES controller to the second port of the multitap, the + /// controller info is next set using the address: + /// + /// 1/game.controller.multitap/2 + /// + /// Any attempts to connect a controller to a port on a disconnected multitap + /// will return false. + /// + virtual bool ConnectController(bool connect, + const std::string& port_address, + const std::string& controller_id) + { + return false; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Notify the add-on of an input event + /// + /// @param[in] event The input event + /// + /// @return true if the event was handled, false otherwise + /// + virtual bool InputEvent(const game_input_event& event) + { + return false; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**
Notify the port of an input event + /// + /// @param[in] event The input event + /// @return true if the event was handled, false otherwise + /// + /// @note Input events can arrive for the following sources: + /// - @ref GAME_INPUT_EVENT_MOTOR + /// + /// @remarks Only called from addon itself + /// + bool KodiInputEvent(const game_input_event& event) + { + return m_instanceData->toKodi->InputEvent(m_instanceData->toKodi->kodiInstance, &event); + } + //---------------------------------------------------------------------------- + + ///@} + +//--==----==----==----==----==----==----==----==----==----==----==----==----==-- + + //============================================================================ + /// @defgroup cpp_kodi_addon_game_SerializationOperations 5. Serialization operations + /// @ingroup cpp_kodi_addon_game + /// @brief **Serialization operations** + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Serialization operation parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_game_SerializationOperations_header_addon_auto_check + /// @copydetails cpp_kodi_addon_game_SerializationOperations_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Get the number of bytes required to serialize the game + /// + /// @return the number of bytes, or 0 if serialization is not supported + /// + virtual size_t SerializeSize() + { + return 0; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Serialize the state of the game + /// + /// @param[in] data The buffer receiving the serialized game data + /// @param[in] size The size of the buffer + /// + /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was serialized into the buffer + /// + virtual GAME_ERROR Serialize(uint8_t* data, size_t size) + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Deserialize the game from the given state + /// + /// @param[in] data A buffer containing the game's new state + /// @param[in] size The size of the buffer + /// + /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game deserialized + /// + virtual GAME_ERROR Deserialize(const uint8_t* data, size_t size) + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + ///@} + +//--==----==----==----==----==----==----==----==----==----==----==----==----==-- + + //============================================================================ + /// @defgroup cpp_kodi_addon_game_CheatOperations 6. Cheat operations + /// @ingroup cpp_kodi_addon_game + /// @brief **Cheat operations** + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Cheat operation parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_game_CheatOperations_header_addon_auto_check + /// @copydetails cpp_kodi_addon_game_CheatOperations_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Reset the cheat system + /// + /// @return the error, or @ref GAME_ERROR_NO_ERROR if the cheat system was reset + /// + virtual GAME_ERROR CheatReset() + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get a region of memory + /// + /// @param[in] type The type of memory to retrieve + /// @param[in] data Set to the region of memory; must remain valid until UnloadGame() is called + /// @param[in] size Set to the size of the region of memory + /// + /// @return the error, or @ref GAME_ERROR_NO_ERROR if data was set to a valid buffer + /// + virtual GAME_ERROR GetMemory(GAME_MEMORY type, uint8_t*& data, size_t& size) + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Set a cheat code + /// + /// @param[in] index + /// @param[in] enabled + /// @param[in] code + /// + /// @return the error, or @ref GAME_ERROR_NO_ERROR if the cheat was set + /// + virtual GAME_ERROR SetCheat(unsigned int index, bool enabled, const std::string& code) + { + return GAME_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + ///@} + +private: + void SetAddonStruct(KODI_HANDLE instance) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstanceGame: Creation with empty addon structure not" + "allowed, table must be given from Kodi!"); + + m_instanceData = static_cast(instance); + m_instanceData->toAddon->addonInstance = this; + + m_instanceData->toAddon->LoadGame = ADDON_LoadGame; + m_instanceData->toAddon->LoadGameSpecial = ADDON_LoadGameSpecial; + m_instanceData->toAddon->LoadStandalone = ADDON_LoadStandalone; + m_instanceData->toAddon->UnloadGame = ADDON_UnloadGame; + m_instanceData->toAddon->GetGameTiming = ADDON_GetGameTiming; + m_instanceData->toAddon->GetRegion = ADDON_GetRegion; + m_instanceData->toAddon->RequiresGameLoop = ADDON_RequiresGameLoop; + m_instanceData->toAddon->RunFrame = ADDON_RunFrame; + m_instanceData->toAddon->Reset = ADDON_Reset; + + m_instanceData->toAddon->HwContextReset = ADDON_HwContextReset; + m_instanceData->toAddon->HwContextDestroy = ADDON_HwContextDestroy; + + m_instanceData->toAddon->HasFeature = ADDON_HasFeature; + m_instanceData->toAddon->GetTopology = ADDON_GetTopology; + m_instanceData->toAddon->FreeTopology = ADDON_FreeTopology; + m_instanceData->toAddon->SetControllerLayouts = ADDON_SetControllerLayouts; + m_instanceData->toAddon->EnableKeyboard = ADDON_EnableKeyboard; + m_instanceData->toAddon->EnableMouse = ADDON_EnableMouse; + m_instanceData->toAddon->ConnectController = ADDON_ConnectController; + m_instanceData->toAddon->InputEvent = ADDON_InputEvent; + + m_instanceData->toAddon->SerializeSize = ADDON_SerializeSize; + m_instanceData->toAddon->Serialize = ADDON_Serialize; + m_instanceData->toAddon->Deserialize = ADDON_Deserialize; + + m_instanceData->toAddon->CheatReset = ADDON_CheatReset; + m_instanceData->toAddon->GetMemory = ADDON_GetMemory; + m_instanceData->toAddon->SetCheat = ADDON_SetCheat; + } + + // --- Game operations --------------------------------------------------------- + + inline static GAME_ERROR ADDON_LoadGame(const AddonInstance_Game* instance, const char* url) + { + return static_cast(instance->toAddon->addonInstance)->LoadGame(url); + } + + inline static GAME_ERROR ADDON_LoadGameSpecial(const AddonInstance_Game* instance, + SPECIAL_GAME_TYPE type, + const char** urls, + size_t urlCount) + { + std::vector urlList; + for (size_t i = 0; i < urlCount; ++i) + { + if (urls[i] != nullptr) + urlList.push_back(urls[i]); + } + + return static_cast(instance->toAddon->addonInstance) + ->LoadGameSpecial(type, urlList); + } + + inline static GAME_ERROR ADDON_LoadStandalone(const AddonInstance_Game* instance) + { + return static_cast(instance->toAddon->addonInstance)->LoadStandalone(); + } + + inline static GAME_ERROR ADDON_UnloadGame(const AddonInstance_Game* instance) + { + return static_cast(instance->toAddon->addonInstance)->UnloadGame(); + } + + inline static GAME_ERROR ADDON_GetGameTiming(const AddonInstance_Game* instance, + game_system_timing* timing_info) + { + return static_cast(instance->toAddon->addonInstance) + ->GetGameTiming(*timing_info); + } + + inline static GAME_REGION ADDON_GetRegion(const AddonInstance_Game* instance) + { + return static_cast(instance->toAddon->addonInstance)->GetRegion(); + } + + inline static bool ADDON_RequiresGameLoop(const AddonInstance_Game* instance) + { + return static_cast(instance->toAddon->addonInstance)->RequiresGameLoop(); + } + + inline static GAME_ERROR ADDON_RunFrame(const AddonInstance_Game* instance) + { + return static_cast(instance->toAddon->addonInstance)->RunFrame(); + } + + inline static GAME_ERROR ADDON_Reset(const AddonInstance_Game* instance) + { + return static_cast(instance->toAddon->addonInstance)->Reset(); + } + + + // --- Hardware rendering operations ------------------------------------------- + + inline static GAME_ERROR ADDON_HwContextReset(const AddonInstance_Game* instance) + { + return static_cast(instance->toAddon->addonInstance)->HwContextReset(); + } + + inline static GAME_ERROR ADDON_HwContextDestroy(const AddonInstance_Game* instance) + { + return static_cast(instance->toAddon->addonInstance)->HwContextDestroy(); + } + + + // --- Input operations -------------------------------------------------------- + + inline static bool ADDON_HasFeature(const AddonInstance_Game* instance, + const char* controller_id, + const char* feature_name) + { + return static_cast(instance->toAddon->addonInstance) + ->HasFeature(controller_id, feature_name); + } + + inline static game_input_topology* ADDON_GetTopology(const AddonInstance_Game* instance) + { + return static_cast(instance->toAddon->addonInstance)->GetTopology(); + } + + inline static void ADDON_FreeTopology(const AddonInstance_Game* instance, + game_input_topology* topology) + { + static_cast(instance->toAddon->addonInstance)->FreeTopology(topology); + } + + inline static void ADDON_SetControllerLayouts(const AddonInstance_Game* instance, + const game_controller_layout* controllers, + unsigned int controller_count) + { + if (controllers == nullptr) + return; + + std::vector controllerList; + for (unsigned int i = 0; i < controller_count; ++i) + controllerList.push_back(controllers[i]); + + static_cast(instance->toAddon->addonInstance) + ->SetControllerLayouts(controllerList); + } + + inline static bool ADDON_EnableKeyboard(const AddonInstance_Game* instance, + bool enable, + const char* controller_id) + { + return static_cast(instance->toAddon->addonInstance) + ->EnableKeyboard(enable, controller_id); + } + + inline static bool ADDON_EnableMouse(const AddonInstance_Game* instance, + bool enable, + const char* controller_id) + { + return static_cast(instance->toAddon->addonInstance) + ->EnableMouse(enable, controller_id); + } + + inline static bool ADDON_ConnectController(const AddonInstance_Game* instance, + bool connect, + const char* port_address, + const char* controller_id) + { + return static_cast(instance->toAddon->addonInstance) + ->ConnectController(connect, port_address, controller_id); + } + + inline static bool ADDON_InputEvent(const AddonInstance_Game* instance, + const game_input_event* event) + { + return static_cast(instance->toAddon->addonInstance)->InputEvent(*event); + } + + + // --- Serialization operations ------------------------------------------------ + + inline static size_t ADDON_SerializeSize(const AddonInstance_Game* instance) + { + return static_cast(instance->toAddon->addonInstance)->SerializeSize(); + } + + inline static GAME_ERROR ADDON_Serialize(const AddonInstance_Game* instance, + uint8_t* data, + size_t size) + { + return static_cast(instance->toAddon->addonInstance)->Serialize(data, size); + } + + inline static GAME_ERROR ADDON_Deserialize(const AddonInstance_Game* instance, + const uint8_t* data, + size_t size) + { + return static_cast(instance->toAddon->addonInstance)->Deserialize(data, size); + } + + + // --- Cheat operations -------------------------------------------------------- + + inline static GAME_ERROR ADDON_CheatReset(const AddonInstance_Game* instance) + { + return static_cast(instance->toAddon->addonInstance)->CheatReset(); + } + + inline static GAME_ERROR ADDON_GetMemory(const AddonInstance_Game* instance, + GAME_MEMORY type, + uint8_t** data, + size_t* size) + { + return static_cast(instance->toAddon->addonInstance) + ->GetMemory(type, *data, *size); + } + + inline static GAME_ERROR ADDON_SetCheat(const AddonInstance_Game* instance, + unsigned int index, + bool enabled, + const char* code) + { + return static_cast(instance->toAddon->addonInstance) + ->SetCheat(index, enabled, code); + } + + AddonInstance_Game* m_instanceData; +}; + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/ImageDecoder.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/ImageDecoder.h new file mode 100644 index 0000000..7aeef7b --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/ImageDecoder.h @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../AddonBase.h" +#include "../c-api/addon-instance/image_decoder.h" + +#ifdef __cplusplus +namespace kodi +{ +namespace addon +{ + +//############################################################################## +/// @defgroup cpp_kodi_addon_imagedecoder_Defs Definitions, structures and enumerators +/// @ingroup cpp_kodi_addon_imagedecoder +/// @brief **Image decoder add-on general variables** +/// +/// Used to exchange the available options between Kodi and addon. +/// +/// + +//============================================================================== +/// +/// @addtogroup cpp_kodi_addon_imagedecoder +/// @brief @cpp_class{ kodi::addon::CInstanceImageDecoder } +/// **Image decoder add-on instance**\n +/// This instance type is used to allow Kodi various additional image format +/// types. +/// +/// This usage can be requested under various conditions, by a Mimetype protocol +/// defined in `addon.xml` or supported file extensions. +/// +/// Include the header @ref ImageDecoder.h "#include " +/// to use this class. +/// +/// ---------------------------------------------------------------------------- +/// +/// Here is an example of what the `addon.xml.in` would look like for an +/// image decoder addon: +/// +/// ~~~~~~~~~~~~~{.xml} +/// +/// +/// @ADDON_DEPENDS@ +/// +/// +/// My image decoder addon summary +/// My image decoder description +/// @PLATFORM@ +/// +/// +/// ~~~~~~~~~~~~~ +/// +/// ### Standard values that can be declared for processing in `addon.xml`. +/// +/// These values are used by Kodi to identify associated images and file +/// extensions and then to select the associated addon. +/// +/// \table_start +/// \table_h3{ Labels, Type, Description } +/// \table_row3{ `point`, +/// @anchor cpp_kodi_addon_imagedecoder_point +/// string, +/// The identification of the addon instance to image decoder is mandatory +/// `kodi.imagedecoder`. In addition\, the instance declared in the +/// first `` is also the main type of addon. +/// } +/// \table_row3{ `extension`, +/// @anchor cpp_kodi_addon_imagedecoder_defaultPort +/// string, +/// The from addon operated and supported image file endings.\n +/// Use a `|` to separate between different ones. +/// } +/// \table_row3{ `defaultPort`, +/// @anchor cpp_kodi_addon_imagedecoder_defaultPort +/// string, +/// The from addon operated image [mimetypes](https://en.wikipedia.org/wiki/Media_type).\n +/// Use a `|` to separate between different ones. +/// } +/// \table_row3{ `library_@PLATFORM@`, +/// @anchor cpp_kodi_addon_imagedecoder_library +/// string, +/// The runtime library used for the addon. This is usually declared by `cmake` and correctly displayed in the translated `addon.xml`. +/// } +/// \table_end +/// +/// @remark For more detailed description of the `addon.xml`, see also https://kodi.wiki/view/Addon.xml. +/// +/// +/// -------------------------------------------------------------------------- +/// +/// +/// **Example:** +/// +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class ATTRIBUTE_HIDDEN CMyImageDecoder : public kodi::addon::CInstanceImageDecoder +/// { +/// public: +/// CMyImageDecoder(KODI_HANDLE instance, const std::string& kodiVersion); +/// +/// bool LoadImageFromMemory(unsigned char* buffer, +/// unsigned int bufSize, +/// unsigned int& width, +/// unsigned int& height) override; +/// +/// bool Decode(unsigned char* pixels, +/// unsigned int width, +/// unsigned int height, +/// unsigned int pitch, +/// ImageFormat format) override; +/// +/// ... +/// }; +/// +/// CMyImageDecoder::CMyImageDecoder(KODI_HANDLE instance, const std::string& kodiVersion) +/// : CInstanceImageDecoder(instance, kodiVersion) +/// { +/// ... +/// } +/// +/// bool CMyImageDecoder::LoadImageFromMemory(unsigned char* buffer, +/// unsigned int bufSize, +/// unsigned int& width, +/// unsigned int& height) +/// { +/// ... +/// return true; +/// } +/// +/// bool CMyImageDecoder::Decode(unsigned char* pixels, +/// unsigned int width, +/// unsigned int height, +/// unsigned int pitch, +/// ImageFormat format) override; +/// { +/// ... +/// return true; +/// } +/// +/// //---------------------------------------------------------------------- +/// +/// class ATTRIBUTE_HIDDEN CMyAddon : public kodi::addon::CAddonBase +/// { +/// public: +/// CMyAddon() = default; +/// ADDON_STATUS CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) override; +/// }; +/// +/// // If you use only one instance in your add-on, can be instanceType and +/// // instanceID ignored +/// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) +/// { +/// if (instanceType == ADDON_INSTANCE_IMAGEDECODER) +/// { +/// kodi::Log(ADDON_LOG_INFO, "Creating my image decoder instance"); +/// addonInstance = new CMyImageDecoder(instance, version); +/// return ADDON_STATUS_OK; +/// } +/// else if (...) +/// { +/// ... +/// } +/// return ADDON_STATUS_UNKNOWN; +/// } +/// +/// ADDONCREATOR(CMyAddon) +/// ~~~~~~~~~~~~~ +/// +/// The destruction of the example class `CMyImageDecoder` is called from +/// Kodi's header. Manually deleting the add-on instance is not required. +/// +//------------------------------------------------------------------------------ +class ATTRIBUTE_HIDDEN CInstanceImageDecoder : public IAddonInstance +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_addon_imagedecoder + /// @brief Class constructor. + /// + /// @param[in] instance The from Kodi given instance given be add-on + /// CreateInstance call with instance id + /// @ref ADDON_INSTANCE_IMAGEDECODER. + /// @param[in] kodiVersion [opt] Version used in Kodi for this instance, to + /// allow compatibility to older Kodi versions. + /// + /// @note Recommended to set `kodiVersion`. + /// + explicit CInstanceImageDecoder(KODI_HANDLE instance, const std::string& kodiVersion = "") + : IAddonInstance(ADDON_INSTANCE_IMAGEDECODER, + !kodiVersion.empty() ? kodiVersion + : GetKodiTypeVersion(ADDON_INSTANCE_IMAGEDECODER)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceImageDecoder: Creation of multiple together " + "with single instance way is not allowed!"); + + SetAddonStruct(instance); + } + //---------------------------------------------------------------------------- + + ~CInstanceImageDecoder() override = default; + + //============================================================================ + /// @ingroup cpp_kodi_addon_imagedecoder + /// @brief Initialize an encoder. + /// + /// @param[in] buffer The data to read from memory + /// @param[in] bufSize The buffer size + /// @param[in,out] width The optimal width of image on entry, obtained width + /// on return + /// @param[in,out] height The optimal height of image, actual obtained height + /// on return + /// @return true if successful done, false on error + /// + virtual bool LoadImageFromMemory(unsigned char* buffer, + unsigned int bufSize, + unsigned int& width, + unsigned int& height) = 0; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_imagedecoder + /// @brief Decode previously loaded image. + /// + /// @param[in] pixels Output buffer + /// @param[in] width Width of output image + /// @param[in] height Height of output image + /// @param[in] pitch Pitch of output image + /// @param[in] format Format of output image + /// @return true if successful done, false on error + /// + virtual bool Decode(unsigned char* pixels, + unsigned int width, + unsigned int height, + unsigned int pitch, + ImageFormat format) = 0; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_imagedecoder + /// @brief **Callback to Kodi Function**\n + /// Get the wanted mime type from Kodi. + /// + /// @return the mimetype wanted from Kodi + /// + /// @remarks Only called from addon itself. + /// + inline std::string MimeType() { return m_instanceData->props->mimetype; } + //---------------------------------------------------------------------------- + +private: + void SetAddonStruct(KODI_HANDLE instance) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstanceImageDecoder: Creation with empty addon " + "structure not allowed, table must be given from Kodi!"); + + m_instanceData = static_cast(instance); + m_instanceData->toAddon->addonInstance = this; + m_instanceData->toAddon->load_image_from_memory = ADDON_LoadImageFromMemory; + m_instanceData->toAddon->decode = ADDON_Decode; + } + + inline static bool ADDON_LoadImageFromMemory(const AddonInstance_ImageDecoder* instance, + unsigned char* buffer, + unsigned int bufSize, + unsigned int* width, + unsigned int* height) + { + return static_cast(instance->toAddon->addonInstance) + ->LoadImageFromMemory(buffer, bufSize, *width, *height); + } + + inline static bool ADDON_Decode(const AddonInstance_ImageDecoder* instance, + unsigned char* pixels, + unsigned int width, + unsigned int height, + unsigned int pitch, + enum ImageFormat format) + { + return static_cast(instance->toAddon->addonInstance) + ->Decode(pixels, width, height, pitch, format); + } + + AddonInstance_ImageDecoder* m_instanceData; +}; + +} /* namespace addon */ +} /* namespace kodi */ +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Inputstream.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Inputstream.h new file mode 100644 index 0000000..396b92e --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Inputstream.h @@ -0,0 +1,934 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +/* + * Parts with a comment named "internal" are only used inside header and not + * used or accessed direct during add-on development! + */ + +#include "../AddonBase.h" +#include "../StreamCodec.h" +#include "../StreamCrypto.h" + +#ifdef BUILD_KODI_ADDON +#include "../DemuxPacket.h" +#include "../InputStreamConstants.h" +#else +#include "cores/VideoPlayer/Interface/Addon/DemuxPacket.h" +#include "cores/VideoPlayer/Interface/Addon/InputStreamConstants.h" +#endif + +//Increment this level always if you add features which can lead to compile failures in the addon +#define INPUTSTREAM_VERSION_LEVEL 2 + +#define INPUTSTREAM_MAX_STREAM_COUNT 256 +#define INPUTSTREAM_MAX_STRING_NAME_SIZE 256 +#define INPUTSTREAM_MAX_STRING_CODEC_SIZE 32 +#define INPUTSTREAM_MAX_STRING_LANGUAGE_SIZE 64 + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + /*! + * @brief InputStream add-on capabilities. All capabilities are set to "false" as default. + */ + struct INPUTSTREAM_CAPABILITIES + { + enum MASKTYPE : uint32_t + { + /// supports interface IDemux + SUPPORTS_IDEMUX = (1 << 0), + + /// supports interface IPosTime + SUPPORTS_IPOSTIME = (1 << 1), + + /// supports interface IDisplayTime + SUPPORTS_IDISPLAYTIME = (1 << 2), + + /// supports seek + SUPPORTS_SEEK = (1 << 3), + + /// supports pause + SUPPORTS_PAUSE = (1 << 4), + + /// supports interface ITime + SUPPORTS_ITIME = (1 << 5), + + /// supports interface IChapter + SUPPORTS_ICHAPTER = (1 << 6), + }; + + /// set of supported capabilities + uint32_t m_mask; + }; + + /*! + * @brief structure of key/value pairs passed to addon on Open() + */ + struct INPUTSTREAM + { + const char* m_strURL; + const char* m_mimeType; + + unsigned int m_nCountInfoValues; + struct LISTITEMPROPERTY + { + const char* m_strKey; + const char* m_strValue; + } m_ListItemProperties[STREAM_MAX_PROPERTY_COUNT]; + + const char* m_libFolder; + const char* m_profileFolder; + }; + + /*! + * @brief Array of stream IDs + */ + struct INPUTSTREAM_IDS + { + unsigned int m_streamCount; + unsigned int m_streamIds[INPUTSTREAM_MAX_STREAM_COUNT]; + }; + + /*! + * @brief MASTERING Metadata + */ + struct INPUTSTREAM_MASTERING_METADATA + { + double primary_r_chromaticity_x; + double primary_r_chromaticity_y; + double primary_g_chromaticity_x; + double primary_g_chromaticity_y; + double primary_b_chromaticity_x; + double primary_b_chromaticity_y; + double white_point_chromaticity_x; + double white_point_chromaticity_y; + double luminance_max; + double luminance_min; + }; + + /*! + * @brief CONTENTLIGHT Metadata + */ + struct INPUTSTREAM_CONTENTLIGHT_METADATA + { + uint64_t max_cll; + uint64_t max_fall; + }; + + /*! + * @brief stream properties + */ + struct INPUTSTREAM_INFO + { + enum STREAM_TYPE + { + TYPE_NONE = 0, + TYPE_VIDEO, + TYPE_AUDIO, + TYPE_SUBTITLE, + TYPE_TELETEXT, + TYPE_RDS, + } m_streamType; + + enum Codec_FEATURES : uint32_t + { + FEATURE_DECODE = 1 + }; + uint32_t m_features; + + enum STREAM_FLAGS : uint32_t + { + FLAG_NONE = 0x0000, + FLAG_DEFAULT = 0x0001, + FLAG_DUB = 0x0002, + FLAG_ORIGINAL = 0x0004, + FLAG_COMMENT = 0x0008, + FLAG_LYRICS = 0x0010, + FLAG_KARAOKE = 0x0020, + FLAG_FORCED = 0x0040, + FLAG_HEARING_IMPAIRED = 0x0080, + FLAG_VISUAL_IMPAIRED = 0x0100, + }; + + // Keep in sync with AVColorSpace + enum COLORSPACE + { + COLORSPACE_RGB = 0, + COLORSPACE_BT709 = 1, + COLORSPACE_UNSPECIFIED = 2, + COLORSPACE_UNKNOWN = COLORSPACE_UNSPECIFIED, // compatibility + COLORSPACE_RESERVED = 3, + COLORSPACE_FCC = 4, + COLORSPACE_BT470BG = 5, + COLORSPACE_SMPTE170M = 6, + COLORSPACE_SMPTE240M = 7, + COLORSPACE_YCGCO = 8, + COLORSPACE_YCOCG = COLORSPACE_YCGCO, + COLORSPACE_BT2020_NCL = 9, + COLORSPACE_BT2020_CL = 10, + COLORSPACE_SMPTE2085 = 11, + COLORSPACE_CHROMA_DERIVED_NCL = 12, + COLORSPACE_CHROMA_DERIVED_CL = 13, + COLORSPACE_ICTCP = 14, + COLORSPACE_MAX + }; + + // Keep in sync with AVColorPrimaries + enum COLORPRIMARIES : int32_t + { + COLORPRIMARY_RESERVED0 = 0, + COLORPRIMARY_BT709 = 1, + COLORPRIMARY_UNSPECIFIED = 2, + COLORPRIMARY_RESERVED = 3, + COLORPRIMARY_BT470M = 4, + COLORPRIMARY_BT470BG = 5, + COLORPRIMARY_SMPTE170M = 6, + COLORPRIMARY_SMPTE240M = 7, + COLORPRIMARY_FILM = 8, + COLORPRIMARY_BT2020 = 9, + COLORPRIMARY_SMPTE428 = 10, + COLORPRIMARY_SMPTEST428_1 = COLORPRIMARY_SMPTE428, + COLORPRIMARY_SMPTE431 = 11, + COLORPRIMARY_SMPTE432 = 12, + COLORPRIMARY_JEDEC_P22 = 22, + COLORPRIMARY_MAX + }; + + // Keep in sync with AVColorRange + enum COLORRANGE + { + COLORRANGE_UNKNOWN = 0, + COLORRANGE_LIMITED, + COLORRANGE_FULLRANGE, + COLORRANGE_MAX + }; + + // keep in sync with AVColorTransferCharacteristic + enum COLORTRC : int32_t + { + COLORTRC_RESERVED0 = 0, + COLORTRC_BT709 = 1, + COLORTRC_UNSPECIFIED = 2, + COLORTRC_RESERVED = 3, + COLORTRC_GAMMA22 = 4, + COLORTRC_GAMMA28 = 5, + COLORTRC_SMPTE170M = 6, + COLORTRC_SMPTE240M = 7, + COLORTRC_LINEAR = 8, + COLORTRC_LOG = 9, + COLORTRC_LOG_SQRT = 10, + COLORTRC_IEC61966_2_4 = 11, + COLORTRC_BT1361_ECG = 12, + COLORTRC_IEC61966_2_1 = 13, + COLORTRC_BT2020_10 = 14, + COLORTRC_BT2020_12 = 15, + COLORTRC_SMPTE2084 = 16, + COLORTRC_SMPTEST2084 = COLORTRC_SMPTE2084, + COLORTRC_SMPTE428 = 17, + COLORTRC_SMPTEST428_1 = COLORTRC_SMPTE428, + COLORTRC_ARIB_STD_B67 = 18, + COLORTRC_MAX + }; + + uint32_t m_flags; + + //! @brief (optional) name of the stream, \0 for default handling + char m_name[INPUTSTREAM_MAX_STRING_NAME_SIZE]; + + //! @brief (required) name of codec according to ffmpeg + char m_codecName[INPUTSTREAM_MAX_STRING_CODEC_SIZE]; + + //! @brief (optional) internal name of codec (selectionstream info) + char m_codecInternalName[INPUTSTREAM_MAX_STRING_CODEC_SIZE]; + + //! @brief (optional) the profile of the codec + STREAMCODEC_PROFILE m_codecProfile; + + //! @brief (required) physical index + unsigned int m_pID; + + const uint8_t* m_ExtraData; + unsigned int m_ExtraSize; + + //! @brief RFC 5646 language code (empty string if undefined) + char m_language[INPUTSTREAM_MAX_STRING_LANGUAGE_SIZE]; + + //! Video stream related data + //@{ + + //! @brief Scale of 1000 and a rate of 29970 will result in 29.97 fps + unsigned int m_FpsScale; + + unsigned int m_FpsRate; + + //! @brief height of the stream reported by the demuxer + unsigned int m_Height; + + //! @brief width of the stream reported by the demuxer + unsigned int m_Width; + + //! @brief display aspect of stream + float m_Aspect; + + //@} + + //! Audio stream related data + //@{ + + //! @brief (required) amount of channels + unsigned int m_Channels; + + //! @brief (required) sample rate + unsigned int m_SampleRate; + + //! @brief (required) bit rate + unsigned int m_BitRate; + + //! @brief (required) bits per sample + unsigned int m_BitsPerSample; + + unsigned int m_BlockAlign; + + //@} + + CRYPTO_INFO m_cryptoInfo; + + // new in API version 2.0.8 + //@{ + //! @brief Codec If available, the fourcc code codec + unsigned int m_codecFourCC; + + //! @brief definition of colorspace + COLORSPACE m_colorSpace; + + //! @brief color range if available + COLORRANGE m_colorRange; + //@} + + //new in API 2.0.9 / INPUTSTREAM_VERSION_LEVEL 1 + //@{ + COLORPRIMARIES m_colorPrimaries; + COLORTRC m_colorTransferCharacteristic; + //@} + + //! @brief mastering static Metadata + INPUTSTREAM_MASTERING_METADATA* m_masteringMetadata; + + //! @brief content light static Metadata + INPUTSTREAM_CONTENTLIGHT_METADATA* m_contentLightMetadata; + }; + + struct INPUTSTREAM_TIMES + { + time_t startTime; + double ptsStart; + double ptsBegin; + double ptsEnd; + }; + + /*! + * @brief "C" ABI Structures to transfer the methods from this to Kodi + */ + + // this are properties given to the addon on create + // at this time we have no parameters for the addon + typedef struct AddonProps_InputStream /* internal */ + { + int dummy; + } AddonProps_InputStream; + + typedef struct AddonToKodiFuncTable_InputStream /* internal */ + { + KODI_HANDLE kodiInstance; + DemuxPacket* (*allocate_demux_packet)(void* kodiInstance, int data_size); + DemuxPacket* (*allocate_encrypted_demux_packet)(void* kodiInstance, + unsigned int data_size, + unsigned int encrypted_subsample_count); + void (*free_demux_packet)(void* kodiInstance, DemuxPacket* packet); + } AddonToKodiFuncTable_InputStream; + + struct AddonInstance_InputStream; + typedef struct KodiToAddonFuncTable_InputStream /* internal */ + { + KODI_HANDLE addonInstance; + + bool(__cdecl* open)(const AddonInstance_InputStream* instance, INPUTSTREAM* props); + void(__cdecl* close)(const AddonInstance_InputStream* instance); + const char*(__cdecl* get_path_list)(const AddonInstance_InputStream* instance); + void(__cdecl* get_capabilities)(const AddonInstance_InputStream* instance, + INPUTSTREAM_CAPABILITIES* capabilities); + + // IDemux + struct INPUTSTREAM_IDS(__cdecl* get_stream_ids)(const AddonInstance_InputStream* instance); + struct INPUTSTREAM_INFO(__cdecl* get_stream)(const AddonInstance_InputStream* instance, + int streamid); + void(__cdecl* enable_stream)(const AddonInstance_InputStream* instance, + int streamid, + bool enable); + bool(__cdecl* open_stream)(const AddonInstance_InputStream* instance, int streamid); + void(__cdecl* demux_reset)(const AddonInstance_InputStream* instance); + void(__cdecl* demux_abort)(const AddonInstance_InputStream* instance); + void(__cdecl* demux_flush)(const AddonInstance_InputStream* instance); + DemuxPacket*(__cdecl* demux_read)(const AddonInstance_InputStream* instance); + bool(__cdecl* demux_seek_time)(const AddonInstance_InputStream* instance, + double time, + bool backwards, + double* startpts); + void(__cdecl* demux_set_speed)(const AddonInstance_InputStream* instance, int speed); + void(__cdecl* set_video_resolution)(const AddonInstance_InputStream* instance, + int width, + int height); + + // IDisplayTime + int(__cdecl* get_total_time)(const AddonInstance_InputStream* instance); + int(__cdecl* get_time)(const AddonInstance_InputStream* instance); + + // ITime + bool(__cdecl* get_times)(const AddonInstance_InputStream* instance, INPUTSTREAM_TIMES* times); + + // IPosTime + bool(__cdecl* pos_time)(const AddonInstance_InputStream* instance, int ms); + + int(__cdecl* read_stream)(const AddonInstance_InputStream* instance, + uint8_t* buffer, + unsigned int bufferSize); + int64_t(__cdecl* seek_stream)(const AddonInstance_InputStream* instance, + int64_t position, + int whence); + int64_t(__cdecl* position_stream)(const AddonInstance_InputStream* instance); + int64_t(__cdecl* length_stream)(const AddonInstance_InputStream* instance); + bool(__cdecl* is_real_time_stream)(const AddonInstance_InputStream* instance); + + // IChapter + int(__cdecl* get_chapter)(const AddonInstance_InputStream* instance); + int(__cdecl* get_chapter_count)(const AddonInstance_InputStream* instance); + const char*(__cdecl* get_chapter_name)(const AddonInstance_InputStream* instance, int ch); + int64_t(__cdecl* get_chapter_pos)(const AddonInstance_InputStream* instance, int ch); + bool(__cdecl* seek_chapter)(const AddonInstance_InputStream* instance, int ch); + + int(__cdecl* block_size_stream)(const AddonInstance_InputStream* instance); + } KodiToAddonFuncTable_InputStream; + + typedef struct AddonInstance_InputStream /* internal */ + { + AddonProps_InputStream* props; + AddonToKodiFuncTable_InputStream* toKodi; + KodiToAddonFuncTable_InputStream* toAddon; + } AddonInstance_InputStream; + +#ifdef __cplusplus +} /* extern "C" */ + +namespace kodi +{ +namespace addon +{ + +class ATTRIBUTE_HIDDEN CInstanceInputStream : public IAddonInstance +{ +public: + explicit CInstanceInputStream(KODI_HANDLE instance, const std::string& kodiVersion = "") + : IAddonInstance(ADDON_INSTANCE_INPUTSTREAM, + !kodiVersion.empty() ? kodiVersion + : GetKodiTypeVersion(ADDON_INSTANCE_INPUTSTREAM)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceInputStream: Creation of multiple together " + "with single instance way is not allowed!"); + + SetAddonStruct(instance, m_kodiVersion); + } + + ~CInstanceInputStream() override = default; + + /*! + * Open a stream. + * @param props + * @return True if the stream has been opened successfully, false otherwise. + * @remarks + */ + virtual bool Open(INPUTSTREAM& props) = 0; + + /*! + * Close an open stream. + * @remarks + */ + virtual void Close() = 0; + + /*! + * Get Capabilities of this addon. + * @param capabilities The add-on's capabilities. + * @remarks + */ + virtual void GetCapabilities(INPUTSTREAM_CAPABILITIES& capabilities) = 0; + + /*! + * Get IDs of available streams + * @remarks + */ + virtual INPUTSTREAM_IDS GetStreamIds() = 0; + + /*! + * Get stream properties of a stream. + * @param streamid unique id of stream + * @return struc of stream properties + * @remarks + */ + virtual INPUTSTREAM_INFO GetStream(int streamid) = 0; + + /*! + * Enable or disable a stream. + * A disabled stream does not send demux packets + * @param streamid unique id of stream + * @param enable true for enable, false for disable + * @remarks + */ + virtual void EnableStream(int streamid, bool enable) = 0; + + /*! + * Opens a stream for playback. + * @param streamid unique id of stream + * @remarks + */ + virtual bool OpenStream(int streamid) = 0; + + /*! + * Reset the demultiplexer in the add-on. + * @remarks Required if bHandlesDemuxing is set to true. + */ + virtual void DemuxReset() {} + + /*! + * Abort the demultiplexer thread in the add-on. + * @remarks Required if bHandlesDemuxing is set to true. + */ + virtual void DemuxAbort() {} + + /*! + * Flush all data that's currently in the demultiplexer buffer in the add-on. + * @remarks Required if bHandlesDemuxing is set to true. + */ + virtual void DemuxFlush() {} + + /*! + * Read the next packet from the demultiplexer, if there is one. + * @return The next packet. + * If there is no next packet, then the add-on should return the + * packet created by calling AllocateDemuxPacket(0) on the callback. + * If the stream changed and Kodi's player needs to be reinitialised, + * then, the add-on should call AllocateDemuxPacket(0) on the + * callback, and set the streamid to DMX_SPECIALID_STREAMCHANGE and + * return the value. + * The add-on should return NULL if an error occurred. + * @remarks Return NULL if this add-on won't provide this function. + */ + virtual DemuxPacket* DemuxRead() { return nullptr; } + + /*! + * Notify the InputStream addon/demuxer that Kodi wishes to seek the stream by time + * Demuxer is required to set stream to an IDR frame + * @param time The absolute time since stream start + * @param backwards True to seek to keyframe BEFORE time, else AFTER + * @param startpts can be updated to point to where display should start + * @return True if the seek operation was possible + * @remarks Optional, and only used if addon has its own demuxer. + */ + virtual bool DemuxSeekTime(double time, bool backwards, double& startpts) { return false; } + + /*! + * Notify the InputStream addon/demuxer that Kodi wishes to change playback speed + * @param speed The requested playback speed + * @remarks Optional, and only used if addon has its own demuxer. + */ + virtual void DemuxSetSpeed(int speed) {} + + /*! + * Sets desired width / height + * @param width / hight + */ + virtual void SetVideoResolution(int width, int height) {} + + /*! + * Totel time in ms + * @remarks + */ + virtual int GetTotalTime() { return -1; } + + /*! + * Playing time in ms + * @remarks + */ + virtual int GetTime() { return -1; } + + /*! + * Get current timing values in PTS scale + * @remarks + */ + virtual bool GetTimes(INPUTSTREAM_TIMES& times) { return false; } + + /*! + * Positions inputstream to playing time given in ms + * @remarks + */ + virtual bool PosTime(int ms) { return false; } + + /*! + * Return currently selected chapter + * @remarks + */ + virtual int GetChapter() { return -1; }; + + /*! + * Return number of available chapters + * @remarks + */ + virtual int GetChapterCount() { return 0; }; + + /*! + * Return name of chapter # ch + * @remarks + */ + virtual const char* GetChapterName(int ch) { return nullptr; }; + + /*! + * Return position if chapter # ch in milliseconds + * @remarks + */ + virtual int64_t GetChapterPos(int ch) { return 0; }; + + /*! + * Seek to the beginning of chapter # ch + * @remarks + */ + virtual bool SeekChapter(int ch) { return false; }; + + /*! + * Read from an open stream. + * @param buffer The buffer to store the data in. + * @param bufferSize The amount of bytes to read. + * @return The amount of bytes that were actually read from the stream. + * @remarks Return -1 if this add-on won't provide this function. + */ + virtual int ReadStream(uint8_t* buffer, unsigned int bufferSize) { return -1; } + + /*! + * Seek in a stream. + * @param position The position to seek to. + * @param whence ? + * @return The new position. + * @remarks Return -1 if this add-on won't provide this function. + */ + virtual int64_t SeekStream(int64_t position, int whence = SEEK_SET) { return -1; } + + /*! + * @return The position in the stream that's currently being read. + * @remarks Return -1 if this add-on won't provide this function. + */ + virtual int64_t PositionStream() { return -1; } + + /*! + * @return The total length of the stream that's currently being read. + * @remarks Return -1 if this add-on won't provide this function. + */ + virtual int64_t LengthStream() { return -1; } + + /*! + * @return Obtain the chunk size to use when reading streams. + * @remarks Return 0 if this add-on won't provide this function. + */ + virtual int GetBlockSize() { return 0; } + + /*! + * Check for real-time streaming + * @return true if current stream is real-time + */ + virtual bool IsRealTimeStream() { return true; } + + /*! + * @brief Allocate a demux packet. Free with FreeDemuxPacket + * @param dataSize The size of the data that will go into the packet + * @return The allocated packet + */ + DemuxPacket* AllocateDemuxPacket(int dataSize) + { + return m_instanceData->toKodi->allocate_demux_packet(m_instanceData->toKodi->kodiInstance, + dataSize); + } + + /*! + * @brief Allocate a demux packet. Free with FreeDemuxPacket + * @param dataSize The size of the data that will go into the packet + * @return The allocated packet + */ + DemuxPacket* AllocateEncryptedDemuxPacket(int dataSize, unsigned int encryptedSubsampleCount) + { + return m_instanceData->toKodi->allocate_encrypted_demux_packet( + m_instanceData->toKodi->kodiInstance, dataSize, encryptedSubsampleCount); + } + + /*! + * @brief Free a packet that was allocated with AllocateDemuxPacket + * @param packet The packet to free + */ + void FreeDemuxPacket(DemuxPacket* packet) + { + return m_instanceData->toKodi->free_demux_packet(m_instanceData->toKodi->kodiInstance, packet); + } + +private: + static int compareVersion(const int v1[3], const int v2[3]) + { + for (unsigned i(0); i < 3; ++i) + if (v1[i] != v2[i]) + return v1[i] - v2[i]; + return 0; + } + + void SetAddonStruct(KODI_HANDLE instance, const std::string& kodiVersion) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstanceInputStream: Creation with empty addon " + "structure not allowed, table must be given from Kodi!"); + int api[3] = { 0, 0, 0 }; + sscanf(kodiVersion.c_str(), "%d.%d.%d", &api[0], &api[1], &api[2]); + + m_instanceData = static_cast(instance); + m_instanceData->toAddon->addonInstance = this; + m_instanceData->toAddon->open = ADDON_Open; + m_instanceData->toAddon->close = ADDON_Close; + m_instanceData->toAddon->get_capabilities = ADDON_GetCapabilities; + + m_instanceData->toAddon->get_stream_ids = ADDON_GetStreamIds; + m_instanceData->toAddon->get_stream = ADDON_GetStream; + m_instanceData->toAddon->enable_stream = ADDON_EnableStream; + m_instanceData->toAddon->open_stream = ADDON_OpenStream; + m_instanceData->toAddon->demux_reset = ADDON_DemuxReset; + m_instanceData->toAddon->demux_abort = ADDON_DemuxAbort; + m_instanceData->toAddon->demux_flush = ADDON_DemuxFlush; + m_instanceData->toAddon->demux_read = ADDON_DemuxRead; + m_instanceData->toAddon->demux_seek_time = ADDON_DemuxSeekTime; + m_instanceData->toAddon->demux_set_speed = ADDON_DemuxSetSpeed; + m_instanceData->toAddon->set_video_resolution = ADDON_SetVideoResolution; + + m_instanceData->toAddon->get_total_time = ADDON_GetTotalTime; + m_instanceData->toAddon->get_time = ADDON_GetTime; + + m_instanceData->toAddon->get_times = ADDON_GetTimes; + m_instanceData->toAddon->pos_time = ADDON_PosTime; + + m_instanceData->toAddon->read_stream = ADDON_ReadStream; + m_instanceData->toAddon->seek_stream = ADDON_SeekStream; + m_instanceData->toAddon->position_stream = ADDON_PositionStream; + m_instanceData->toAddon->length_stream = ADDON_LengthStream; + m_instanceData->toAddon->is_real_time_stream = ADDON_IsRealTimeStream; + + // Added on 2.0.10 + m_instanceData->toAddon->get_chapter = ADDON_GetChapter; + m_instanceData->toAddon->get_chapter_count = ADDON_GetChapterCount; + m_instanceData->toAddon->get_chapter_name = ADDON_GetChapterName; + m_instanceData->toAddon->get_chapter_pos = ADDON_GetChapterPos; + m_instanceData->toAddon->seek_chapter = ADDON_SeekChapter; + + // Added on 2.0.12 + m_instanceData->toAddon->block_size_stream = ADDON_GetBlockSize; + + /* + // Way to include part on new API version + int minPartVersion[3] = { 3, 0, 0 }; + if (compareVersion(api, minPartVersion) >= 0) + { + + } + */ + } + + inline static bool ADDON_Open(const AddonInstance_InputStream* instance, INPUTSTREAM* props) + { + return static_cast(instance->toAddon->addonInstance)->Open(*props); + } + + inline static void ADDON_Close(const AddonInstance_InputStream* instance) + { + static_cast(instance->toAddon->addonInstance)->Close(); + } + + inline static void ADDON_GetCapabilities(const AddonInstance_InputStream* instance, + INPUTSTREAM_CAPABILITIES* capabilities) + { + static_cast(instance->toAddon->addonInstance) + ->GetCapabilities(*capabilities); + } + + + // IDemux + inline static struct INPUTSTREAM_IDS ADDON_GetStreamIds(const AddonInstance_InputStream* instance) + { + return static_cast(instance->toAddon->addonInstance)->GetStreamIds(); + } + + inline static struct INPUTSTREAM_INFO ADDON_GetStream(const AddonInstance_InputStream* instance, + int streamid) + { + return static_cast(instance->toAddon->addonInstance) + ->GetStream(streamid); + } + + inline static void ADDON_EnableStream(const AddonInstance_InputStream* instance, + int streamid, + bool enable) + { + static_cast(instance->toAddon->addonInstance) + ->EnableStream(streamid, enable); + } + + inline static bool ADDON_OpenStream(const AddonInstance_InputStream* instance, int streamid) + { + return static_cast(instance->toAddon->addonInstance) + ->OpenStream(streamid); + } + + inline static void ADDON_DemuxReset(const AddonInstance_InputStream* instance) + { + static_cast(instance->toAddon->addonInstance)->DemuxReset(); + } + + inline static void ADDON_DemuxAbort(const AddonInstance_InputStream* instance) + { + static_cast(instance->toAddon->addonInstance)->DemuxAbort(); + } + + inline static void ADDON_DemuxFlush(const AddonInstance_InputStream* instance) + { + static_cast(instance->toAddon->addonInstance)->DemuxFlush(); + } + + inline static DemuxPacket* ADDON_DemuxRead(const AddonInstance_InputStream* instance) + { + return static_cast(instance->toAddon->addonInstance)->DemuxRead(); + } + + inline static bool ADDON_DemuxSeekTime(const AddonInstance_InputStream* instance, + double time, + bool backwards, + double* startpts) + { + return static_cast(instance->toAddon->addonInstance) + ->DemuxSeekTime(time, backwards, *startpts); + } + + inline static void ADDON_DemuxSetSpeed(const AddonInstance_InputStream* instance, int speed) + { + static_cast(instance->toAddon->addonInstance)->DemuxSetSpeed(speed); + } + + inline static void ADDON_SetVideoResolution(const AddonInstance_InputStream* instance, + int width, + int height) + { + static_cast(instance->toAddon->addonInstance) + ->SetVideoResolution(width, height); + } + + + // IDisplayTime + inline static int ADDON_GetTotalTime(const AddonInstance_InputStream* instance) + { + return static_cast(instance->toAddon->addonInstance)->GetTotalTime(); + } + + inline static int ADDON_GetTime(const AddonInstance_InputStream* instance) + { + return static_cast(instance->toAddon->addonInstance)->GetTime(); + } + + // ITime + inline static bool ADDON_GetTimes(const AddonInstance_InputStream* instance, + INPUTSTREAM_TIMES* times) + { + return static_cast(instance->toAddon->addonInstance)->GetTimes(*times); + } + + // IPosTime + inline static bool ADDON_PosTime(const AddonInstance_InputStream* instance, int ms) + { + return static_cast(instance->toAddon->addonInstance)->PosTime(ms); + } + + inline static int ADDON_GetChapter(const AddonInstance_InputStream* instance) + { + return static_cast(instance->toAddon->addonInstance)->GetChapter(); + } + + inline static int ADDON_GetChapterCount(const AddonInstance_InputStream* instance) + { + return static_cast(instance->toAddon->addonInstance)->GetChapterCount(); + } + + inline static const char* ADDON_GetChapterName(const AddonInstance_InputStream* instance, int ch) + { + return static_cast(instance->toAddon->addonInstance)->GetChapterName(ch); + } + + inline static int64_t ADDON_GetChapterPos(const AddonInstance_InputStream* instance, int ch) + { + return static_cast(instance->toAddon->addonInstance)->GetChapterPos(ch); + } + + inline static bool ADDON_SeekChapter(const AddonInstance_InputStream* instance, int ch) + { + return static_cast(instance->toAddon->addonInstance)->SeekChapter(ch); + } + + inline static int ADDON_ReadStream(const AddonInstance_InputStream* instance, + uint8_t* buffer, + unsigned int bufferSize) + { + return static_cast(instance->toAddon->addonInstance) + ->ReadStream(buffer, bufferSize); + } + + inline static int64_t ADDON_SeekStream(const AddonInstance_InputStream* instance, + int64_t position, + int whence) + { + return static_cast(instance->toAddon->addonInstance) + ->SeekStream(position, whence); + } + + inline static int64_t ADDON_PositionStream(const AddonInstance_InputStream* instance) + { + return static_cast(instance->toAddon->addonInstance)->PositionStream(); + } + + inline static int64_t ADDON_LengthStream(const AddonInstance_InputStream* instance) + { + return static_cast(instance->toAddon->addonInstance)->LengthStream(); + } + + inline static int ADDON_GetBlockSize(const AddonInstance_InputStream* instance) + { + return static_cast(instance->toAddon->addonInstance)->GetBlockSize(); + } + + inline static bool ADDON_IsRealTimeStream(const AddonInstance_InputStream* instance) + { + return static_cast(instance->toAddon->addonInstance)->IsRealTimeStream(); + } + + AddonInstance_InputStream* m_instanceData; +}; + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/PVR.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/PVR.h new file mode 100644 index 0000000..d5977a7 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/PVR.h @@ -0,0 +1,3423 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../c-api/addon-instance/pvr.h" +#include "pvr/ChannelGroups.h" +#include "pvr/Channels.h" +#include "pvr/EDL.h" +#include "pvr/EPG.h" +#include "pvr/General.h" +#include "pvr/MenuHook.h" +#include "pvr/Recordings.h" +#include "pvr/Stream.h" +#include "pvr/Timers.h" + +#ifdef __cplusplus + +/*! + * @internal + * @brief PVR "C++" API interface + * + * In this field are the pure addon-side C++ data. + * + * @note Changes can be made without problems and have no influence on other + * PVR addons that have already been created.\n + * \n + * Therefore, @ref ADDON_INSTANCE_VERSION_PVR_MIN can be ignored for these + * fields and only the @ref ADDON_INSTANCE_VERSION_PVR needs to be increased.\n + * \n + * Only must be min version increased if a new compile of addon breaks after + * changes here. + * + * Have by add of new parts a look about **Doxygen** `\\ingroup`, so that + * added parts included in documentation. + * + * If you add addon side related documentation, where his dev need know, use `///`. + * For parts only for Kodi make it like here. + * + * @endinternal + */ + +namespace kodi +{ +namespace addon +{ + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" Doxygen group set for the definitions +//{{{ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs Definitions, structures and enumerators +/// @ingroup cpp_kodi_addon_pvr +/// @brief **PVR client add-on instance definition values**\n +/// All PVR functions associated data structures. +/// +/// Used to exchange the available options between Kodi and addon.\n +/// The groups described here correspond to the groups of functions on PVR +/// instance class. +/// + +//############################################################################## +/// @defgroup cpp_kodi_addon_pvr_Defs_General 1. General +/// @ingroup cpp_kodi_addon_pvr_Defs +/// @brief **PVR add-on general variables**\n +/// Used to exchange the available options between Kodi and addon. +/// +/// This group also includes @ref cpp_kodi_addon_pvr_Defs_PVRCapabilities with +/// which Kodi an @ref kodi::addon::CInstancePVRClient::GetCapabilities() +/// queries the supported **modules** of the addon. +/// +/// The standard values are also below, once for error messages and once to +/// @ref kodi::addon::CInstancePVRClient::ConnectionStateChange() to give Kodi +/// any information. +/// +///@{ +//############################################################################## +/// @defgroup cpp_kodi_addon_pvr_Defs_General_Inputstream class PVRStreamProperty & definition PVR_STREAM_PROPERTY +/// @ingroup cpp_kodi_addon_pvr_Defs_General +/// @brief **Inputstream variables**\n +/// This includes values related to the outside of PVR available inputstream +/// system. +/// +/// This can be by separate instance on same addon, by handling in Kodi itself +/// or to reference of another addon where support needed inputstream. +/// +/// @note This is complete independent from own system included here +/// @ref cpp_kodi_addon_pvr_Streams "inputstream". +/// +//------------------------------------------------------------------------------ +///@} + +//############################################################################## +/// @defgroup cpp_kodi_addon_pvr_Defs_Channel 2. Channel +/// @ingroup cpp_kodi_addon_pvr_Defs +/// @brief **PVR add-on channel**\n +/// Used to exchange the available channel options between Kodi and addon. +/// +/// Modules here are mainly intended for @ref cpp_kodi_addon_pvr_Channels "channels", +/// but are also used on other modules to identify the respective TV/radio +/// channel. +/// +/// Because of @ref cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus and +/// @ref cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo is a special case at +/// this point. This is currently only used on running streams, but it may be +/// possible that this must always be usable in connection with PiP in the +/// future. +/// +//------------------------------------------------------------------------------ + +//############################################################################## +/// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup 3. Channel Group +/// @ingroup cpp_kodi_addon_pvr_Defs +/// @brief **PVR add-on channel group**\n +/// This group contains data classes and values which are used in PVR on +/// @ref cpp_kodi_addon_pvr_supportsChannelGroups "channel groups". +/// +//------------------------------------------------------------------------------ + +//############################################################################## +/// @defgroup cpp_kodi_addon_pvr_Defs_epg 4. EPG Tag +/// @ingroup cpp_kodi_addon_pvr_Defs +/// @brief **PVR add-on EPG data**\n +/// Used on @ref cpp_kodi_addon_pvr_EPGTag "EPG methods in PVR instance class". +/// +/// See related modules about, also below in this view are few macros where +/// default values of associated places. +/// +//------------------------------------------------------------------------------ + +//############################################################################## +/// @defgroup cpp_kodi_addon_pvr_Defs_Recording 5. Recording +/// @ingroup cpp_kodi_addon_pvr_Defs +/// @brief **Representation of a recording**\n +/// Used to exchange the available recording data between Kodi and addon on +/// @ref cpp_kodi_addon_pvr_Recordings "Recordings methods in PVR instance class". +/// +//------------------------------------------------------------------------------ + +//############################################################################## +/// @defgroup cpp_kodi_addon_pvr_Defs_Timer 6. Timer +/// @ingroup cpp_kodi_addon_pvr_Defs +/// @brief **PVR add-on timer data**\n +/// Used to exchange the available timer data between Kodi and addon on +/// @ref cpp_kodi_addon_pvr_Timers "Timers methods in PVR instance class". +/// +//------------------------------------------------------------------------------ + +//############################################################################## +/// @defgroup cpp_kodi_addon_pvr_Defs_Menuhook 7. Menuhook +/// @ingroup cpp_kodi_addon_pvr_Defs +/// @brief **PVR Context menu data**\n +/// Define data for the context menus available to the user +/// +//------------------------------------------------------------------------------ + +//############################################################################## +/// @defgroup cpp_kodi_addon_pvr_Defs_EDLEntry 8. Edit decision list (EDL) +/// @ingroup cpp_kodi_addon_pvr_Defs +/// @brief **An edit decision list or EDL is used in the post-production process +/// of film editing and video editing**\n +/// Used on @ref kodi::addon::CInstancePVRClient::GetEPGTagEdl and +/// @ref kodi::addon::CInstancePVRClient::GetRecordingEdl +/// +//------------------------------------------------------------------------------ + +//############################################################################## +/// @defgroup cpp_kodi_addon_pvr_Defs_Stream 9. Inputstream +/// @ingroup cpp_kodi_addon_pvr_Defs +/// @brief **Inputstream**\n +/// This includes classes and values that are used in the PVR inputstream. +/// +/// Used on @ref cpp_kodi_addon_pvr_Streams "Inputstream methods in PVR instance class". +/// +/// @note The parts here will be removed in the future and replaced by the +/// separate @ref cpp_kodi_addon_inputstream "inputstream addon instance". +/// If there is already a possibility, new addons should do it via the +/// inputstream instance. +/// +//------------------------------------------------------------------------------ + +//}}} +//______________________________________________________________________________ + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" PVR addon instance class +//{{{ + +//============================================================================== +/// @addtogroup cpp_kodi_addon_pvr +/// @brief \cpp_class{ kodi::addon::CInstancePVRClient } +/// **PVR client add-on instance** +/// +/// Kodi features powerful [Live TV](https://kodi.wiki/view/Live_TV) and +/// [video recording (DVR/PVR)](http://en.wikipedia.org/wiki/Digital_video_recorder) +/// abilities using a very flexible distributed application structure. That is, by +/// leveraging other existing third-party +/// [PVR backend applications](https://kodi.wiki/view/PVR_backend) or +/// [DVR devices](https://kodi.wiki/view/PVR_backend) +/// that specialize in receiving television signals and also support the same type +/// of [client–server model](http://en.wikipedia.org/wiki/client%E2%80%93server_model) +/// which Kodi uses, (following a [frontend-backend](http://en.wikipedia.org/wiki/Front_and_back_ends) +/// design principle for [separation of concerns](http://en.wikipedia.org/wiki/Separation_of_concerns)), +/// these PVR features in Kodi allow you to watch Live TV, listen to radio, view an EPG TV-Guide +/// and schedule recordings, and also enables many other TV related features, all using +/// Kodi as your primary interface once the initial pairing connection and +/// configuration have been done. +/// +/// @note It is very important to understand that with "Live TV" in the reference +/// to PVR in Kodi, we do not mean [streaming video](http://en.wikipedia.org/wiki/Streaming_media) +/// from the internet via websites providing [free content](https://kodi.wiki/view/Free_content) +/// or online services such as Netflix, Hulu, Vudu and similar, no matter if that +/// content is actually streamed live or not. If that is what you are looking for +/// then you might want to look into [Video Addons](https://kodi.wiki/view/Add-ons) +/// for Kodi instead, (which again is not the same as the "PVR" or "Live TV" we +/// discuss in this article), but remember that [Kodi does not provide any video +/// content or video streaming services](https://kodi.wiki/view/Free_content). +/// +/// The use of the PVR is based on the @ref CInstancePVRClient. +/// +/// Include the header @ref PVR.h "#include " +/// to use this class. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// Here is an example of what the `addon.xml.in` would look like for an PVR addon: +/// +/// ~~~~~~~~~~~~~{.xml} +/// +/// +/// @ADDON_DEPENDS@ +/// +/// +/// My PVR addon addon +/// My PVR addon description +/// @PLATFORM@ +/// +/// +/// ~~~~~~~~~~~~~ +/// +/// +/// At `` the basic instance definition is declared, this is intended to identify the addon as an PVR and to see its supported types: +/// | Name | Description +/// |------|---------------------- +/// | `point` | The identification of the addon instance to inputstream is mandatory `kodi.pvrclient`. In addition, the instance declared in the first `` is also the main type of addon. +/// | `library_@PLATFORM@` | The runtime library used for the addon. This is usually declared by cmake and correctly displayed in the translated `addon.xml`. +/// +/// +/// @remark For more detailed description of the `addon.xml`, see also https://kodi.wiki/view/Addon.xml. +/// +/// +/// -------------------------------------------------------------------------- +/// +/// **Example:** +/// +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class CMyPVRClient : public ::kodi::addon::CInstancePVRClient +/// { +/// public: +/// CMyPVRClient(KODI_HANDLE instance, const std::string& kodiVersion); +/// +/// PVR_ERROR GetCapabilities(kodi::addon::PVRCapabilities& capabilities) override; +/// PVR_ERROR GetBackendName(std::string& name) override; +/// PVR_ERROR GetBackendVersion(std::string& version) override; +/// +/// PVR_ERROR GetChannelsAmount(int& amount) override; +/// PVR_ERROR GetChannels(bool radio, std::vector& channels) override; +/// PVR_ERROR GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, +/// std::vector& properties) override; +/// +/// private: +/// std::vector m_myChannels; +/// }; +/// +/// CMyPVRClient::CMyPVRClient(KODI_HANDLE instance, const std::string& kodiVersion) +/// : CInstancePVRClient(instance, kodiVersion) +/// { +/// kodi::addon::PVRChannel channel; +/// channel.SetUniqueId(123); +/// channel.SetChannelNumber(1); +/// channel.SetChannelName("My test channel"); +/// m_myChannels.push_back(channel); +/// } +/// +/// PVR_ERROR CMyPVRClient::GetCapabilities(kodi::addon::PVRCapabilities& capabilities) +/// { +/// capabilities.SetSupportsTV(true); +/// return PVR_ERROR_NO_ERROR; +/// } +/// +/// PVR_ERROR CMyPVRClient::GetBackendName(std::string& name) +/// { +/// name = "My special PVR client"; +/// return PVR_ERROR_NO_ERROR; +/// } +/// +/// PVR_ERROR CMyPVRClient::GetBackendVersion(std::string& version) +/// { +/// version = "1.0.0"; +/// return PVR_ERROR_NO_ERROR; +/// } +/// +/// PVR_ERROR CMyInstance::GetChannelsAmount(int& amount) +/// { +/// amount = m_myChannels.size(); +/// return PVR_ERROR_NO_ERROR; +/// } +/// +/// PVR_ERROR CMyPVRClient::GetChannels(bool radio, std::vector& channels) +/// { +/// channels = m_myChannels; +/// return PVR_ERROR_NO_ERROR; +/// } +/// +/// PVR_ERROR CMyPVRClient::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, +/// std::vector& properties) +/// { +/// if (channel.GetUniqueId() == 123) +/// { +/// properties.push_back(PVR_STREAM_PROPERTY_STREAMURL, "http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4"); +/// properties.push_back(PVR_STREAM_PROPERTY_ISREALTIMESTREAM, "true"); +/// return PVR_ERROR_NO_ERROR; +/// } +/// return PVR_ERROR_UNKNOWN; +/// } +/// +/// ... +/// +/// //---------------------------------------------------------------------- +/// +/// class CMyAddon : public ::kodi::addon::CAddonBase +/// { +/// public: +/// CMyAddon() = default; +/// ADDON_STATUS CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) override; +/// }; +/// +/// // If you use only one instance in your add-on, can be instanceType and +/// // instanceID ignored +/// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) +/// { +/// if (instanceType == ADDON_INSTANCE_PVR) +/// { +/// kodi::Log(ADDON_LOG_INFO, "Creating my PVR client instance"); +/// addonInstance = new CMyPVRClient(instance, version); +/// return ADDON_STATUS_OK; +/// } +/// else if (...) +/// { +/// ... +/// } +/// return ADDON_STATUS_UNKNOWN; +/// } +/// +/// ADDONCREATOR(CMyAddon) +/// ~~~~~~~~~~~~~ +/// +/// The destruction of the example class `CMyPVRClient` is called from +/// Kodi's header. Manually deleting the add-on instance is not required. +/// +class ATTRIBUTE_HIDDEN CInstancePVRClient : public IAddonInstance +{ +public: + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Base 1. Basic functions + /// @ingroup cpp_kodi_addon_pvr + /// @brief **Functions to manage the addon and get basic information about it**\n + /// These are e.g. @ref GetCapabilities to know supported groups at + /// this addon or the others to get information about the source of the PVR + /// stream. + /// + /// The with "Valid implementation required." declared functions are mandatory, + /// all others are an option. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Basic parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_pvr_Base_header_addon_auto_check + /// @copydetails cpp_kodi_addon_pvr_Base_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief PVR client class constructor. + /// + /// Used by an add-on that only supports only PVR and only in one instance. + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Here's example about the use of this:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// ... + /// + /// class ATTRIBUTE_HIDDEN CPVRExample + /// : public kodi::addon::CAddonBase, + /// public kodi::addon::CInstancePVRClient + /// { + /// public: + /// CPVRExample() + /// { + /// } + /// + /// ~CPVRExample() override; + /// { + /// } + /// + /// ... + /// }; + /// + /// ADDONCREATOR(CPVRExample) + /// ~~~~~~~~~~~~~ + /// + CInstancePVRClient() : IAddonInstance(ADDON_INSTANCE_PVR, GetKodiTypeVersion(ADDON_INSTANCE_PVR)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstancePVRClient: Creation of more as one in single " + "instance way is not allowed!"); + + SetAddonStruct(CAddonBase::m_interface->firstKodiInstance, m_kodiVersion); + CAddonBase::m_interface->globalSingleInstance = this; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief PVR client class constructor used to support multiple instance + /// types. + /// + /// @param[in] instance The instance value given to + /// `kodi::addon::CAddonBase::CreateInstance(...)`. + /// @param[in] kodiVersion [opt] Version used in Kodi for this instance, to + /// allow compatibility to older Kodi versions. + /// + /// @note Recommended to set `kodiVersion`. + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Here's example about the use of this:** + /// ~~~~~~~~~~~~~{.cpp} + /// class CMyPVRClient : public ::kodi::addon::CInstancePVRClient + /// { + /// public: + /// CMyPVRClient(KODI_HANDLE instance, const std::string& kodiVersion) + /// : CInstancePVRClient(instance, kodiVersion) + /// { + /// ... + /// } + /// + /// ... + /// }; + /// + /// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, + /// const std::string& instanceID, + /// KODI_HANDLE instance, + /// const std::string& version, + /// KODI_HANDLE& addonInstance) + /// { + /// kodi::Log(ADDON_LOG_INFO, "Creating my PVR client instance"); + /// addonInstance = new CMyPVRClient(instance, version); + /// return ADDON_STATUS_OK; + /// } + /// ~~~~~~~~~~~~~ + /// + explicit CInstancePVRClient(KODI_HANDLE instance, const std::string& kodiVersion = "") + : IAddonInstance(ADDON_INSTANCE_PVR, + !kodiVersion.empty() ? kodiVersion : GetKodiTypeVersion(ADDON_INSTANCE_PVR)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstancePVRClient: Creation of multiple together with " + "single instance way is not allowed!"); + + SetAddonStruct(instance, m_kodiVersion); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Destructor + /// + ~CInstancePVRClient() override = default; + //---------------------------------------------------------------------------- + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + //============================================================================ + /// @brief Get the list of features that this add-on provides. + /// + /// Called by Kodi to query the add-on's capabilities. + /// Used to check which options should be presented in the UI, which methods to call, etc. + /// All capabilities that the add-on supports should be set to true. + /// + /// @param capabilities The with @ref cpp_kodi_addon_pvr_Defs_PVRCapabilities defined add-on's capabilities. + /// @return @ref PVR_ERROR_NO_ERROR if the properties were fetched successfully. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_PVRCapabilities_Help + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// PVR_ERROR CMyPVRClient::GetCapabilities(kodi::addon::PVRCapabilities& capabilities) + /// { + /// capabilities.SetSupportsTV(true); + /// capabilities.SetSupportsEPG(true); + /// return PVR_ERROR_NO_ERROR; + /// } + /// ~~~~~~~~~~~~~ + /// + /// -------------------------------------------------------------------------- + /// + /// @note Valid implementation required. + /// + virtual PVR_ERROR GetCapabilities(kodi::addon::PVRCapabilities& capabilities) = 0; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the name reported by the backend that will be displayed in the UI. + /// + /// @param[out] name The name reported by the backend that will be displayed in the UI. + /// @return @ref PVR_ERROR_NO_ERROR if successfully done + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// PVR_ERROR CMyPVRClient::GetBackendName(std::string& name) + /// { + /// name = "My special PVR client"; + /// return PVR_ERROR_NO_ERROR; + /// } + /// ~~~~~~~~~~~~~ + /// + /// -------------------------------------------------------------------------- + /// + /// @note Valid implementation required. + /// + virtual PVR_ERROR GetBackendName(std::string& name) = 0; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the version string reported by the backend that will be + /// displayed in the UI. + /// + /// @param[out] version The version string reported by the backend that will be + /// displayed in the UI. + /// @return @ref PVR_ERROR_NO_ERROR if successfully done + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// PVR_ERROR CMyPVRClient::GetBackendVersion(std::string& version) + /// { + /// version = "1.0.0"; + /// return PVR_ERROR_NO_ERROR; + /// } + /// ~~~~~~~~~~~~~ + /// + /// -------------------------------------------------------------------------- + /// + /// @note Valid implementation required. + /// + virtual PVR_ERROR GetBackendVersion(std::string& version) = 0; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the hostname of the pvr backend server + /// + /// @param[out] hostname Hostname as ip address or alias. If backend does not + /// utilize a server, return empty string. + /// @return @ref PVR_ERROR_NO_ERROR if successfully done + /// + virtual PVR_ERROR GetBackendHostname(std::string& hostname) { return PVR_ERROR_NOT_IMPLEMENTED; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief To get the connection string reported by the backend that will be + /// displayed in the UI. + /// + /// @param[out] connection The connection string reported by the backend that + /// will be displayed in the UI. + /// @return @ref PVR_ERROR_NO_ERROR if successfully done + /// + virtual PVR_ERROR GetConnectionString(std::string& connection) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the disk space reported by the backend (if supported). + /// + /// @param[in] total The total disk space in KiB. + /// @param[in] used The used disk space in KiB. + /// @return @ref PVR_ERROR_NO_ERROR if the drive space has been fetched + /// successfully. + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// PVR_ERROR CMyPVRClient::GetDriveSpace(uint64_t& total, uint64_t& used) + /// { + /// total = 100 * 1024 * 1024; // To set complete size of drive in KiB (100GB) + /// used = 12232424; // To set the used amount + /// return PVR_ERROR_NO_ERROR; + /// } + /// ~~~~~~~~~~~~~ + /// + virtual PVR_ERROR GetDriveSpace(uint64_t& total, uint64_t& used) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Call one of the settings related menu hooks (if supported). + /// + /// Supported @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook "menu hook " + /// instances have to be added in `constructor()`, by calling @ref AddMenuHook() + /// on the callback. + /// + /// @param[in] menuhook The hook to call. + /// @return @ref PVR_ERROR_NO_ERROR if the hook was called successfully. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// PVR_ERROR CMyPVRClient::CallSettingsMenuHook(const kodi::addon::PVRMenuhook& menuhook) + /// { + /// if (menuhook.GetHookId() == 2) + /// kodi::QueueNotification(QUEUE_INFO, "", kodi::GetLocalizedString(menuhook.GetLocalizedStringId())); + /// return PVR_ERROR_NO_ERROR; + /// } + /// ~~~~~~~~~~~~~ + /// + virtual PVR_ERROR CallSettingsMenuHook(const kodi::addon::PVRMenuhook& menuhook) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief **Callback to Kodi Function**\nAdd or replace a menu hook for the context menu for this add-on + /// + /// This is a callback function, called from addon to give Kodi his context menu's. + /// + /// @param[in] menuhook The with @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook defined hook to add + /// + /// @remarks Only called from addon itself + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Here's an example of the use of it:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// ... + /// + /// { + /// kodi::addon::PVRMenuhook hook; + /// hook.SetHookId(1); + /// hook.SetCategory(PVR_MENUHOOK_CHANNEL); + /// hook.SetLocalizedStringId(30000); + /// AddMenuHook(hook); + /// } + /// + /// { + /// kodi::addon::PVRMenuhook hook; + /// hook.SetHookId(2); + /// hook.SetCategory(PVR_MENUHOOK_SETTING); + /// hook.SetLocalizedStringId(30001); + /// AddMenuHook(hook); + /// } + /// ... + /// ~~~~~~~~~~~~~ + /// + /// **Here another way:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// ... + /// + /// AddMenuHook(kodi::addon::PVRMenuhook(1, 30000, PVR_MENUHOOK_CHANNEL)); + /// AddMenuHook(kodi::addon::PVRMenuhook(2, 30001, PVR_MENUHOOK_SETTING)); + /// ... + /// ~~~~~~~~~~~~~ + /// + inline void AddMenuHook(const kodi::addon::PVRMenuhook& hook) + { + m_instanceData->toKodi->AddMenuHook(m_instanceData->toKodi->kodiInstance, hook); + } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief **Callback to Kodi Function**\n + /// Notify a state change for a PVR backend connection. + /// + /// @param[in] connectionString The connection string reported by the backend + /// that can be displayed in the UI. + /// @param[in] newState The by @ref PVR_CONNECTION_STATE defined new state. + /// @param[in] message A localized addon-defined string representing the new + /// state, that can be displayed in the UI or **empty** if + /// the Kodi-defined default string for the new state + /// shall be displayed. + /// + /// @remarks Only called from addon itself + /// + /// + /// -------------------------------------------------------------------------- + /// + /// + /// **Here's an example of the use of it:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// #include /* for kodi::GetLocalizedString(...) */ + /// ... + /// + /// ConnectionStateChange("PVR demo connection lost", PVR_CONNECTION_STATE_DISCONNECTED, kodi::GetLocalizedString(30005, "Lost connection to Server");); + /// ... + /// ~~~~~~~~~~~~~ + /// + inline void ConnectionStateChange(const std::string& connectionString, + PVR_CONNECTION_STATE newState, + const std::string& message) + { + m_instanceData->toKodi->ConnectionStateChange( + m_instanceData->toKodi->kodiInstance, connectionString.c_str(), newState, message.c_str()); + } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief **Callback to Kodi Function**\n + /// Get user data path of the PVR addon. + /// + /// @return Path of current Kodi user + /// + /// @remarks Only called from addon itself + /// + /// @note Alternatively, @ref kodi::GetAddonPath() can be used for this. + /// + inline std::string UserPath() const { return m_instanceData->props->strUserPath; } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief **Callback to Kodi Function**\n + /// Get main client path of the PVR addon. + /// + /// @return Path of addon client + /// + /// @remarks Only called from addon itself. + /// + /// @note Alternatively, @ref kodi::GetBaseUserPath() can be used for this. + /// + inline std::string ClientPath() const { return m_instanceData->props->strClientPath; } + //---------------------------------------------------------------------------- + + ///@} + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Channels 2. Channels (required) + /// @ingroup cpp_kodi_addon_pvr + /// @brief **Functions to get available TV or Radio channels**\n + /// These are mandatory functions for using this addon to get the available + /// channels. + /// + /// @remarks Either @ref PVRCapabilities::SetSupportsTV "SetSupportsTV()" or + /// @ref PVRCapabilities::SetSupportsRadio "SetSupportsRadio()" is required to + /// be set to `true`.\n + /// If a channel changes after the initial import, or if a new one was added, + /// then the add-on should call @ref TriggerChannelUpdate(). + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Channel parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_pvr_Channels_header_addon_auto_check + /// @copydetails cpp_kodi_addon_pvr_Channels_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief The total amount of channels on the backend + /// + /// @param[out] amount The total amount of channels on the backend + /// @return @ref PVR_ERROR_NO_ERROR if the amount has been fetched successfully. + /// + /// @remarks Valid implementation required. + /// + virtual PVR_ERROR GetChannelsAmount(int& amount) { return PVR_ERROR_NOT_IMPLEMENTED; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Request the list of all channels from the backend. + /// + /// @param[in] radio True to get the radio channels, false to get the TV channels. + /// @param[out] results The channels defined with @ref cpp_kodi_addon_pvr_Defs_Channel_PVRChannel + /// and available at the addon, them transferred with + /// @ref cpp_kodi_addon_pvr_Defs_Channel_PVRChannelsResultSet. + /// @return @ref PVR_ERROR_NO_ERROR if the list has been fetched successfully. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRChannel_Help + /// + /// + /// -------------------------------------------------------------------------- + /// + /// @remarks + /// If @ref PVRCapabilities::SetSupportsTV() is set to + /// `true`, a valid result set needs to be provided for `radio = false`.\n + /// If @ref PVRCapabilities::SetSupportsRadio() is set to + /// `true`, a valid result set needs to be provided for `radio = true`. + /// At least one of these two must provide a valid result set. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// PVR_ERROR CMyPVRInstance::GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& results) + /// { + /// // Minimal demo example, in reality bigger and loop to transfer all + /// kodi::addon::PVRChannel channel; + /// channel.SetUniqueId(123); + /// channel.SetIsRadio(false); + /// channel.SetChannelNumber(1); + /// channel.SetChannelName("My channel name"); + /// ... + /// + /// // Give it now to Kodi + /// results.Add(channel); + /// return PVR_ERROR_NO_ERROR; + /// } + /// ... + /// ~~~~~~~~~~~~~ + /// + virtual PVR_ERROR GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& results) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the stream properties for a channel from the backend. + /// + /// @param[in] channel The channel to get the stream properties for. + /// @param[out] properties the properties required to play the stream. + /// @return @ref PVR_ERROR_NO_ERROR if the stream is available. + /// + /// @remarks If @ref PVRCapabilities::SetSupportsTV "SetSupportsTV" or + /// @ref PVRCapabilities::SetSupportsRadio "SetSupportsRadio" are set to true + /// and @ref PVRCapabilities::SetHandlesInputStream "SetHandlesInputStream" is + /// set to false.\n\n + /// In this case the implementation must fill the property @ref PVR_STREAM_PROPERTY_STREAMURL + /// with the URL Kodi should resolve to playback the channel. + /// + /// @note The value directly related to inputstream must always begin with the + /// name of the associated add-on, e.g. `"inputstream.adaptive.manifest_update_parameter"`. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// PVR_ERROR CMyPVRInstance::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, + /// std::vector& properties) + /// { + /// ... + /// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM, "inputstream.adaptive"); + /// properties.emplace_back("inputstream.adaptive.manifest_type", "mpd"); + /// properties.emplace_back("inputstream.adaptive.manifest_update_parameter", "full"); + /// properties.emplace_back(PVR_STREAM_PROPERTY_MIMETYPE, "application/xml+dash"); + /// return PVR_ERROR_NO_ERROR; + /// } + /// ... + /// ~~~~~~~~~~~~~ + /// + virtual PVR_ERROR GetChannelStreamProperties( + const kodi::addon::PVRChannel& channel, + std::vector& properties) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the signal status of the stream that's currently open. + /// + /// @param[out] signalStatus The signal status. + /// @return @ref PVR_ERROR_NO_ERROR if the signal status has been read successfully, false otherwise. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetHandlesInputStream "SetHandlesInputStream" + /// is set to true. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus_Help + /// + /// + /// -------------------------------------------------------------------------- + /// + /// + /// **Here's example about the use of this:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// ... + /// + /// class ATTRIBUTE_HIDDEN CPVRExample + /// : public kodi::addon::CAddonBase, + /// public kodi::addon::CInstancePVRClient + /// { + /// public: + /// ... + /// PVR_ERROR SignalStatus(PVRSignalStatus &signalStatus) override + /// { + /// signalStatus.SetAapterName("Example adapter 1"); + /// signalStatus.SetAdapterStatus("OK"); + /// signalStatus.SetSignal(0xFFFF); // 100% + /// + /// return PVR_ERROR_NO_ERROR; + /// } + /// }; + /// + /// ADDONCREATOR(CPVRExample) + /// ~~~~~~~~~~~~~ + /// + virtual PVR_ERROR GetSignalStatus(int channelUid, kodi::addon::PVRSignalStatus& signalStatus) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the descramble information of the stream that's currently open. + /// + /// @param[out] descrambleInfo The descramble information. + /// @return @ref PVR_ERROR_NO_ERROR if the descramble information has been + /// read successfully, false otherwise. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsDescrambleInfo "supportsDescrambleInfo" + /// is set to true. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo_Help + /// + virtual PVR_ERROR GetDescrambleInfo(int channelUid, + kodi::addon::PVRDescrambleInfo& descrambleInfo) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// Request Kodi to update it's list of channels. + /// + /// @remarks Only called from addon itself. + /// + inline void TriggerChannelUpdate() + { + m_instanceData->toKodi->TriggerChannelUpdate(m_instanceData->toKodi->kodiInstance); + } + //---------------------------------------------------------------------------- + + ///@} + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_supportsChannelGroups 3. Channel Groups (optional) + /// @ingroup cpp_kodi_addon_pvr + /// @brief Bring in this functions if you have set @ref PVRCapabilities::SetSupportsChannelGroups "supportsChannelGroups" + /// to true\n + /// This is used to divide available addon channels into groups, which can + /// then be selected by the user. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Channel group parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_pvr_supportsChannelGroups_header_addon_auto_check + /// @copydetails cpp_kodi_addon_pvr_supportsChannelGroups_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Get the total amount of channel groups on the backend if it supports channel groups. + /// + /// @param[out] amount The total amount of channel groups on the backend + /// @return @ref PVR_ERROR_NO_ERROR if the amount has been fetched successfully. + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelGroups "supportsChannelGroups" is set to true. + /// + virtual PVR_ERROR GetChannelGroupsAmount(int& amount) { return PVR_ERROR_NOT_IMPLEMENTED; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get a list of available channel groups on addon + /// + /// Request the list of all channel groups from the backend if it supports + /// channel groups. + /// + /// @param[in] radio True to get the radio channel groups, false to get the + /// TV channel groups. + /// @param[out] results List of available groups on addon defined with + /// @ref cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup, + /// them transferred with + /// @ref cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupsResultSet. + /// @return @ref PVR_ERROR_NO_ERROR if the list has been fetched successfully. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup_Help + /// + /// + /// -------------------------------------------------------------------------- + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelGroups "supportsChannelGroups" + /// is set to true. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// PVR_ERROR CMyPVRInstance::GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResultSet& groups) + /// { + /// kodi::addon::PVRChannelGroup group; + /// group.SetIsRadio(false); + /// group.SetGroupName("My group name"); + /// group.SetPosition(1); + /// ... + /// + /// // Give it now to Kodi + /// results.Add(group); + /// return PVR_ERROR_NO_ERROR; + /// } + /// ... + /// ~~~~~~~~~~~~~ + /// + virtual PVR_ERROR GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResultSet& results) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get a list of members on a group + /// + /// Request the list of all group members of a group from the backend if it + /// supports channel groups. + /// + /// @param[in] group The group to get the members for. + /// @param[out] results List of available group member channels defined with + /// @ref cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember, + /// them transferred with + /// @ref PVRChannelGroupMembersResultSet. + /// @return @ref PVR_ERROR_NO_ERROR if the list has been fetched successfully. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember_Help + /// + /// -------------------------------------------------------------------------- + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelGroups "supportsChannelGroups" + /// is set to true. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// PVR_ERROR CMyPVRInstance::GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& group, + /// kodi::addon::PVRChannelGroupMembersResultSet& results) + /// { + /// for (const auto& myGroup : m_myGroups) + /// { + /// if (myGroup.strGroupName == group.GetGroupName()) + /// { + /// for (unsigned int iChannelPtr = 0; iChannelPtr < myGroup.members.size(); iChannelPtr++) + /// { + /// int iId = myGroup.members.at(iChannelPtr) - 1; + /// if (iId < 0 || iId > (int)m_channels.size() - 1) + /// continue; + /// + /// PVRDemoChannel &channel = m_channels.at(iId); + /// kodi::addon::PVRChannelGroupMember kodiGroupMember; + /// kodiGroupMember.SetGroupName(group.GetGroupName()); + /// kodiGroupMember.SetChannelUniqueId(channel.iUniqueId); + /// kodiGroupMember.SetChannelNumber(channel.iChannelNumber); + /// kodiGroupMember.SetSubChannelNumber(channel.iSubChannelNumber); + /// + /// results.Add(kodiGroupMember); + /// } + /// } + /// } + /// return PVR_ERROR_NO_ERROR; + /// } + /// ... + /// ~~~~~~~~~~~~~ + /// + virtual PVR_ERROR GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& group, + kodi::addon::PVRChannelGroupMembersResultSet& results) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// Request Kodi to update it's list of channel groups. + /// + /// @remarks Only called from addon itself + /// + inline void TriggerChannelGroupsUpdate() + { + m_instanceData->toKodi->TriggerChannelGroupsUpdate(m_instanceData->toKodi->kodiInstance); + } + //---------------------------------------------------------------------------- + + ///@} + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_supportsChannelEdit 4. Channel edit (optional) + /// @ingroup cpp_kodi_addon_pvr + /// @brief Bring in this functions if you have set @ref PVRCapabilities::SetSupportsChannelSettings "supportsChannelSettings" + /// to true or for @ref OpenDialogChannelScan() set @ref PVRCapabilities::SetSupportsChannelScan "supportsChannelScan" + /// to true\n + /// The support of this is a pure option and not mandatory. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Channel edit parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_pvr_supportsChannelEdit_header_addon_auto_check + /// @copydetails cpp_kodi_addon_pvr_supportsChannelEdit_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Delete a channel from the backend. + /// + /// @param[in] channel The channel to delete. + /// @return @ref PVR_ERROR_NO_ERROR if the channel has been deleted successfully. + /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelSettings "supportsChannelSettings" + /// is set to true. + /// + virtual PVR_ERROR DeleteChannel(const kodi::addon::PVRChannel& channel) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief Rename a channel on the backend. + /// + /// @param[in] channel The channel to rename, containing the new channel name. + /// @return @ref PVR_ERROR_NO_ERROR if the channel has been renamed successfully. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRChannel_Help + /// + /// + /// -------------------------------------------------------------------------- + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsChannelSettings "supportsChannelSettings" + /// is set to true. + /// + virtual PVR_ERROR RenameChannel(const kodi::addon::PVRChannel& channel) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief Show the channel settings dialog, if supported by the backend. + /// + /// @param[in] channel The channel to show the dialog for. + /// @return @ref PVR_ERROR_NO_ERROR if the dialog has been displayed successfully. + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelSettings "supportsChannelSettings" is set to true. + /// @note Use @ref cpp_kodi_gui_CWindow "kodi::gui::CWindow" to create dialog for them. + /// + virtual PVR_ERROR OpenDialogChannelSettings(const kodi::addon::PVRChannel& channel) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief Show the dialog to add a channel on the backend, if supported by the backend. + /// + /// @param[in] channel The channel to add. + /// @return @ref PVR_ERROR_NO_ERROR if the channel has been added successfully. + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelSettings "supportsChannelSettings" is set to true. + /// @note Use @ref cpp_kodi_gui_CWindow "kodi::gui::CWindow" to create dialog for them. + /// + virtual PVR_ERROR OpenDialogChannelAdd(const kodi::addon::PVRChannel& channel) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief Show the channel scan dialog if this backend supports it. + /// + /// @return @ref PVR_ERROR_NO_ERROR if the dialog was displayed successfully. + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsChannelScan "supportsChannelScan" is set to true. + /// @note Use @ref cpp_kodi_gui_CWindow "kodi::gui::CWindow" to create dialog for them. + /// + virtual PVR_ERROR OpenDialogChannelScan() { return PVR_ERROR_NOT_IMPLEMENTED; } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief Call one of the channel related menu hooks (if supported). + /// + /// Supported @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook instances have to be added in + /// `constructor()`, by calling @ref AddMenuHook() on the callback. + /// + /// @param[in] menuhook The hook to call. + /// @param[in] item The selected channel item for which the hook was called. + /// @return @ref PVR_ERROR_NO_ERROR if the hook was called successfully. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help + /// + virtual PVR_ERROR CallChannelMenuHook(const kodi::addon::PVRMenuhook& menuhook, + const kodi::addon::PVRChannel& item) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + ///@} + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_EPGTag 4. EPG methods (optional) + /// @ingroup cpp_kodi_addon_pvr + /// @brief **PVR EPG methods**\n + /// These C ++ class functions of are intended for processing EPG information + /// and for giving it to Kodi. + /// + /// The necessary data is transferred with @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag. + /// + /// @remarks Only used by Kodi if @ref PVRCapabilities::SetSupportsEPG "supportsEPG" + /// is set to true.\n\n + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **EPG parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_pvr_EPGTag_header_addon_auto_check + /// @copydetails cpp_kodi_addon_pvr_EPGTag_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Request the EPG for a channel from the backend. + /// + /// @param[in] channelUid The UID of the channel to get the EPG table for. + /// @param[in] start Get events after this time (UTC). + /// @param[in] end Get events before this time (UTC). + /// @param[out] results List where available EPG information becomes + /// transferred with @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag + /// and given to Kodi + /// @return @ref PVR_ERROR_NO_ERROR if the table has been fetched successfully. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_epg_PVREPGTag_Help + /// + /// + /// -------------------------------------------------------------------------- + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsEPG "supportsEPG" is set to true. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// PVR_ERROR CMyPVRInstance::GetEPGForChannel(int channelUid, + /// time_t start, + /// time_t end, + /// kodi::addon::PVREPGTagsResultSet& results) + /// { + /// // Minimal demo example, in reality bigger, loop to transfer all and to + /// // match wanted times. + /// kodi::addon::PVREPGTag tag; + /// tag.SetUniqueBroadcastId(123); + /// tag.SetUniqueChannelId(123); + /// tag.SetTitle("My epg entry name"); + /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MOVIEDRAMA); + /// tag.SetStartTime(1589148283); // Seconds elapsed since 00:00 hours, Jan 1, 1970 UTC + /// tag.SetEndTime(1589151913); + /// ... + /// + /// // Give it now to Kodi + /// results.Add(tag); + /// return PVR_ERROR_NO_ERROR; + /// } + /// ... + /// ~~~~~~~~~~~~~ + /// + virtual PVR_ERROR GetEPGForChannel(int channelUid, + time_t start, + time_t end, + kodi::addon::PVREPGTagsResultSet& results) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Check if the given EPG tag can be recorded. + /// + /// @param[in] tag the @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "epg tag" to check. + /// @param[out] isRecordable Set to true if the tag can be recorded. + /// @return @ref PVR_ERROR_NO_ERROR if bIsRecordable has been set successfully. + /// + /// @remarks Optional, it return @ref PVR_ERROR_NOT_IMPLEMENTED by parent to let Kodi decide. + /// + virtual PVR_ERROR IsEPGTagRecordable(const kodi::addon::PVREPGTag& tag, bool& isRecordable) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Check if the given EPG tag can be played. + /// + /// @param[in] tag the @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "epg tag" to check. + /// @param[out] isPlayable Set to true if the tag can be played. + /// @return @ref PVR_ERROR_NO_ERROR if bIsPlayable has been set successfully. + /// + /// @remarks Required if add-on supports playing epg tags. + /// + virtual PVR_ERROR IsEPGTagPlayable(const kodi::addon::PVREPGTag& tag, bool& isPlayable) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Retrieve the edit decision list (EDL) of an EPG tag on the backend. + /// + /// @param[in] tag The @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "epg tag". + /// @param[out] edl The function has to write the EDL into this array. + /// @return @ref PVR_ERROR_NO_ERROR if the EDL was successfully read or no EDL exists. + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsEPGEdl "supportsEPGEdl" is set to true. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry_Help + /// + /// + /// -------------------------------------------------------------------------- + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsEPGEdl "supportsEPGEdl" is set to true. + /// + virtual PVR_ERROR GetEPGTagEdl(const kodi::addon::PVREPGTag& tag, + std::vector& edl) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the stream properties for an epg tag from the backend. + /// + /// @param[in] tag The @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "epg tag" to get the stream properties for. + /// @param[out] properties the properties required to play the stream. + /// @return @ref PVR_ERROR_NO_ERROR if the stream is available. + /// + /// @remarks Required if add-on supports playing epg tags. + /// In this case your implementation must fill the property @ref PVR_STREAM_PROPERTY_STREAMURL + /// with the URL Kodi should resolve to playback the epg tag. + /// It return @ref PVR_ERROR_NOT_IMPLEMENTED from parent if this add-on won't provide this function. + /// + /// @note The value directly related to inputstream must always begin with the + /// name of the associated add-on, e.g. `"inputstream.adaptive.manifest_update_parameter"`. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// PVR_ERROR CMyPVRInstance::GetEPGTagStreamProperties(const kodi::addon::PVREPGTag& tag, + /// std::vector& properties) + /// { + /// ... + /// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM, "inputstream.adaptive"); + /// properties.emplace_back("inputstream.adaptive.manifest_type", "mpd"); + /// properties.emplace_back("inputstream.adaptive.manifest_update_parameter", "full"); + /// properties.emplace_back(PVR_STREAM_PROPERTY_MIMETYPE, "application/xml+dash"); + /// return PVR_ERROR_NO_ERROR; + /// } + /// ... + /// ~~~~~~~~~~~~~ + /// + virtual PVR_ERROR GetEPGTagStreamProperties( + const kodi::addon::PVREPGTag& tag, std::vector& properties) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Tell the client the time frame to use when notifying epg events back to Kodi + /// + /// The client might push epg events asynchronously to Kodi using the callback function + /// @ref EpgEventStateChange. To be able to only push events that are actually of + /// interest for Kodi, client needs to know about the epg time frame Kodi uses. Kodi + /// supplies the current epg time frame value in @ref EpgMaxDays() when creating the + /// addon and calls @ref SetEPGTimeFrame later whenever Kodi's epg time frame value + /// changes. + /// + /// @param[in] days number of days from "now". @ref EPG_TIMEFRAME_UNLIMITED means that Kodi + /// is interested in all epg events, regardless of event times. + /// @return @ref PVR_ERROR_NO_ERROR if new value was successfully set. + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsEPG "supportsEPG" is set to true. + /// + virtual PVR_ERROR SetEPGTimeFrame(int days) { return PVR_ERROR_NOT_IMPLEMENTED; } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief Call one of the EPG related menu hooks (if supported). + /// + /// Supported @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook instances have to be added in + /// `constructor()`, by calling @ref AddMenuHook() on the callback. + /// + /// @param[in] menuhook The hook to call. + /// @param[in] tag The selected EPG item for which the hook was called. + /// @return @ref PVR_ERROR_NO_ERROR if the hook was called successfully. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help + /// + virtual PVR_ERROR CallEPGMenuHook(const kodi::addon::PVRMenuhook& menuhook, + const kodi::addon::PVREPGTag& tag) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief **Callback to Kodi Function**\n + /// Get the Max days handled by Kodi. + /// + /// If > @ref EPG_TIMEFRAME_UNLIMITED, in async epg mode, deliver only events + /// in the range from 'end time > now' to 'start time < now + EpgMaxDays(). + /// @ref EPG_TIMEFRAME_UNLIMITED, notify all events. + /// + /// @return The Max days handled by Kodi + /// + inline int EpgMaxDays() const { return m_instanceData->props->iEpgMaxDays; } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief **Callback to Kodi Function**\n + /// Schedule an EPG update for the given channel channel. + /// + /// @param[in] channelUid The unique id of the channel for this add-on + /// + /// @remarks Only called from addon itself + /// + inline void TriggerEpgUpdate(unsigned int channelUid) + { + m_instanceData->toKodi->TriggerEpgUpdate(m_instanceData->toKodi->kodiInstance, channelUid); + } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief **Callback to Kodi Function**\n + /// Notify a state change for an EPG event. + /// + /// @param[in] tag The @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "EPG tag" where have event. + /// @param[in] newState The new state. + /// - For @ref EPG_EVENT_CREATED and @ref EPG_EVENT_UPDATED, tag must be filled with all available event data, not just a delta. + /// - For @ref EPG_EVENT_DELETED, it is sufficient to fill @ref kodi::addon::PVREPGTag::SetUniqueBroadcastId + /// + /// @remarks Only called from addon itself, + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// + /// void CMyPVRInstance::MyProcessFunction() + /// { + /// ... + /// kodi::addon::PVREPGTag tag; // Here as mini add, in real it should be a complete tag + /// tag.SetUniqueId(123); + /// + /// // added namespace here not needed to have, only to have more clear for where is + /// kodi::addon::CInstancePVRClient::EpgEventStateChange(tag, EPG_EVENT_UPDATED); + /// ... + /// } + /// + /// ... + /// ~~~~~~~~~~~~~ + /// + inline void EpgEventStateChange(kodi::addon::PVREPGTag& tag, EPG_EVENT_STATE newState) + { + m_instanceData->toKodi->EpgEventStateChange(m_instanceData->toKodi->kodiInstance, tag.GetTag(), + newState); + } + //---------------------------------------------------------------------------- + + ///@} + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Recordings 5. Recordings (optional) + /// @ingroup cpp_kodi_addon_pvr + /// @brief **PVR recording methods**\n + /// To transfer available recordings of the PVR backend and to allow possible + /// playback. + /// + /// @remarks Only used by Kodi if @ref PVRCapabilities::SetSupportsRecordings "supportsRecordings" + /// is set to true.\n\n + /// If a recordings changes after the initial import, or if a new one was added, + /// then the add-on should call @ref TriggerRecordingUpdate(). + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Recordings parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_pvr_Recordings_header_addon_auto_check + /// @copydetails cpp_kodi_addon_pvr_Recordings_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief To get amount of recording present on backend + /// + /// @param[in] deleted if set return deleted recording (called if + /// @ref PVRCapabilities::SetSupportsRecordingsUndelete "supportsRecordingsUndelete" + /// set to true) + /// @param[out] amount The total amount of recordings on the backend + /// @return @ref PVR_ERROR_NO_ERROR if the amount has been fetched successfully. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings "supportsRecordings" is set to true. + /// + virtual PVR_ERROR GetRecordingsAmount(bool deleted, int& amount) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Request the list of all recordings from the backend, if supported. + /// + /// Recording entries are added to Kodi by calling TransferRecordingEntry() on the callback. + /// + /// @param[in] deleted if set return deleted recording (called if + /// @ref PVRCapabilities::SetSupportsRecordingsUndelete "supportsRecordingsUndelete" + /// set to true) + /// @param[out] results List of available recordings with @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording + /// becomes transferred with @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecordingsResultSet + /// and given to Kodi + /// @return @ref PVR_ERROR_NO_ERROR if the recordings have been fetched successfully. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings "supportsRecordings" + /// is set to true. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Recording_PVRRecording_Help + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// PVR_ERROR CMyPVRInstance::GetRecordings(bool deleted, kodi::addon::PVRRecordingsResultSet& results) + /// { + /// // Minimal demo example, in reality bigger and loop to transfer all + /// kodi::addon::PVRRecording recording; + /// recording.SetRecordingId(123); + /// recording.SetTitle("My recording name"); + /// ... + /// + /// // Give it now to Kodi + /// results.Add(recording); + /// return PVR_ERROR_NO_ERROR; + /// } + /// ... + /// ~~~~~~~~~~~~~ + /// + virtual PVR_ERROR GetRecordings(bool deleted, kodi::addon::PVRRecordingsResultSet& results) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Delete a recording on the backend. + /// + /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording to delete. + /// @return @ref PVR_ERROR_NO_ERROR if the recording has been deleted successfully. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings "supportsRecordings" + /// is set to true. + /// + virtual PVR_ERROR DeleteRecording(const kodi::addon::PVRRecording& recording) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Undelete a recording on the backend. + /// + /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording to undelete. + /// @return @ref PVR_ERROR_NO_ERROR if the recording has been undeleted successfully. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordingsUndelete "supportsRecordingsUndelete" + /// is set to true. + /// + virtual PVR_ERROR UndeleteRecording(const kodi::addon::PVRRecording& recording) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Delete all recordings permanent which in the deleted folder on the backend. + /// + /// @return @ref PVR_ERROR_NO_ERROR if the recordings has been deleted successfully. + /// + virtual PVR_ERROR DeleteAllRecordingsFromTrash() { return PVR_ERROR_NOT_IMPLEMENTED; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Rename a recording on the backend. + /// + /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording + /// to rename, containing the new name. + /// @return @ref PVR_ERROR_NO_ERROR if the recording has been renamed successfully. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings "supportsRecordings" + /// is set to true. + /// + virtual PVR_ERROR RenameRecording(const kodi::addon::PVRRecording& recording) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Set the lifetime of a recording on the backend. + /// + /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording + /// to change the lifetime for. recording.iLifetime + /// contains the new lieftime value. + /// @return @ref PVR_ERROR_NO_ERROR if the recording's lifetime has been set + /// successfully. + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsRecordingsLifetimeChange "supportsRecordingsLifetimeChange" + /// is set to true. + /// + virtual PVR_ERROR SetRecordingLifetime(const kodi::addon::PVRRecording& recording) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Set the play count of a recording on the backend. + /// + /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording + /// to change the play count. + /// @param[in] count Play count. + /// @return @ref PVR_ERROR_NO_ERROR if the recording's play count has been set + /// successfully. + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsRecordingPlayCount "supportsRecordingPlayCount" + /// is set to true. + /// + virtual PVR_ERROR SetRecordingPlayCount(const kodi::addon::PVRRecording& recording, int count) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Set the last watched position of a recording on the backend. + /// + /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording. + /// @param[in] lastplayedposition The last watched position in seconds + /// @return @ref PVR_ERROR_NO_ERROR if the position has been stored successfully. + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsLastPlayedPosition "supportsLastPlayedPosition" + /// is set to true. + /// + virtual PVR_ERROR SetRecordingLastPlayedPosition(const kodi::addon::PVRRecording& recording, + int lastplayedposition) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Retrieve the last watched position of a recording on the backend. + /// + /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording. + /// @param[out] position The last watched position in seconds + /// @return @ref PVR_ERROR_NO_ERROR if the amount has been fetched successfully. + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsRecordingPlayCount "supportsRecordingPlayCount" + /// is set to true. + /// + virtual PVR_ERROR GetRecordingLastPlayedPosition(const kodi::addon::PVRRecording& recording, + int& position) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Retrieve the edit decision list (EDL) of a recording on the backend. + /// + /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording. + /// @param[out] edl The function has to write the EDL into this array. + /// @return @ref PVR_ERROR_NO_ERROR if the EDL was successfully read or no EDL exists. + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsRecordingEdl "supportsRecordingEdl" + /// is set to true. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry_Help + /// + virtual PVR_ERROR GetRecordingEdl(const kodi::addon::PVRRecording& recording, + std::vector& edl) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Retrieve the size of a recording on the backend. + /// + /// @param[in] recording The recording to get the size in bytes for. + /// @param[out] size The size in bytes of the recording + /// @return @ref PVR_ERROR_NO_ERROR if the recording's size has been set successfully. + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsRecordingSize "supportsRecordingSize" + /// is set to true. + /// + virtual PVR_ERROR GetRecordingSize(const kodi::addon::PVRRecording& recording, int64_t& size) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the stream properties for a recording from the backend. + /// + /// @param[in] recording The @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording + /// to get the stream properties for. + /// @param[out] properties The properties required to play the stream. + /// @return @ref PVR_ERROR_NO_ERROR if the stream is available. + /// + /// @remarks Required if @ref PVRCapabilities::SetSupportsRecordings "supportsRecordings" + /// is set to true and the add-on does not implement recording stream functions + /// (@ref OpenRecordedStream, ...).\n + /// In this case your implementation must fill the property @ref PVR_STREAM_PROPERTY_STREAMURL + /// with the URL Kodi should resolve to playback the recording. + /// + /// @note The value directly related to inputstream must always begin with the + /// name of the associated add-on, e.g. `"inputstream.adaptive.manifest_update_parameter"`. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// PVR_ERROR CMyPVRInstance::GetRecordingStreamProperties(const kodi::addon::PVRRecording& recording, + /// std::vector& properties) + /// { + /// ... + /// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM, "inputstream.adaptive"); + /// properties.emplace_back("inputstream.adaptive.manifest_type", "mpd"); + /// properties.emplace_back("inputstream.adaptive.manifest_update_parameter", "full"); + /// properties.emplace_back(PVR_STREAM_PROPERTY_MIMETYPE, "application/xml+dash"); + /// return PVR_ERROR_NO_ERROR; + /// } + /// ... + /// ~~~~~~~~~~~~~ + /// + virtual PVR_ERROR GetRecordingStreamProperties( + const kodi::addon::PVRRecording& recording, + std::vector& properties) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @brief Call one of the recording related menu hooks (if supported). + /// + /// Supported @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook instances have to be added in + /// `constructor()`, by calling @ref AddMenuHook() on the callback. + /// + /// @param[in] menuhook The hook to call. + /// @param[in] item The selected recording item for which the hook was called. + /// @return @ref PVR_ERROR_NO_ERROR if the hook was called successfully. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help + /// + virtual PVR_ERROR CallRecordingMenuHook(const kodi::addon::PVRMenuhook& menuhook, + const kodi::addon::PVRRecording& item) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// Display a notification in Kodi that a recording started or stopped on the + /// server. + /// + /// @param[in] recordingName The name of the recording to display + /// @param[in] fileName The filename of the recording + /// @param[in] on True when recording started, false when it stopped + /// + /// @remarks Only called from addon itself + /// + inline void RecordingNotification(const std::string& recordingName, + const std::string& fileName, + bool on) + { + m_instanceData->toKodi->RecordingNotification(m_instanceData->toKodi->kodiInstance, + recordingName.c_str(), fileName.c_str(), on); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// Request Kodi to update it's list of recordings. + /// + /// @remarks Only called from addon itself + /// + inline void TriggerRecordingUpdate() + { + m_instanceData->toKodi->TriggerRecordingUpdate(m_instanceData->toKodi->kodiInstance); + } + //---------------------------------------------------------------------------- + + ///@} + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Timers 6. Timers (optional) + /// @ingroup cpp_kodi_addon_pvr + /// @brief **PVR timer methods**\n + /// For editing and displaying timed work, such as video recording. + /// + /// @remarks Only used by Kodi if @ref PVRCapabilities::SetSupportsTimers "supportsTimers" + /// is set to true.\n\n + /// If a timer changes after the initial import, or if a new one was added, + /// then the add-on should call @ref TriggerTimerUpdate(). + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Timer parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_pvr_Timers_header_addon_auto_check + /// @copydetails cpp_kodi_addon_pvr_Timers_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Retrieve the timer types supported by the backend. + /// + /// @param[out] types The function has to write the definition of the + /// @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType types + /// into this array. + /// @return @ref PVR_ERROR_NO_ERROR if the types were successfully written to + /// the array. + /// + /// @note Maximal 32 entries are allowed inside. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType_Help + /// + virtual PVR_ERROR GetTimerTypes(std::vector& types) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief To get total amount of timers on the backend or -1 on error. + /// + /// @param[out] amount The total amount of timers on the backend + /// @return @ref PVR_ERROR_NO_ERROR if the amount has been fetched successfully. + /// + /// @note Required to use if @ref PVRCapabilities::SetSupportsTimers "supportsTimers" + /// is set to true. + /// + virtual PVR_ERROR GetTimersAmount(int& amount) { return PVR_ERROR_NOT_IMPLEMENTED; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Request the list of all timers from the backend if supported. + /// + /// @param[out] results List of available timers with @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimer + /// becomes transferred with @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimersResultSet + /// and given to Kodi + /// @return @ref PVR_ERROR_NO_ERROR if the list has been fetched successfully. + /// + /// @note Required to use if @ref PVRCapabilities::SetSupportsTimers "supportsTimers" + /// is set to true. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Timer_PVRTimer_Help + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// PVR_ERROR CMyPVRInstance::GetTimers(kodi::addon::PVRTimersResultSet& results) + /// { + /// // Minimal demo example, in reality bigger and loop to transfer all + /// kodi::addon::PVRTimer timer; + /// timer.SetClientIndex(123); + /// timer.SetState(PVR_TIMER_STATE_SCHEDULED); + /// timer.SetTitle("My timer name"); + /// ... + /// + /// // Give it now to Kodi + /// results.Add(timer); + /// return PVR_ERROR_NO_ERROR; + /// } + /// ... + /// ~~~~~~~~~~~~~ + /// + virtual PVR_ERROR GetTimers(kodi::addon::PVRTimersResultSet& results) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Add a timer on the backend. + /// + /// @param[in] timer The timer to add. + /// @return @ref PVR_ERROR_NO_ERROR if the timer has been added successfully. + /// + /// @note Required to use if @ref PVRCapabilities::SetSupportsTimers "supportsTimers" + /// is set to true. + /// + virtual PVR_ERROR AddTimer(const kodi::addon::PVRTimer& timer) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Delete a timer on the backend. + /// + /// @param[in] timer The timer to delete. + /// @param[in] forceDelete Set to true to delete a timer that is currently + /// recording a program. + /// @return @ref PVR_ERROR_NO_ERROR if the timer has been deleted successfully. + /// + /// @note Required to use if @ref PVRCapabilities::SetSupportsTimers "supportsTimers" + /// is set to true. + /// + virtual PVR_ERROR DeleteTimer(const kodi::addon::PVRTimer& timer, bool forceDelete) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Update the timer information on the backend. + /// + /// @param[in] timer The timer to update. + /// @return @ref PVR_ERROR_NO_ERROR if the timer has been updated successfully. + /// + /// @note Required to use if @ref PVRCapabilities::SetSupportsTimers "supportsTimers" + /// is set to true. + /// + virtual PVR_ERROR UpdateTimer(const kodi::addon::PVRTimer& timer) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Call one of the timer related menu hooks (if supported). + /// + /// Supported @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook instances have + /// to be added in `constructor()`, by calling @ref AddMenuHook() on the + /// callback. + /// + /// @param[in] menuhook The hook to call. + /// @param[in] item The selected timer item for which the hook was called. + /// @return @ref PVR_ERROR_NO_ERROR if the hook was called successfully. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help + /// + virtual PVR_ERROR CallTimerMenuHook(const kodi::addon::PVRMenuhook& menuhook, + const kodi::addon::PVRTimer& item) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// Request Kodi to update it's list of timers. + /// + /// @remarks Only called from addon itself + /// + inline void TriggerTimerUpdate() + { + m_instanceData->toKodi->TriggerTimerUpdate(m_instanceData->toKodi->kodiInstance); + } + //---------------------------------------------------------------------------- + + ///@} + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_PowerManagement 7. Power management events (optional) + /// @ingroup cpp_kodi_addon_pvr + /// @brief **Used to notify the pvr addon for power management events**\n + /// Used to allow any energy savings. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Power management events in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_pvr_PowerManagement_header_addon_auto_check + /// @copydetails cpp_kodi_addon_pvr_PowerManagement_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief To notify addon about system sleep + /// + /// @return @ref PVR_ERROR_NO_ERROR If successfully done. + /// + virtual PVR_ERROR OnSystemSleep() { return PVR_ERROR_NOT_IMPLEMENTED; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief To notify addon about system wake up + /// + /// @return @ref PVR_ERROR_NO_ERROR If successfully done. + /// + virtual PVR_ERROR OnSystemWake() { return PVR_ERROR_NOT_IMPLEMENTED; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief To notify addon power saving on system is activated + /// + /// @return @ref PVR_ERROR_NO_ERROR If successfully done. + /// + virtual PVR_ERROR OnPowerSavingActivated() { return PVR_ERROR_NOT_IMPLEMENTED; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief To notify addon power saving on system is deactivated + /// + /// @return @ref PVR_ERROR_NO_ERROR If successfully done. + /// + virtual PVR_ERROR OnPowerSavingDeactivated() { return PVR_ERROR_NOT_IMPLEMENTED; } + //---------------------------------------------------------------------------- + + ///@} + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Streams 8. Inputstream + /// @ingroup cpp_kodi_addon_pvr + /// @brief **PVR Inputstream**\n + /// This includes functions that are used in the PVR inputstream. + /// + /// @warning The parts here will be removed in the future and replaced by the + /// separate @ref cpp_kodi_addon_inputstream "inputstream addon instance". + /// If there is already a possibility, new addons should do it via the + /// inputstream instance. + /// + ///@{ + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Streams_TV 8.1. TV stream + /// @ingroup cpp_kodi_addon_pvr_Streams + /// @brief **PVR TV stream**\n + /// Stream processing regarding live TV. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **TV stream parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_pvr_Streams_TV_header_addon_auto_check + /// @copydetails cpp_kodi_addon_pvr_Streams_TV_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Open a live stream on the backend. + /// + /// @param[in] channel The channel to stream. + /// @return True if the stream has been opened successfully, false otherwise. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRChannel_Help + /// + /// + /// -------------------------------------------------------------------------- + /// + /// @remarks Required if @ref PVRCapabilities::SetHandlesInputStream() or + /// @ref PVRCapabilities::SetHandlesDemuxing() is set to true. + /// @ref CloseLiveStream() will always be called by Kodi prior to calling this + /// function. + /// + virtual bool OpenLiveStream(const kodi::addon::PVRChannel& channel) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Close an open live stream. + /// + /// @remarks Required if @ref PVRCapabilities::SetHandlesInputStream() or + /// @ref PVRCapabilities::SetHandlesDemuxing() is set to true. + /// + virtual void CloseLiveStream() {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Read from an open live stream. + /// + /// @param[in] pBuffer The buffer to store the data in. + /// @param[in] iBufferSize The amount of bytes to read. + /// @return The amount of bytes that were actually read from the stream. + /// + /// @remarks Required if @ref PVRCapabilities::SetHandlesInputStream() is set + /// to true. + /// + virtual int ReadLiveStream(unsigned char* buffer, unsigned int size) { return 0; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Seek in a live stream on a backend that supports timeshifting. + /// + /// @param[in] position The position to seek to. + /// @param[in] whence [optional] offset relative to + /// You can set the value of whence to one of three things: + /// | Value | int | Description | + /// |:--------:|:---:|:----------------------------------------------------| + /// | SEEK_SET | 0 | position is relative to the beginning of the file. This is probably what you had in mind anyway, and is the most commonly used value for whence. + /// | SEEK_CUR | 1 | position is relative to the current file pointer position. So, in effect, you can say, "Move to my current position plus 30 bytes," or, "move to my current position minus 20 bytes." + /// | SEEK_END | 2 | position is relative to the end of the file. Just like SEEK_SET except from the other end of the file. Be sure to use negative values for offset if you want to back up from the end of the file, instead of going past the end into oblivion. + /// + /// @return The new position. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetHandlesInputStream() + /// is set to true. + /// + virtual int64_t SeekLiveStream(int64_t position, int whence) { return 0; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Obtain the length of a live stream. + /// + /// @return The total length of the stream that's currently being read. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetHandlesInputStream() + /// is set to true. + /// + virtual int64_t LengthLiveStream() { return 0; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Streams_TV_Demux 8.1.1. Stream demuxing + /// @ingroup cpp_kodi_addon_pvr_Streams_TV + /// @brief **PVR stream demuxing**\n + /// Read TV streams with own demux within addon. + /// + /// This is only on Live TV streams and only if @ref PVRCapabilities::SetHandlesDemuxing() + /// has been set to "true". + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Stream demuxing parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_pvr_Streams_TV_Demux_header_addon_auto_check + /// @copydetails cpp_kodi_addon_pvr_Streams_TV_Demux_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Get the stream properties of the stream that's currently being read. + /// + /// @param[in] properties The properties of the currently playing stream. + /// @return @ref PVR_ERROR_NO_ERROR if the properties have been fetched successfully. + /// + /// @remarks Required, and only used if addon has its own demuxer. + /// + virtual PVR_ERROR GetStreamProperties(std::vector& properties) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Read the next packet from the demultiplexer, if there is one. + /// + /// @return The next packet. + /// If there is no next packet, then the add-on should return the packet + /// created by calling @ref AllocateDemuxPacket(0) on the callback. + /// If the stream changed and Kodi's player needs to be reinitialised, then, + /// the add-on should call @ref AllocateDemuxPacket(0) on the callback, and set + /// the streamid to @ref DMX_SPECIALID_STREAMCHANGE and return the value. + /// The add-on should return `nullptr` if an error occurred. + /// + /// @remarks Required, and only used if addon has its own demuxer. + /// Return `nullptr` if this add-on won't provide this function. + /// + virtual DemuxPacket* DemuxRead() { return nullptr; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Reset the demultiplexer in the add-on. + /// + /// @remarks Required, and only used if addon has its own demuxer. + /// + virtual void DemuxReset() {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Abort the demultiplexer thread in the add-on. + /// + /// @remarks Required, and only used if addon has its own demuxer. + /// + virtual void DemuxAbort() {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Flush all data that's currently in the demultiplexer buffer in the + /// add-on. + /// + /// @remarks Required, and only used if addon has its own demuxer. + /// + virtual void DemuxFlush() {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Notify the pvr addon/demuxer that Kodi wishes to change playback + /// speed. + /// + /// @param[in] speed The requested playback speed + /// + /// @remarks Optional, and only used if addon has its own demuxer. + /// + virtual void SetSpeed(int speed) {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Notify the pvr addon/demuxer that Kodi wishes to fill demux queue. + /// + /// @param[in] mode The requested filling mode + /// + /// @remarks Optional, and only used if addon has its own demuxer. + /// + virtual void FillBuffer(bool mode) {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Notify the pvr addon/demuxer that Kodi wishes to seek the stream by + /// time. + /// + /// @param[in] time The absolute time since stream start + /// @param[in] backwards True to seek to keyframe BEFORE time, else AFTER + /// @param[in] startpts can be updated to point to where display should start + /// @return True if the seek operation was possible + /// + /// @remarks Optional, and only used if addon has its own demuxer. + /// Return False if this add-on won't provide this function. + /// + virtual bool SeekTime(double time, bool backwards, double& startpts) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// Get the codec id used by Kodi. + /// + /// @param[in] codecName The name of the codec + /// @return The codec_id, or a codec_id with 0 values when not supported + /// + /// @remarks Only called from addon itself + /// + inline PVRCodec GetCodecByName(const std::string& codecName) const + { + return PVRCodec(m_instanceData->toKodi->GetCodecByName(m_instanceData->toKodi->kodiInstance, + codecName.c_str())); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// Allocate a demux packet. Free with @ref FreeDemuxPacket(). + /// + /// @param[in] iDataSize The size of the data that will go into the packet + /// @return The allocated packet + /// + /// @remarks Only called from addon itself + /// + inline DemuxPacket* AllocateDemuxPacket(int iDataSize) + { + return m_instanceData->toKodi->AllocateDemuxPacket(m_instanceData->toKodi->kodiInstance, + iDataSize); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Callback to Kodi Function**\n + /// Free a packet that was allocated with @ref AllocateDemuxPacket(). + /// + /// @param[in] pPacket The packet to free + /// + /// @remarks Only called from addon itself. + /// + inline void FreeDemuxPacket(DemuxPacket* pPacket) + { + m_instanceData->toKodi->FreeDemuxPacket(m_instanceData->toKodi->kodiInstance, pPacket); + } + //---------------------------------------------------------------------------- + ///@} + + ///@} + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Streams_Recording 8.2. Recording stream + /// @ingroup cpp_kodi_addon_pvr_Streams + /// @brief **PVR Recording stream**\n + /// Stream processing regarding recordings. + /// + /// @note Demuxing is not possible with the recordings. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Recording stream parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_pvr_Streams_Recording_header_addon_auto_check + /// @copydetails cpp_kodi_addon_pvr_Streams_Recording_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Open a stream to a recording on the backend. + /// + /// @param[in] recording The recording to open. + /// @return True if the stream has been opened successfully, false otherwise. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings() + /// is set to true. @ref CloseRecordedStream() will always be called by Kodi + /// prior to calling this function. + /// + virtual bool OpenRecordedStream(const kodi::addon::PVRRecording& recording) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Close an open stream from a recording. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings() + /// is set to true. + /// + virtual void CloseRecordedStream() {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Read from a recording. + /// + /// @param[in] buffer The buffer to store the data in. + /// @param[in] size The amount of bytes to read. + /// @return The amount of bytes that were actually read from the stream. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings() + /// is set to true. + /// + virtual int ReadRecordedStream(unsigned char* buffer, unsigned int size) { return 0; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Seek in a recorded stream. + /// + /// @param[in] position The position to seek to. + /// @param[in] whence [optional] offset relative to + /// You can set the value of whence to one of three things: + /// | Value | int | Description | + /// |:--------:|:---:|:----------------------------------------------------| + /// | SEEK_SET | 0 | position is relative to the beginning of the file. This is probably what you had in mind anyway, and is the most commonly used value for whence. + /// | SEEK_CUR | 1 | position is relative to the current file pointer position. So, in effect, you can say, "Move to my current position plus 30 bytes," or, "move to my current position minus 20 bytes." + /// | SEEK_END | 2 | position is relative to the end of the file. Just like SEEK_SET except from the other end of the file. Be sure to use negative values for offset if you want to back up from the end of the file, instead of going past the end into oblivion. + /// + /// @return The new position. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings() + /// is set to true. + /// + virtual int64_t SeekRecordedStream(int64_t position, int whence) { return 0; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Obtain the length of a recorded stream. + /// + /// @return The total length of the stream that's currently being read. + /// + /// @remarks Optional, and only used if @ref PVRCapabilities::SetSupportsRecordings() + /// is true (=> @ref ReadRecordedStream). + /// + virtual int64_t LengthRecordedStream() { return 0; } + //---------------------------------------------------------------------------- + + ///@} + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Streams_Various 8.3. Various functions + /// @ingroup cpp_kodi_addon_pvr_Streams + /// @brief **Various other PVR stream related functions**\n + /// These apply to all other groups in inputstream and are therefore declared + /// as several. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Various stream parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_pvr_Streams_Various_header_addon_auto_check + /// @copydetails cpp_kodi_addon_pvr_Streams_Various_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// + /// @brief Check if the backend support pausing the currently playing stream. + /// + /// This will enable/disable the pause button in Kodi based on the return + /// value. + /// + /// @return false if the PVR addon/backend does not support pausing, true if + /// possible + /// + virtual bool CanPauseStream() { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @brief Check if the backend supports seeking for the currently playing + /// stream. + /// + /// This will enable/disable the rewind/forward buttons in Kodi based on the + /// return value. + /// + /// @return false if the PVR addon/backend does not support seeking, true if + /// possible + /// + virtual bool CanSeekStream() { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @brief Notify the pvr addon that Kodi (un)paused the currently playing + /// stream. + /// + /// @param[in] paused To inform by `true` is paused and with `false` playing + /// + virtual void PauseStream(bool paused) {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @brief Check for real-time streaming. + /// + /// @return true if current stream is real-time + /// + virtual bool IsRealTimeStream() { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @brief Get stream times. + /// + /// @param[out] times A pointer to the data to be filled by the implementation. + /// @return @ref PVR_ERROR_NO_ERROR on success. + /// + virtual PVR_ERROR GetStreamTimes(kodi::addon::PVRStreamTimes& times) + { + return PVR_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @brief Obtain the chunk size to use when reading streams. + /// + /// @param[out] chunksize must be filled with the chunk size in bytes. + /// @return @ref PVR_ERROR_NO_ERROR if the chunk size has been fetched successfully. + /// + /// @remarks Optional, and only used if not reading from demuxer (=> @ref DemuxRead) and + /// @ref PVRCapabilities::SetSupportsRecordings() is true (=> @ref ReadRecordedStream) or + /// @ref PVRCapabilities::SetHandlesInputStream() is true (=> @ref ReadLiveStream). + /// + virtual PVR_ERROR GetStreamReadChunkSize(int& chunksize) { return PVR_ERROR_NOT_IMPLEMENTED; } + //---------------------------------------------------------------------------- + + ///@} + //--==----==----==----==----==----==----==----==----==----==----==----==----== + +private: + void SetAddonStruct(KODI_HANDLE instance, const std::string& kodiVersion) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstancePVRClient: Creation with empty addon " + "structure not allowed, table must be given from Kodi!"); + + m_instanceData = static_cast(instance); + m_instanceData->toAddon->addonInstance = this; + //--==----==----==----==----==----==----==----==----==----==----==----==----== + m_instanceData->toAddon->GetCapabilities = ADDON_GetCapabilities; + m_instanceData->toAddon->GetConnectionString = ADDON_GetConnectionString; + m_instanceData->toAddon->GetBackendName = ADDON_GetBackendName; + m_instanceData->toAddon->GetBackendVersion = ADDON_GetBackendVersion; + m_instanceData->toAddon->GetBackendHostname = ADDON_GetBackendHostname; + m_instanceData->toAddon->GetDriveSpace = ADDON_GetDriveSpace; + m_instanceData->toAddon->CallSettingsMenuHook = ADDON_CallSettingsMenuHook; + //--==----==----==----==----==----==----==----==----==----==----==----==----== + m_instanceData->toAddon->GetChannelsAmount = ADDON_GetChannelsAmount; + m_instanceData->toAddon->GetChannels = ADDON_GetChannels; + m_instanceData->toAddon->GetChannelStreamProperties = ADDON_GetChannelStreamProperties; + m_instanceData->toAddon->GetSignalStatus = ADDON_GetSignalStatus; + m_instanceData->toAddon->GetDescrambleInfo = ADDON_GetDescrambleInfo; + //--==----==----==----==----==----==----==----==----==----==----==----==----== + m_instanceData->toAddon->GetChannelGroupsAmount = ADDON_GetChannelGroupsAmount; + m_instanceData->toAddon->GetChannelGroups = ADDON_GetChannelGroups; + m_instanceData->toAddon->GetChannelGroupMembers = ADDON_GetChannelGroupMembers; + //--==----==----==----==----==----==----==----==----==----==----==----==----== + m_instanceData->toAddon->DeleteChannel = ADDON_DeleteChannel; + m_instanceData->toAddon->RenameChannel = ADDON_RenameChannel; + m_instanceData->toAddon->OpenDialogChannelSettings = ADDON_OpenDialogChannelSettings; + m_instanceData->toAddon->OpenDialogChannelAdd = ADDON_OpenDialogChannelAdd; + m_instanceData->toAddon->OpenDialogChannelScan = ADDON_OpenDialogChannelScan; + m_instanceData->toAddon->CallChannelMenuHook = ADDON_CallChannelMenuHook; + //--==----==----==----==----==----==----==----==----==----==----==----==----== + m_instanceData->toAddon->GetEPGForChannel = ADDON_GetEPGForChannel; + m_instanceData->toAddon->IsEPGTagRecordable = ADDON_IsEPGTagRecordable; + m_instanceData->toAddon->IsEPGTagPlayable = ADDON_IsEPGTagPlayable; + m_instanceData->toAddon->GetEPGTagEdl = ADDON_GetEPGTagEdl; + m_instanceData->toAddon->GetEPGTagStreamProperties = ADDON_GetEPGTagStreamProperties; + m_instanceData->toAddon->SetEPGTimeFrame = ADDON_SetEPGTimeFrame; + m_instanceData->toAddon->CallEPGMenuHook = ADDON_CallEPGMenuHook; + //--==----==----==----==----==----==----==----==----==----==----==----==----== + m_instanceData->toAddon->GetRecordingsAmount = ADDON_GetRecordingsAmount; + m_instanceData->toAddon->GetRecordings = ADDON_GetRecordings; + m_instanceData->toAddon->DeleteRecording = ADDON_DeleteRecording; + m_instanceData->toAddon->UndeleteRecording = ADDON_UndeleteRecording; + m_instanceData->toAddon->DeleteAllRecordingsFromTrash = ADDON_DeleteAllRecordingsFromTrash; + m_instanceData->toAddon->RenameRecording = ADDON_RenameRecording; + m_instanceData->toAddon->SetRecordingLifetime = ADDON_SetRecordingLifetime; + m_instanceData->toAddon->SetRecordingPlayCount = ADDON_SetRecordingPlayCount; + m_instanceData->toAddon->SetRecordingLastPlayedPosition = ADDON_SetRecordingLastPlayedPosition; + m_instanceData->toAddon->GetRecordingLastPlayedPosition = ADDON_GetRecordingLastPlayedPosition; + m_instanceData->toAddon->GetRecordingEdl = ADDON_GetRecordingEdl; + m_instanceData->toAddon->GetRecordingSize = ADDON_GetRecordingSize; + m_instanceData->toAddon->GetRecordingStreamProperties = ADDON_GetRecordingStreamProperties; + m_instanceData->toAddon->CallRecordingMenuHook = ADDON_CallRecordingMenuHook; + //--==----==----==----==----==----==----==----==----==----==----==----==----== + m_instanceData->toAddon->GetTimerTypes = ADDON_GetTimerTypes; + m_instanceData->toAddon->GetTimersAmount = ADDON_GetTimersAmount; + m_instanceData->toAddon->GetTimers = ADDON_GetTimers; + m_instanceData->toAddon->AddTimer = ADDON_AddTimer; + m_instanceData->toAddon->DeleteTimer = ADDON_DeleteTimer; + m_instanceData->toAddon->UpdateTimer = ADDON_UpdateTimer; + m_instanceData->toAddon->CallTimerMenuHook = ADDON_CallTimerMenuHook; + //--==----==----==----==----==----==----==----==----==----==----==----==----== + m_instanceData->toAddon->OnSystemSleep = ADDON_OnSystemSleep; + m_instanceData->toAddon->OnSystemWake = ADDON_OnSystemWake; + m_instanceData->toAddon->OnPowerSavingActivated = ADDON_OnPowerSavingActivated; + m_instanceData->toAddon->OnPowerSavingDeactivated = ADDON_OnPowerSavingDeactivated; + //--==----==----==----==----==----==----==----==----==----==----==----==----== + m_instanceData->toAddon->OpenLiveStream = ADDON_OpenLiveStream; + m_instanceData->toAddon->CloseLiveStream = ADDON_CloseLiveStream; + m_instanceData->toAddon->ReadLiveStream = ADDON_ReadLiveStream; + m_instanceData->toAddon->SeekLiveStream = ADDON_SeekLiveStream; + m_instanceData->toAddon->LengthLiveStream = ADDON_LengthLiveStream; + m_instanceData->toAddon->GetStreamProperties = ADDON_GetStreamProperties; + m_instanceData->toAddon->GetStreamReadChunkSize = ADDON_GetStreamReadChunkSize; + m_instanceData->toAddon->IsRealTimeStream = ADDON_IsRealTimeStream; + //--==----==----==----==----==----==----==----==----==----==----==----==----== + m_instanceData->toAddon->OpenRecordedStream = ADDON_OpenRecordedStream; + m_instanceData->toAddon->CloseRecordedStream = ADDON_CloseRecordedStream; + m_instanceData->toAddon->ReadRecordedStream = ADDON_ReadRecordedStream; + m_instanceData->toAddon->SeekRecordedStream = ADDON_SeekRecordedStream; + m_instanceData->toAddon->LengthRecordedStream = ADDON_LengthRecordedStream; + //--==----==----==----==----==----==----==----==----==----==----==----==----== + m_instanceData->toAddon->DemuxReset = ADDON_DemuxReset; + m_instanceData->toAddon->DemuxAbort = ADDON_DemuxAbort; + m_instanceData->toAddon->DemuxFlush = ADDON_DemuxFlush; + m_instanceData->toAddon->DemuxRead = ADDON_DemuxRead; + //--==----==----==----==----==----==----==----==----==----==----==----==----== + m_instanceData->toAddon->CanPauseStream = ADDON_CanPauseStream; + m_instanceData->toAddon->PauseStream = ADDON_PauseStream; + m_instanceData->toAddon->CanSeekStream = ADDON_CanSeekStream; + m_instanceData->toAddon->SeekTime = ADDON_SeekTime; + m_instanceData->toAddon->SetSpeed = ADDON_SetSpeed; + m_instanceData->toAddon->FillBuffer = ADDON_FillBuffer; + m_instanceData->toAddon->GetStreamTimes = ADDON_GetStreamTimes; + } + + inline static PVR_ERROR ADDON_GetCapabilities(const AddonInstance_PVR* instance, + PVR_ADDON_CAPABILITIES* capabilities) + { + PVRCapabilities cppCapabilities(capabilities); + return static_cast(instance->toAddon->addonInstance) + ->GetCapabilities(cppCapabilities); + } + + inline static PVR_ERROR ADDON_GetBackendName(const AddonInstance_PVR* instance, + char* str, + int memSize) + { + std::string backendName; + PVR_ERROR err = static_cast(instance->toAddon->addonInstance) + ->GetBackendName(backendName); + if (err == PVR_ERROR_NO_ERROR) + strncpy(str, backendName.c_str(), memSize); + return err; + } + + inline static PVR_ERROR ADDON_GetBackendVersion(const AddonInstance_PVR* instance, + char* str, + int memSize) + { + std::string backendVersion; + PVR_ERROR err = static_cast(instance->toAddon->addonInstance) + ->GetBackendVersion(backendVersion); + if (err == PVR_ERROR_NO_ERROR) + strncpy(str, backendVersion.c_str(), memSize); + return err; + } + + inline static PVR_ERROR ADDON_GetBackendHostname(const AddonInstance_PVR* instance, + char* str, + int memSize) + { + std::string backendHostname; + PVR_ERROR err = static_cast(instance->toAddon->addonInstance) + ->GetBackendHostname(backendHostname); + if (err == PVR_ERROR_NO_ERROR) + strncpy(str, backendHostname.c_str(), memSize); + return err; + } + + inline static PVR_ERROR ADDON_GetConnectionString(const AddonInstance_PVR* instance, + char* str, + int memSize) + { + std::string connectionString; + PVR_ERROR err = static_cast(instance->toAddon->addonInstance) + ->GetConnectionString(connectionString); + if (err == PVR_ERROR_NO_ERROR) + strncpy(str, connectionString.c_str(), memSize); + return err; + } + + inline static PVR_ERROR ADDON_GetDriveSpace(const AddonInstance_PVR* instance, + uint64_t* total, + uint64_t* used) + { + return static_cast(instance->toAddon->addonInstance) + ->GetDriveSpace(*total, *used); + } + + inline static PVR_ERROR ADDON_CallSettingsMenuHook(const AddonInstance_PVR* instance, + const PVR_MENUHOOK* menuhook) + { + return static_cast(instance->toAddon->addonInstance) + ->CallSettingsMenuHook(menuhook); + } + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + inline static PVR_ERROR ADDON_GetChannelsAmount(const AddonInstance_PVR* instance, int* amount) + { + return static_cast(instance->toAddon->addonInstance) + ->GetChannelsAmount(*amount); + } + + inline static PVR_ERROR ADDON_GetChannels(const AddonInstance_PVR* instance, + ADDON_HANDLE handle, + bool radio) + { + PVRChannelsResultSet result(instance, handle); + return static_cast(instance->toAddon->addonInstance) + ->GetChannels(radio, result); + } + + inline static PVR_ERROR ADDON_GetChannelStreamProperties(const AddonInstance_PVR* instance, + const PVR_CHANNEL* channel, + PVR_NAMED_VALUE* properties, + unsigned int* propertiesCount) + { + *propertiesCount = 0; + std::vector propertiesList; + PVR_ERROR error = static_cast(instance->toAddon->addonInstance) + ->GetChannelStreamProperties(channel, propertiesList); + if (error == PVR_ERROR_NO_ERROR) + { + for (const auto& property : propertiesList) + { + strncpy(properties[*propertiesCount].strName, property.GetCStructure()->strName, + sizeof(properties[*propertiesCount].strName) - 1); + strncpy(properties[*propertiesCount].strValue, property.GetCStructure()->strValue, + sizeof(properties[*propertiesCount].strValue) - 1); + ++*propertiesCount; + if (*propertiesCount > STREAM_MAX_PROPERTY_COUNT) + break; + } + } + return error; + } + + inline static PVR_ERROR ADDON_GetSignalStatus(const AddonInstance_PVR* instance, + int channelUid, + PVR_SIGNAL_STATUS* signalStatus) + { + PVRSignalStatus cppSignalStatus(signalStatus); + return static_cast(instance->toAddon->addonInstance) + ->GetSignalStatus(channelUid, cppSignalStatus); + } + + inline static PVR_ERROR ADDON_GetDescrambleInfo(const AddonInstance_PVR* instance, + int channelUid, + PVR_DESCRAMBLE_INFO* descrambleInfo) + { + PVRDescrambleInfo cppDescrambleInfo(descrambleInfo); + return static_cast(instance->toAddon->addonInstance) + ->GetDescrambleInfo(channelUid, cppDescrambleInfo); + } + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + inline static PVR_ERROR ADDON_GetChannelGroupsAmount(const AddonInstance_PVR* instance, + int* amount) + { + return static_cast(instance->toAddon->addonInstance) + ->GetChannelGroupsAmount(*amount); + } + + inline static PVR_ERROR ADDON_GetChannelGroups(const AddonInstance_PVR* instance, + ADDON_HANDLE handle, + bool radio) + { + PVRChannelGroupsResultSet result(instance, handle); + return static_cast(instance->toAddon->addonInstance) + ->GetChannelGroups(radio, result); + } + + inline static PVR_ERROR ADDON_GetChannelGroupMembers(const AddonInstance_PVR* instance, + ADDON_HANDLE handle, + const PVR_CHANNEL_GROUP* group) + { + PVRChannelGroupMembersResultSet result(instance, handle); + return static_cast(instance->toAddon->addonInstance) + ->GetChannelGroupMembers(group, result); + } + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + inline static PVR_ERROR ADDON_DeleteChannel(const AddonInstance_PVR* instance, + const PVR_CHANNEL* channel) + { + return static_cast(instance->toAddon->addonInstance) + ->DeleteChannel(channel); + } + + inline static PVR_ERROR ADDON_RenameChannel(const AddonInstance_PVR* instance, + const PVR_CHANNEL* channel) + { + return static_cast(instance->toAddon->addonInstance) + ->RenameChannel(channel); + } + + inline static PVR_ERROR ADDON_OpenDialogChannelSettings(const AddonInstance_PVR* instance, + const PVR_CHANNEL* channel) + { + return static_cast(instance->toAddon->addonInstance) + ->OpenDialogChannelSettings(channel); + } + + inline static PVR_ERROR ADDON_OpenDialogChannelAdd(const AddonInstance_PVR* instance, + const PVR_CHANNEL* channel) + { + return static_cast(instance->toAddon->addonInstance) + ->OpenDialogChannelAdd(channel); + } + + inline static PVR_ERROR ADDON_OpenDialogChannelScan(const AddonInstance_PVR* instance) + { + return static_cast(instance->toAddon->addonInstance) + ->OpenDialogChannelScan(); + } + + inline static PVR_ERROR ADDON_CallChannelMenuHook(const AddonInstance_PVR* instance, + const PVR_MENUHOOK* menuhook, + const PVR_CHANNEL* channel) + { + return static_cast(instance->toAddon->addonInstance) + ->CallChannelMenuHook(menuhook, channel); + } + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + inline static PVR_ERROR ADDON_GetEPGForChannel(const AddonInstance_PVR* instance, + ADDON_HANDLE handle, + int channelUid, + time_t start, + time_t end) + { + PVREPGTagsResultSet result(instance, handle); + return static_cast(instance->toAddon->addonInstance) + ->GetEPGForChannel(channelUid, start, end, result); + } + + inline static PVR_ERROR ADDON_IsEPGTagRecordable(const AddonInstance_PVR* instance, + const EPG_TAG* tag, + bool* isRecordable) + { + return static_cast(instance->toAddon->addonInstance) + ->IsEPGTagRecordable(tag, *isRecordable); + } + + inline static PVR_ERROR ADDON_IsEPGTagPlayable(const AddonInstance_PVR* instance, + const EPG_TAG* tag, + bool* isPlayable) + { + return static_cast(instance->toAddon->addonInstance) + ->IsEPGTagPlayable(tag, *isPlayable); + } + + inline static PVR_ERROR ADDON_GetEPGTagEdl(const AddonInstance_PVR* instance, + const EPG_TAG* tag, + PVR_EDL_ENTRY* edl, + int* size) + { + *size = 0; + std::vector edlList; + PVR_ERROR error = static_cast(instance->toAddon->addonInstance) + ->GetEPGTagEdl(tag, edlList); + if (error == PVR_ERROR_NO_ERROR) + { + for (const auto& edlEntry : edlList) + { + edl[*size] = *edlEntry; + ++*size; + } + } + return error; + } + + inline static PVR_ERROR ADDON_GetEPGTagStreamProperties(const AddonInstance_PVR* instance, + const EPG_TAG* tag, + PVR_NAMED_VALUE* properties, + unsigned int* propertiesCount) + { + *propertiesCount = 0; + std::vector propertiesList; + PVR_ERROR error = static_cast(instance->toAddon->addonInstance) + ->GetEPGTagStreamProperties(tag, propertiesList); + if (error == PVR_ERROR_NO_ERROR) + { + for (const auto& property : propertiesList) + { + strncpy(properties[*propertiesCount].strName, property.GetCStructure()->strName, + sizeof(properties[*propertiesCount].strName) - 1); + strncpy(properties[*propertiesCount].strValue, property.GetCStructure()->strValue, + sizeof(properties[*propertiesCount].strValue) - 1); + ++*propertiesCount; + if (*propertiesCount > STREAM_MAX_PROPERTY_COUNT) + break; + } + } + return error; + } + + inline static PVR_ERROR ADDON_SetEPGTimeFrame(const AddonInstance_PVR* instance, int days) + { + return static_cast(instance->toAddon->addonInstance) + ->SetEPGTimeFrame(days); + } + + inline static PVR_ERROR ADDON_CallEPGMenuHook(const AddonInstance_PVR* instance, + const PVR_MENUHOOK* menuhook, + const EPG_TAG* tag) + { + return static_cast(instance->toAddon->addonInstance) + ->CallEPGMenuHook(menuhook, tag); + } + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + inline static PVR_ERROR ADDON_GetRecordingsAmount(const AddonInstance_PVR* instance, + bool deleted, + int* amount) + { + return static_cast(instance->toAddon->addonInstance) + ->GetRecordingsAmount(deleted, *amount); + } + + inline static PVR_ERROR ADDON_GetRecordings(const AddonInstance_PVR* instance, + ADDON_HANDLE handle, + bool deleted) + { + PVRRecordingsResultSet result(instance, handle); + return static_cast(instance->toAddon->addonInstance) + ->GetRecordings(deleted, result); + } + + inline static PVR_ERROR ADDON_DeleteRecording(const AddonInstance_PVR* instance, + const PVR_RECORDING* recording) + { + return static_cast(instance->toAddon->addonInstance) + ->DeleteRecording(recording); + } + + inline static PVR_ERROR ADDON_UndeleteRecording(const AddonInstance_PVR* instance, + const PVR_RECORDING* recording) + { + return static_cast(instance->toAddon->addonInstance) + ->UndeleteRecording(recording); + } + + inline static PVR_ERROR ADDON_DeleteAllRecordingsFromTrash(const AddonInstance_PVR* instance) + { + return static_cast(instance->toAddon->addonInstance) + ->DeleteAllRecordingsFromTrash(); + } + + inline static PVR_ERROR ADDON_RenameRecording(const AddonInstance_PVR* instance, + const PVR_RECORDING* recording) + { + return static_cast(instance->toAddon->addonInstance) + ->RenameRecording(recording); + } + + inline static PVR_ERROR ADDON_SetRecordingLifetime(const AddonInstance_PVR* instance, + const PVR_RECORDING* recording) + { + return static_cast(instance->toAddon->addonInstance) + ->SetRecordingLifetime(recording); + } + + inline static PVR_ERROR ADDON_SetRecordingPlayCount(const AddonInstance_PVR* instance, + const PVR_RECORDING* recording, + int count) + { + return static_cast(instance->toAddon->addonInstance) + ->SetRecordingPlayCount(recording, count); + } + + inline static PVR_ERROR ADDON_SetRecordingLastPlayedPosition(const AddonInstance_PVR* instance, + const PVR_RECORDING* recording, + int lastplayedposition) + { + return static_cast(instance->toAddon->addonInstance) + ->SetRecordingLastPlayedPosition(recording, lastplayedposition); + } + + inline static PVR_ERROR ADDON_GetRecordingLastPlayedPosition(const AddonInstance_PVR* instance, + const PVR_RECORDING* recording, + int* position) + { + return static_cast(instance->toAddon->addonInstance) + ->GetRecordingLastPlayedPosition(recording, *position); + } + + inline static PVR_ERROR ADDON_GetRecordingEdl(const AddonInstance_PVR* instance, + const PVR_RECORDING* recording, + PVR_EDL_ENTRY* edl, + int* size) + { + *size = 0; + std::vector edlList; + PVR_ERROR error = static_cast(instance->toAddon->addonInstance) + ->GetRecordingEdl(recording, edlList); + if (error == PVR_ERROR_NO_ERROR) + { + for (const auto& edlEntry : edlList) + { + edl[*size] = *edlEntry; + ++*size; + } + } + return error; + } + + inline static PVR_ERROR ADDON_GetRecordingSize(const AddonInstance_PVR* instance, + const PVR_RECORDING* recording, + int64_t* size) + { + return static_cast(instance->toAddon->addonInstance) + ->GetRecordingSize(recording, *size); + } + + inline static PVR_ERROR ADDON_GetRecordingStreamProperties(const AddonInstance_PVR* instance, + const PVR_RECORDING* recording, + PVR_NAMED_VALUE* properties, + unsigned int* propertiesCount) + { + *propertiesCount = 0; + std::vector propertiesList; + PVR_ERROR error = static_cast(instance->toAddon->addonInstance) + ->GetRecordingStreamProperties(recording, propertiesList); + if (error == PVR_ERROR_NO_ERROR) + { + for (const auto& property : propertiesList) + { + strncpy(properties[*propertiesCount].strName, property.GetCStructure()->strName, + sizeof(properties[*propertiesCount].strName) - 1); + strncpy(properties[*propertiesCount].strValue, property.GetCStructure()->strValue, + sizeof(properties[*propertiesCount].strValue) - 1); + ++*propertiesCount; + if (*propertiesCount > STREAM_MAX_PROPERTY_COUNT) + break; + } + } + return error; + } + + inline static PVR_ERROR ADDON_CallRecordingMenuHook(const AddonInstance_PVR* instance, + const PVR_MENUHOOK* menuhook, + const PVR_RECORDING* recording) + { + return static_cast(instance->toAddon->addonInstance) + ->CallRecordingMenuHook(menuhook, recording); + } + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + + inline static PVR_ERROR ADDON_GetTimerTypes(const AddonInstance_PVR* instance, + PVR_TIMER_TYPE* types, + int* typesCount) + { + *typesCount = 0; + std::vector timerTypes; + PVR_ERROR error = static_cast(instance->toAddon->addonInstance) + ->GetTimerTypes(timerTypes); + if (error == PVR_ERROR_NO_ERROR) + { + for (const auto& timerType : timerTypes) + { + types[*typesCount] = *timerType; + ++*typesCount; + if (*typesCount >= PVR_ADDON_TIMERTYPE_ARRAY_SIZE) + break; + } + } + return error; + } + + inline static PVR_ERROR ADDON_GetTimersAmount(const AddonInstance_PVR* instance, int* amount) + { + return static_cast(instance->toAddon->addonInstance) + ->GetTimersAmount(*amount); + } + + inline static PVR_ERROR ADDON_GetTimers(const AddonInstance_PVR* instance, ADDON_HANDLE handle) + { + PVRTimersResultSet result(instance, handle); + return static_cast(instance->toAddon->addonInstance)->GetTimers(result); + } + + inline static PVR_ERROR ADDON_AddTimer(const AddonInstance_PVR* instance, const PVR_TIMER* timer) + { + return static_cast(instance->toAddon->addonInstance)->AddTimer(timer); + } + + inline static PVR_ERROR ADDON_DeleteTimer(const AddonInstance_PVR* instance, + const PVR_TIMER* timer, + bool forceDelete) + { + return static_cast(instance->toAddon->addonInstance) + ->DeleteTimer(timer, forceDelete); + } + + inline static PVR_ERROR ADDON_UpdateTimer(const AddonInstance_PVR* instance, + const PVR_TIMER* timer) + { + return static_cast(instance->toAddon->addonInstance)->UpdateTimer(timer); + } + + inline static PVR_ERROR ADDON_CallTimerMenuHook(const AddonInstance_PVR* instance, + const PVR_MENUHOOK* menuhook, + const PVR_TIMER* timer) + { + return static_cast(instance->toAddon->addonInstance) + ->CallTimerMenuHook(menuhook, timer); + } + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + + inline static PVR_ERROR ADDON_OnSystemSleep(const AddonInstance_PVR* instance) + { + return static_cast(instance->toAddon->addonInstance)->OnSystemSleep(); + } + + inline static PVR_ERROR ADDON_OnSystemWake(const AddonInstance_PVR* instance) + { + return static_cast(instance->toAddon->addonInstance)->OnSystemWake(); + } + + inline static PVR_ERROR ADDON_OnPowerSavingActivated(const AddonInstance_PVR* instance) + { + return static_cast(instance->toAddon->addonInstance) + ->OnPowerSavingActivated(); + } + + inline static PVR_ERROR ADDON_OnPowerSavingDeactivated(const AddonInstance_PVR* instance) + { + return static_cast(instance->toAddon->addonInstance) + ->OnPowerSavingDeactivated(); + } + + // obsolete parts below + ///@{ + + inline static bool ADDON_OpenLiveStream(const AddonInstance_PVR* instance, + const PVR_CHANNEL* channel) + { + return static_cast(instance->toAddon->addonInstance) + ->OpenLiveStream(channel); + } + + inline static void ADDON_CloseLiveStream(const AddonInstance_PVR* instance) + { + static_cast(instance->toAddon->addonInstance)->CloseLiveStream(); + } + + inline static int ADDON_ReadLiveStream(const AddonInstance_PVR* instance, + unsigned char* buffer, + unsigned int size) + { + return static_cast(instance->toAddon->addonInstance) + ->ReadLiveStream(buffer, size); + } + + inline static int64_t ADDON_SeekLiveStream(const AddonInstance_PVR* instance, + int64_t position, + int whence) + { + return static_cast(instance->toAddon->addonInstance) + ->SeekLiveStream(position, whence); + } + + inline static int64_t ADDON_LengthLiveStream(const AddonInstance_PVR* instance) + { + return static_cast(instance->toAddon->addonInstance)->LengthLiveStream(); + } + + inline static PVR_ERROR ADDON_GetStreamProperties(const AddonInstance_PVR* instance, + PVR_STREAM_PROPERTIES* properties) + { + properties->iStreamCount = 0; + std::vector cppProperties; + PVR_ERROR err = static_cast(instance->toAddon->addonInstance) + ->GetStreamProperties(cppProperties); + if (err == PVR_ERROR_NO_ERROR) + { + for (unsigned int i = 0; i < cppProperties.size(); ++i) + { + memcpy(&properties->stream[i], + static_cast(cppProperties[i]), + sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); + ++properties->iStreamCount; + + if (properties->iStreamCount >= PVR_STREAM_MAX_STREAMS) + { + kodi::Log( + ADDON_LOG_ERROR, + "CInstancePVRClient::%s: Addon given with '%li' more allowed streams where '%i'", + __func__, cppProperties.size(), PVR_STREAM_MAX_STREAMS); + break; + } + } + } + + return err; + } + + inline static PVR_ERROR ADDON_GetStreamReadChunkSize(const AddonInstance_PVR* instance, + int* chunksize) + { + return static_cast(instance->toAddon->addonInstance) + ->GetStreamReadChunkSize(*chunksize); + } + + inline static bool ADDON_IsRealTimeStream(const AddonInstance_PVR* instance) + { + return static_cast(instance->toAddon->addonInstance)->IsRealTimeStream(); + } + + inline static bool ADDON_OpenRecordedStream(const AddonInstance_PVR* instance, + const PVR_RECORDING* recording) + { + return static_cast(instance->toAddon->addonInstance) + ->OpenRecordedStream(recording); + } + + inline static void ADDON_CloseRecordedStream(const AddonInstance_PVR* instance) + { + static_cast(instance->toAddon->addonInstance)->CloseRecordedStream(); + } + + inline static int ADDON_ReadRecordedStream(const AddonInstance_PVR* instance, + unsigned char* buffer, + unsigned int size) + { + return static_cast(instance->toAddon->addonInstance) + ->ReadRecordedStream(buffer, size); + } + + inline static int64_t ADDON_SeekRecordedStream(const AddonInstance_PVR* instance, + int64_t position, + int whence) + { + return static_cast(instance->toAddon->addonInstance) + ->SeekRecordedStream(position, whence); + } + + inline static int64_t ADDON_LengthRecordedStream(const AddonInstance_PVR* instance) + { + return static_cast(instance->toAddon->addonInstance) + ->LengthRecordedStream(); + } + + inline static void ADDON_DemuxReset(const AddonInstance_PVR* instance) + { + static_cast(instance->toAddon->addonInstance)->DemuxReset(); + } + + inline static void ADDON_DemuxAbort(const AddonInstance_PVR* instance) + { + static_cast(instance->toAddon->addonInstance)->DemuxAbort(); + } + + inline static void ADDON_DemuxFlush(const AddonInstance_PVR* instance) + { + static_cast(instance->toAddon->addonInstance)->DemuxFlush(); + } + + inline static DemuxPacket* ADDON_DemuxRead(const AddonInstance_PVR* instance) + { + return static_cast(instance->toAddon->addonInstance)->DemuxRead(); + } + + inline static bool ADDON_CanPauseStream(const AddonInstance_PVR* instance) + { + return static_cast(instance->toAddon->addonInstance)->CanPauseStream(); + } + + inline static bool ADDON_CanSeekStream(const AddonInstance_PVR* instance) + { + return static_cast(instance->toAddon->addonInstance)->CanSeekStream(); + } + + inline static void ADDON_PauseStream(const AddonInstance_PVR* instance, bool bPaused) + { + static_cast(instance->toAddon->addonInstance)->PauseStream(bPaused); + } + + inline static bool ADDON_SeekTime(const AddonInstance_PVR* instance, + double time, + bool backwards, + double* startpts) + { + return static_cast(instance->toAddon->addonInstance) + ->SeekTime(time, backwards, *startpts); + } + + inline static void ADDON_SetSpeed(const AddonInstance_PVR* instance, int speed) + { + static_cast(instance->toAddon->addonInstance)->SetSpeed(speed); + } + + inline static void ADDON_FillBuffer(const AddonInstance_PVR* instance, bool mode) + { + static_cast(instance->toAddon->addonInstance)->FillBuffer(mode); + } + + inline static PVR_ERROR ADDON_GetStreamTimes(const AddonInstance_PVR* instance, + PVR_STREAM_TIMES* times) + { + PVRStreamTimes cppTimes(times); + return static_cast(instance->toAddon->addonInstance) + ->GetStreamTimes(cppTimes); + } + ///@} + + AddonInstance_PVR* m_instanceData = nullptr; +}; +//}}} +//______________________________________________________________________________ + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Peripheral.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Peripheral.h new file mode 100644 index 0000000..46060a8 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Peripheral.h @@ -0,0 +1,907 @@ +/* + * Copyright (C) 2014-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../AddonBase.h" +#include "peripheral/PeripheralUtils.h" + +#ifdef __cplusplus +namespace kodi +{ +namespace addon +{ + +//############################################################################## +/// @defgroup cpp_kodi_addon_peripheral_Defs Definitions, structures and enumerators +/// @ingroup cpp_kodi_addon_peripheral +/// @brief %Peripheral add-on general variables +/// +/// Used to exchange the available options between Kodi and addon. +/// +/// + +//############################################################################## +/// @defgroup cpp_kodi_addon_peripheral_Defs_General 1. General +/// @ingroup cpp_kodi_addon_peripheral_Defs +/// @brief **%Peripheral add-on general variables**\n +/// Used to exchange the available options between Kodi and addon. +/// +/// This group also includes @ref cpp_kodi_addon_peripheral_Defs_PeripheralCapabilities +/// with which Kodi an @ref kodi::addon::CInstancePeripheral::GetCapabilities() +/// queries the supported **modules** of the addon. +/// + +//############################################################################## +/// @defgroup cpp_kodi_addon_peripheral_Defs_Peripheral 2. Peripheral +/// @ingroup cpp_kodi_addon_peripheral_Defs +/// @brief **%Peripheral add-on operation variables**\n +/// Used to exchange the available options between Kodi and addon. +/// + +//############################################################################## +/// @defgroup cpp_kodi_addon_peripheral_Defs_Event 3. Event +/// @ingroup cpp_kodi_addon_peripheral_Defs +/// @brief **%Event add-on operation variables**\n +/// Used to exchange the available options between Kodi and addon. +/// + +//############################################################################## +/// @defgroup cpp_kodi_addon_peripheral_Defs_Joystick 4. Joystick +/// @ingroup cpp_kodi_addon_peripheral_Defs +/// @brief **%Joystick add-on operation variables**\n +/// Used to exchange the available options between Kodi and addon. +/// + +//============================================================================== +/// @addtogroup cpp_kodi_addon_peripheral +/// @brief \cpp_class{ kodi::addon::CInstancePeripheral } +/// **%Peripheral add-on instance** +/// +/// The peripheral add-ons provides access to many joystick and gamepad +/// interfaces across various platforms. An input addon is used to map the +/// buttons/axis on your physical input device, to the buttons/axis of your +/// virtual system. This is necessary because different retro systems usually +/// have different button layouts. A controller configuration utility is also +/// in the works. +/// +/// ---------------------------------------------------------------------------- +/// +/// Here is an example of what the `addon.xml.in` would look like for an +/// peripheral addon: +/// +/// ~~~~~~~~~~~~~{.xml} +/// +/// +/// @ADDON_DEPENDS@ +/// +/// +/// My peripheral addon +/// My peripheral addon description +/// @PLATFORM@ +/// +/// +/// ~~~~~~~~~~~~~ +/// +/// Description to peripheral related addon.xml values: +/// | Name | Description +/// |:------------------------------|---------------------------------------- +/// | `provides_joysticks` | Set to "true" if addon provides joystick support. +/// | `provides_buttonmaps` | Set to "true" if button map is used and supported by addon. +/// | `point` | Addon type specification
At all addon types and for this kind always "kodi.peripheral". +/// | `library_@PLATFORM@` | Sets the used library name, which is automatically set by cmake at addon build. +/// +/// @remark For more detailed description of the `addon.xml`, see also https://kodi.wiki/view/Addon.xml. +/// +/// +/// -------------------------------------------------------------------------- +/// +/// **Here is an example of how addon can be used as a single:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class CMyPeripheralAddon : public kodi::addon::CAddonBase, +/// public kodi::addon::CInstancePeripheral +/// { +/// public: +/// CMyPeripheralAddon(); +/// +/// void GetCapabilities(kodi::addon::PeripheralCapabilities& capabilities) override; +/// ... +/// }; +/// +/// CMyPeripheralAddon::CMyPeripheralAddon() +/// { +/// ... +/// } +/// +/// void CMyPeripheralAddon::GetCapabilities(kodi::addon::PeripheralCapabilities& capabilities) +/// { +/// capabilities.SetProvidesJoysticks(true); +/// capabilities.SetProvidesButtonmaps(true); +/// ... +/// } +/// +/// ADDONCREATOR(CMyPeripheralAddon) +/// ~~~~~~~~~~~~~ +/// +/// @note It is imperative to use the necessary functions of this class in the +/// addon. +/// +/// -------------------------------------------------------------------------- +/// +/// +/// **Here is another example where the peripheral is used together with +/// other instance types:** +/// +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class CMyPeripheralAddon : public kodi::addon::CInstancePeripheral +/// { +/// public: +/// CMyPeripheralAddon(KODI_HANDLE instance, const std::string& version); +/// +/// void GetCapabilities(kodi::addon::PeripheralCapabilities& capabilities) override; +/// ... +/// }; +/// +/// CMyPeripheralAddon::CMyPeripheralAddon(KODI_HANDLE instance, const std::string& version) +/// : CInstancePeripheral(instance, version) +/// { +/// ... +/// } +/// +/// void CMyPeripheralAddon::GetCapabilities(kodi::addon::PeripheralCapabilities& capabilities) +/// { +/// capabilities.SetProvidesJoysticks(true); +/// capabilities.SetProvidesButtonmaps(true); +/// ... +/// } +/// +/// //---------------------------------------------------------------------- +/// +/// class CMyAddon : public kodi::addon::CAddonBase +/// { +/// public: +/// CMyAddon() = default; +/// ADDON_STATUS CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) override; +/// }; +/// +/// // If you use only one instance in your add-on, can be instanceType and +/// // instanceID ignored +/// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) +/// { +/// if (instanceType == ADDON_INSTANCE_PERIPHERAL) +/// { +/// kodi::Log(ADDON_LOG_INFO, "Creating my peripheral addon"); +/// addonInstance = new CMyPeripheralAddon(instance, version); +/// return ADDON_STATUS_OK; +/// } +/// else if (...) +/// { +/// ... +/// } +/// return ADDON_STATUS_UNKNOWN; +/// } +/// +/// ADDONCREATOR(CMyAddon) +/// ~~~~~~~~~~~~~ +/// +/// The destruction of the example class `CMyPeripheralAddon` is called from +/// Kodi's header. Manually deleting the add-on instance is not required. +/// +class ATTRIBUTE_HIDDEN CInstancePeripheral : public IAddonInstance +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_addon_peripheral + /// @brief %Peripheral class constructor. + /// + /// Used by an add-on that only supports peripheral. + /// + CInstancePeripheral() + : IAddonInstance(ADDON_INSTANCE_PERIPHERAL, GetKodiTypeVersion(ADDON_INSTANCE_PERIPHERAL)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstancePeripheral: Creation of more as one in single " + "instance way is not allowed!"); + + SetAddonStruct(CAddonBase::m_interface->firstKodiInstance); + CAddonBase::m_interface->globalSingleInstance = this; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_peripheral + /// @brief %Peripheral addon class constructor used to support multiple + /// instance types. + /// + /// @param[in] instance The instance value given to + /// `kodi::addon::CAddonBase::CreateInstance(...)`. + /// @param[in] kodiVersion [opt] Version used in Kodi for this instance, to + /// allow compatibility to older Kodi versions. + /// + /// @note Recommended to set `kodiVersion`. + /// + /// + /// -------------------------------------------------------------------------- + /// + //////*Here's example about the use of this:** + /// ~~~~~~~~~~~~~{.cpp} + /// class CMyPeripheralAddon : public kodi::addon::CInstancePeripheral + /// { + /// public: + /// CMyPeripheralAddon(KODI_HANDLE instance, const std::string& kodiVersion) + /// : kodi::addon::CInstancePeripheral(instance, kodiVersion) + /// { + /// ... + /// } + /// + /// ... + /// }; + /// + /// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, + /// const std::string& instanceID, + /// KODI_HANDLE instance, + /// const std::string& version, + /// KODI_HANDLE& addonInstance) + /// { + /// kodi::Log(ADDON_LOG_INFO, "Creating my peripheral"); + /// addonInstance = new CMyPeripheralAddon(instance, version); + /// return ADDON_STATUS_OK; + /// } + /// ~~~~~~~~~~~~~ + /// + explicit CInstancePeripheral(KODI_HANDLE instance, const std::string& kodiVersion = "") + : IAddonInstance(ADDON_INSTANCE_PERIPHERAL, + !kodiVersion.empty() ? kodiVersion + : GetKodiTypeVersion(ADDON_INSTANCE_PERIPHERAL)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstancePeripheral: Creation of multiple together with " + "single instance way is not allowed!"); + + SetAddonStruct(instance); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_peripheral + /// @brief Destructor. + /// + ~CInstancePeripheral() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_peripheralOp 1. Peripheral operations + /// @ingroup cpp_kodi_addon_peripheral + /// @brief %Peripheral operations to handle control about. + /// + ///--------------------------------------------------------------------------- + /// + /// **%Peripheral parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_peripheral_peripheralOp_header_addon_auto_check + /// @copydetails cpp_kodi_addon_peripheral_peripheralOp_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Get the list of features that this add-on provides. + /// + /// Called by the frontend to query the add-on's capabilities and supported + /// peripherals. All capabilities that the add-on supports should be set to true. + /// + /// @param[out] capabilities The add-on's capabilities + /// + /// @remarks Valid implementation required. + /// + /// + /// ---------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_peripheral_Defs_PeripheralCapabilities_Help + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// void CMyPeripheralAddon::GetCapabilities(kodi::addon::PeripheralCapabilities& capabilities) + /// { + /// capabilities.SetProvidesJoysticks(true); + /// capabilities.SetProvidesButtonmaps(true); + /// } + /// ~~~~~~~~~~~~~ + /// + virtual void GetCapabilities(kodi::addon::PeripheralCapabilities& capabilities) {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Perform a scan for joysticks + /// + /// The frontend calls this when a hardware change is detected. If an add-on + /// detects a hardware change, it can trigger this function using the + /// @ref TriggerScan() callback. + /// + /// @param[in] scan_results Assigned to allocated memory + /// @return @ref PERIPHERAL_NO_ERROR if successful + /// + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_peripheral_Defs_Peripheral_Peripheral_Help + /// + virtual PERIPHERAL_ERROR PerformDeviceScan( + std::vector>& scan_results) + { + return PERIPHERAL_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get all events that have occurred since the last call to + /// @ref GetEvents(). + /// + /// @param[out] events List of available events within addon + /// @return @ref PERIPHERAL_NO_ERROR if successful + /// + /// ---------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_peripheral_Defs_Peripheral_PeripheralEvent_Help + /// + virtual PERIPHERAL_ERROR GetEvents(std::vector& events) + { + return PERIPHERAL_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Send an input event to the peripheral. + /// + /// @param[in] event The input event + /// @return true if the event was handled, false otherwise + /// + virtual bool SendEvent(const kodi::addon::PeripheralEvent& event) { return false; } + //---------------------------------------------------------------------------- + + ///@} + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_joystickOp 2. Joystick operations + /// @ingroup cpp_kodi_addon_peripheral + /// @brief %Joystick operations to handle control about. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **%Joystick parts in interface:**\n + /// Copy this to your project and extend with your parts or leave functions + /// complete away where not used or supported. + /// + /// @copydetails cpp_kodi_addon_peripheral_joystickOp_header_addon_auto_check + /// @copydetails cpp_kodi_addon_peripheral_joystickOp_source_addon_auto_check + /// + ///@{ + + //============================================================================ + /// @brief Get extended info about an attached joystick. + /// + /// @param[in] index The joystick's driver index + /// @param[out] info The container for the allocated joystick info + /// @return @ref PERIPHERAL_NO_ERROR if successful + /// + /// + /// ---------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_peripheral_Defs_Joystick_Joystick_Help + /// + virtual PERIPHERAL_ERROR GetJoystickInfo(unsigned int index, kodi::addon::Joystick& info) + { + return PERIPHERAL_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the features that allow translating the joystick into the + /// controller profile. + /// + /// @param[in] joystick The device's joystick properties; unknown values may + /// be left at their default + /// @param[in] controller_id The controller profile being requested, e.g. + /// `game.controller.default` + /// @param[out] features The array of allocated features + /// @return @ref PERIPHERAL_NO_ERROR if successful + /// + virtual PERIPHERAL_ERROR GetFeatures(const kodi::addon::Joystick& joystick, + const std::string& controller_id, + std::vector& features) + { + return PERIPHERAL_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Add or update joystick features. + /// + /// @param[in] joystick The device's joystick properties; unknown values may be + /// left at their default + /// @param[in] controller_id The game controller profile being updated + /// @param[in] features The array of features + /// @return @ref PERIPHERAL_NO_ERROR if successful + /// + virtual PERIPHERAL_ERROR MapFeatures(const kodi::addon::Joystick& joystick, + const std::string& controller_id, + const std::vector& features) + { + return PERIPHERAL_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get the driver primitives that should be ignored while mapping the + /// device. + /// + /// @param[in] joystick The device's joystick properties; unknown values may + /// be left at their default + /// @param[out] primitives The array of allocated driver primitives to be + /// ignored + /// @return @ref PERIPHERAL_NO_ERROR if successful + /// + virtual PERIPHERAL_ERROR GetIgnoredPrimitives( + const kodi::addon::Joystick& joystick, std::vector& primitives) + { + return PERIPHERAL_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Set the list of driver primitives that are ignored for the device. + /// + /// @param[in] joystick The device's joystick properties; unknown values may be left at their default + /// @param[in] primitives The array of driver primitives to ignore + /// @return @ref PERIPHERAL_NO_ERROR if successful + /// + virtual PERIPHERAL_ERROR SetIgnoredPrimitives( + const kodi::addon::Joystick& joystick, + const std::vector& primitives) + { + return PERIPHERAL_ERROR_NOT_IMPLEMENTED; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Save the button map for the given joystick. + /// + /// @param[in] joystick The device's joystick properties + /// + virtual void SaveButtonMap(const kodi::addon::Joystick& joystick) {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Revert the button map to the last time it was loaded or committed to disk + /// @param[in] joystick The device's joystick properties + /// + virtual void RevertButtonMap(const kodi::addon::Joystick& joystick) {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Reset the button map for the given joystick and controller profile ID + /// @param[in] joystick The device's joystick properties + /// @param[in] controller_id The game controller profile being reset + /// + virtual void ResetButtonMap(const kodi::addon::Joystick& joystick, + const std::string& controller_id) + { + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Powers off the given joystick if supported + /// @param[in] index The joystick's driver index + /// + virtual void PowerOffJoystick(unsigned int index) {} + //---------------------------------------------------------------------------- + + ///@} + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_callbacks 3. Callback functions + /// @ingroup cpp_kodi_addon_peripheral + /// @brief Callback to Kodi functions. + /// + ///@{ + + //============================================================================ + /// @brief Used to get the full path where the add-on is installed. + /// + /// @return The add-on installation path + /// + const std::string AddonPath() const { return m_instanceData->props->addon_path; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Used to get the full path to the add-on's user profile. + /// + /// @note The trailing folder (consisting of the add-on's ID) is not created + /// by default. If it is needed, you must call kodi::vfs::CreateDirectory() + /// to create the folder. + /// + /// @return Path to the user profile + /// + const std::string UserPath() const { return m_instanceData->props->user_path; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Trigger a scan for peripherals + /// + /// The add-on calls this if a change in hardware is detected. + /// + void TriggerScan(void) + { + return m_instanceData->toKodi->trigger_scan(m_instanceData->toKodi->kodiInstance); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Notify the frontend that button maps have changed. + /// + /// @param[in] deviceName [optional] The name of the device to refresh, or + /// empty/null for all devices + /// @param[in] controllerId [optional] The controller ID to refresh, or + /// empty/null for all controllers + /// + void RefreshButtonMaps(const std::string& deviceName = "", const std::string& controllerId = "") + { + return m_instanceData->toKodi->refresh_button_maps(m_instanceData->toKodi->kodiInstance, + deviceName.c_str(), controllerId.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Return the number of features belonging to the specified + /// controller. + /// + /// @param[in] controllerId The controller ID to enumerate + /// @param[in] type [optional] Type to filter by, or @ref JOYSTICK_FEATURE_TYPE_UNKNOWN + /// for all features + /// @return The number of features matching the request parameters + /// + unsigned int FeatureCount(const std::string& controllerId, + JOYSTICK_FEATURE_TYPE type = JOYSTICK_FEATURE_TYPE_UNKNOWN) + { + return m_instanceData->toKodi->feature_count(m_instanceData->toKodi->kodiInstance, + controllerId.c_str(), type); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Return the type of the feature. + /// + /// @param[in] controllerId The controller ID to check + /// @param[in] featureName The feature to check + /// @return The type of the specified feature, or @ref JOYSTICK_FEATURE_TYPE_UNKNOWN + /// if unknown + /// + JOYSTICK_FEATURE_TYPE FeatureType(const std::string& controllerId, const std::string& featureName) + { + return m_instanceData->toKodi->feature_type(m_instanceData->toKodi->kodiInstance, + controllerId.c_str(), featureName.c_str()); + } + //---------------------------------------------------------------------------- + + ///@} + +private: + void SetAddonStruct(KODI_HANDLE instance) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstancePeripheral: Creation with empty addon " + "structure not allowed, table must be given from Kodi!"); + + m_instanceData = static_cast(instance); + m_instanceData->toAddon->addonInstance = this; + + m_instanceData->toAddon->get_capabilities = ADDON_GetCapabilities; + m_instanceData->toAddon->perform_device_scan = ADDON_PerformDeviceScan; + m_instanceData->toAddon->free_scan_results = ADDON_FreeScanResults; + m_instanceData->toAddon->get_events = ADDON_GetEvents; + m_instanceData->toAddon->free_events = ADDON_FreeEvents; + m_instanceData->toAddon->send_event = ADDON_SendEvent; + + m_instanceData->toAddon->get_joystick_info = ADDON_GetJoystickInfo; + m_instanceData->toAddon->free_joystick_info = ADDON_FreeJoystickInfo; + m_instanceData->toAddon->get_features = ADDON_GetFeatures; + m_instanceData->toAddon->free_features = ADDON_FreeFeatures; + m_instanceData->toAddon->map_features = ADDON_MapFeatures; + m_instanceData->toAddon->get_ignored_primitives = ADDON_GetIgnoredPrimitives; + m_instanceData->toAddon->free_primitives = ADDON_FreePrimitives; + m_instanceData->toAddon->set_ignored_primitives = ADDON_SetIgnoredPrimitives; + m_instanceData->toAddon->save_button_map = ADDON_SaveButtonMap; + m_instanceData->toAddon->revert_button_map = ADDON_RevertButtonMap; + m_instanceData->toAddon->reset_button_map = ADDON_ResetButtonMap; + m_instanceData->toAddon->power_off_joystick = ADDON_PowerOffJoystick; + } + + inline static void ADDON_GetCapabilities(const AddonInstance_Peripheral* addonInstance, + PERIPHERAL_CAPABILITIES* capabilities) + { + if (!addonInstance || !capabilities) + return; + + kodi::addon::PeripheralCapabilities peripheralCapabilities(capabilities); + static_cast(addonInstance->toAddon->addonInstance) + ->GetCapabilities(peripheralCapabilities); + } + + inline static PERIPHERAL_ERROR ADDON_PerformDeviceScan( + const AddonInstance_Peripheral* addonInstance, + unsigned int* peripheral_count, + PERIPHERAL_INFO** scan_results) + { + if (!addonInstance || !peripheral_count || !scan_results) + return PERIPHERAL_ERROR_INVALID_PARAMETERS; + + std::vector> peripherals; + PERIPHERAL_ERROR err = static_cast(addonInstance->toAddon->addonInstance) + ->PerformDeviceScan(peripherals); + if (err == PERIPHERAL_NO_ERROR) + { + *peripheral_count = static_cast(peripherals.size()); + kodi::addon::Peripherals::ToStructs(peripherals, scan_results); + } + + return err; + } + + inline static void ADDON_FreeScanResults(const AddonInstance_Peripheral* addonInstance, + unsigned int peripheral_count, + PERIPHERAL_INFO* scan_results) + { + if (!addonInstance) + return; + + kodi::addon::Peripherals::FreeStructs(peripheral_count, scan_results); + } + + inline static PERIPHERAL_ERROR ADDON_GetEvents(const AddonInstance_Peripheral* addonInstance, + unsigned int* event_count, + PERIPHERAL_EVENT** events) + { + if (!addonInstance || !event_count || !events) + return PERIPHERAL_ERROR_INVALID_PARAMETERS; + + std::vector peripheralEvents; + PERIPHERAL_ERROR err = static_cast(addonInstance->toAddon->addonInstance) + ->GetEvents(peripheralEvents); + if (err == PERIPHERAL_NO_ERROR) + { + *event_count = static_cast(peripheralEvents.size()); + kodi::addon::PeripheralEvents::ToStructs(peripheralEvents, events); + } + + return err; + } + + inline static void ADDON_FreeEvents(const AddonInstance_Peripheral* addonInstance, + unsigned int event_count, + PERIPHERAL_EVENT* events) + { + if (!addonInstance) + return; + + kodi::addon::PeripheralEvents::FreeStructs(event_count, events); + } + + inline static bool ADDON_SendEvent(const AddonInstance_Peripheral* addonInstance, + const PERIPHERAL_EVENT* event) + { + if (!addonInstance || !event) + return false; + return static_cast(addonInstance->toAddon->addonInstance) + ->SendEvent(kodi::addon::PeripheralEvent(*event)); + } + + + inline static PERIPHERAL_ERROR ADDON_GetJoystickInfo( + const AddonInstance_Peripheral* addonInstance, unsigned int index, JOYSTICK_INFO* info) + { + if (!addonInstance || !info) + return PERIPHERAL_ERROR_INVALID_PARAMETERS; + + kodi::addon::Joystick addonInfo; + PERIPHERAL_ERROR err = static_cast(addonInstance->toAddon->addonInstance) + ->GetJoystickInfo(index, addonInfo); + if (err == PERIPHERAL_NO_ERROR) + { + addonInfo.ToStruct(*info); + } + + return err; + } + + inline static void ADDON_FreeJoystickInfo(const AddonInstance_Peripheral* addonInstance, + JOYSTICK_INFO* info) + { + if (!addonInstance) + return; + + kodi::addon::Joystick::FreeStruct(*info); + } + + inline static PERIPHERAL_ERROR ADDON_GetFeatures(const AddonInstance_Peripheral* addonInstance, + const JOYSTICK_INFO* joystick, + const char* controller_id, + unsigned int* feature_count, + JOYSTICK_FEATURE** features) + { + if (!addonInstance || !joystick || !controller_id || !feature_count || !features) + return PERIPHERAL_ERROR_INVALID_PARAMETERS; + + kodi::addon::Joystick addonJoystick(*joystick); + std::vector featuresVector; + + PERIPHERAL_ERROR err = static_cast(addonInstance->toAddon->addonInstance) + ->GetFeatures(addonJoystick, controller_id, featuresVector); + if (err == PERIPHERAL_NO_ERROR) + { + *feature_count = static_cast(featuresVector.size()); + kodi::addon::JoystickFeatures::ToStructs(featuresVector, features); + } + + return err; + } + + inline static void ADDON_FreeFeatures(const AddonInstance_Peripheral* addonInstance, + unsigned int feature_count, + JOYSTICK_FEATURE* features) + { + if (!addonInstance) + return; + + kodi::addon::JoystickFeatures::FreeStructs(feature_count, features); + } + + inline static PERIPHERAL_ERROR ADDON_MapFeatures(const AddonInstance_Peripheral* addonInstance, + const JOYSTICK_INFO* joystick, + const char* controller_id, + unsigned int feature_count, + const JOYSTICK_FEATURE* features) + { + if (!addonInstance || !joystick || !controller_id || (feature_count > 0 && !features)) + return PERIPHERAL_ERROR_INVALID_PARAMETERS; + + kodi::addon::Joystick addonJoystick(*joystick); + std::vector primitiveVector; + + for (unsigned int i = 0; i < feature_count; i++) + primitiveVector.emplace_back(*(features + i)); + + return static_cast(addonInstance->toAddon->addonInstance) + ->MapFeatures(addonJoystick, controller_id, primitiveVector); + } + + inline static PERIPHERAL_ERROR ADDON_GetIgnoredPrimitives( + const AddonInstance_Peripheral* addonInstance, + const JOYSTICK_INFO* joystick, + unsigned int* primitive_count, + JOYSTICK_DRIVER_PRIMITIVE** primitives) + { + if (!addonInstance || !joystick || !primitive_count || !primitives) + return PERIPHERAL_ERROR_INVALID_PARAMETERS; + + kodi::addon::Joystick addonJoystick(*joystick); + std::vector primitiveVector; + + PERIPHERAL_ERROR err = static_cast(addonInstance->toAddon->addonInstance) + ->GetIgnoredPrimitives(addonJoystick, primitiveVector); + if (err == PERIPHERAL_NO_ERROR) + { + *primitive_count = static_cast(primitiveVector.size()); + kodi::addon::DriverPrimitives::ToStructs(primitiveVector, primitives); + } + + return err; + } + + inline static void ADDON_FreePrimitives(const AddonInstance_Peripheral* addonInstance, + unsigned int primitive_count, + JOYSTICK_DRIVER_PRIMITIVE* primitives) + { + if (!addonInstance) + return; + + kodi::addon::DriverPrimitives::FreeStructs(primitive_count, primitives); + } + + inline static PERIPHERAL_ERROR ADDON_SetIgnoredPrimitives( + const AddonInstance_Peripheral* addonInstance, + const JOYSTICK_INFO* joystick, + unsigned int primitive_count, + const JOYSTICK_DRIVER_PRIMITIVE* primitives) + { + if (!addonInstance || !joystick || (primitive_count > 0 && !primitives)) + return PERIPHERAL_ERROR_INVALID_PARAMETERS; + + kodi::addon::Joystick addonJoystick(*joystick); + std::vector primitiveVector; + + for (unsigned int i = 0; i < primitive_count; i++) + primitiveVector.emplace_back(*(primitives + i)); + + return static_cast(addonInstance->toAddon->addonInstance) + ->SetIgnoredPrimitives(addonJoystick, primitiveVector); + } + + inline static void ADDON_SaveButtonMap(const AddonInstance_Peripheral* addonInstance, + const JOYSTICK_INFO* joystick) + { + if (!addonInstance || !joystick) + return; + + kodi::addon::Joystick addonJoystick(*joystick); + static_cast(addonInstance->toAddon->addonInstance) + ->SaveButtonMap(addonJoystick); + } + + inline static void ADDON_RevertButtonMap(const AddonInstance_Peripheral* addonInstance, + const JOYSTICK_INFO* joystick) + { + if (!addonInstance || !joystick) + return; + + kodi::addon::Joystick addonJoystick(*joystick); + static_cast(addonInstance->toAddon->addonInstance) + ->RevertButtonMap(addonJoystick); + } + + inline static void ADDON_ResetButtonMap(const AddonInstance_Peripheral* addonInstance, + const JOYSTICK_INFO* joystick, + const char* controller_id) + { + if (!addonInstance || !joystick || !controller_id) + return; + + kodi::addon::Joystick addonJoystick(*joystick); + static_cast(addonInstance->toAddon->addonInstance) + ->ResetButtonMap(addonJoystick, controller_id); + } + + inline static void ADDON_PowerOffJoystick(const AddonInstance_Peripheral* addonInstance, + unsigned int index) + { + if (!addonInstance) + return; + + static_cast(addonInstance->toAddon->addonInstance) + ->PowerOffJoystick(index); + } + + AddonInstance_Peripheral* m_instanceData; +}; + +} /* namespace addon */ +} /* namespace kodi */ +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Screensaver.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Screensaver.h new file mode 100644 index 0000000..4902fcb --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Screensaver.h @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../AddonBase.h" +#include "../c-api/addon-instance/screensaver.h" +#include "../gui/renderHelper.h" + +#ifdef __cplusplus +namespace kodi +{ +namespace addon +{ + +//============================================================================== +/// @addtogroup cpp_kodi_addon_screensaver +/// @brief \cpp_class{ kodi::addon::CInstanceScreensaver } +/// **Screensaver add-on instance** +/// +/// A screensaver is a Kodi addon that fills the screen with moving images or +/// patterns when the computer is not in use. Initially designed to prevent +/// phosphor burn-in on CRT and plasma computer monitors (hence the name), +/// screensavers are now used primarily for entertainment, security or to +/// display system status information. +/// +/// Include the header @ref Screensaver.h "#include " +/// to use this class. +/// +/// This interface allows the creating of screensavers for Kodi, based upon +/// **DirectX** or/and **OpenGL** rendering with `C++` code. +/// +/// The interface is small and easy usable. It has three functions: +/// +/// * Start() - Called on creation +/// * Render() - Called at render time +/// * Stop() - Called when the screensaver has no work +/// +/// Additionally, there are several \ref cpp_kodi_addon_screensaver_CB "other functions" +/// available in which the child class can ask about the current hardware, +/// including the device, display and several other parts. +/// +/// ---------------------------------------------------------------------------- +/// +/// Here is an example of what the `addon.xml.in` would look like for an +/// screensaver addon: +/// +/// ~~~~~~~~~~~~~{.xml} +/// +/// +/// @ADDON_DEPENDS@ +/// +/// +/// My screensaver addon +/// My screensaver addon description +/// @PLATFORM@ +/// +/// +/// ~~~~~~~~~~~~~ +/// +/// Description to screensaver related addon.xml values: +/// | Name | Description +/// |:------------------------------|---------------------------------------- +/// | `point` | Addon type specification
At all addon types and for this kind always "xbmc.ui.screensaver". +/// | `library_@PLATFORM@` | Sets the used library name, which is automatically set by cmake at addon build. +/// +/// @remark For more detailed description of the `addon.xml`, see also https://kodi.wiki/view/Addon.xml. +/// +/// +/// -------------------------------------------------------------------------- +/// +/// **Here is an example of the minimum required code to start a screensaver:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class CMyScreenSaver : public kodi::addon::CAddonBase, +/// public kodi::addon::CInstanceScreensaver +/// { +/// public: +/// CMyScreenSaver(); +/// +/// bool Start() override; +/// void Render() override; +/// }; +/// +/// CMyScreenSaver::CMyScreenSaver() +/// { +/// ... +/// } +/// +/// bool CMyScreenSaver::Start() +/// { +/// ... +/// return true; +/// } +/// +/// void CMyScreenSaver::Render() +/// { +/// ... +/// } +/// +/// ADDONCREATOR(CMyScreenSaver) +/// ~~~~~~~~~~~~~ +/// +/// +/// -------------------------------------------------------------------------- +/// +/// +/// **Here is another example where the screensaver is used together with +/// other instance types:** +/// +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class CMyScreenSaver : public kodi::addon::CInstanceScreensaver +/// { +/// public: +/// CMyScreenSaver(KODI_HANDLE instance, const std::string& version); +/// +/// bool Start() override; +/// void Render() override; +/// }; +/// +/// CMyScreenSaver::CMyScreenSaver(KODI_HANDLE instance, const std::string& version) +/// : CInstanceScreensaver(instance, version) +/// { +/// ... +/// } +/// +/// bool CMyScreenSaver::Start() +/// { +/// ... +/// return true; +/// } +/// +/// void CMyScreenSaver::Render() +/// { +/// ... +/// } +/// +/// +/// //---------------------------------------------------------------------- +/// +/// class CMyAddon : public kodi::addon::CAddonBase +/// { +/// public: +/// CMyAddon() = default; +/// ADDON_STATUS CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) override; +/// }; +/// +/// // If you use only one instance in your add-on, can be instanceType and +/// // instanceID ignored +/// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) +/// { +/// if (instanceType == ADDON_INSTANCE_SCREENSAVER) +/// { +/// kodi::Log(ADDON_LOG_INFO, "Creating my Screensaver"); +/// addonInstance = new CMyScreenSaver(instance, version); +/// return ADDON_STATUS_OK; +/// } +/// else if (...) +/// { +/// ... +/// } +/// return ADDON_STATUS_UNKNOWN; +/// } +/// +/// ADDONCREATOR(CMyAddon) +/// ~~~~~~~~~~~~~ +/// +/// The destruction of the example class `CMyScreenSaver` is called from +/// Kodi's header. Manually deleting the add-on instance is not required. +/// +class ATTRIBUTE_HIDDEN CInstanceScreensaver : public IAddonInstance +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver + /// @brief Screensaver class constructor. + /// + /// Used by an add-on that only supports screensavers. + /// + CInstanceScreensaver() + : IAddonInstance(ADDON_INSTANCE_SCREENSAVER, GetKodiTypeVersion(ADDON_INSTANCE_SCREENSAVER)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceScreensaver: Creation of more as one in single " + "instance way is not allowed!"); + + SetAddonStruct(CAddonBase::m_interface->firstKodiInstance); + CAddonBase::m_interface->globalSingleInstance = this; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver + /// @brief Screensaver class constructor used to support multiple instance + /// types. + /// + /// @param[in] instance The instance value given to + /// `kodi::addon::CAddonBase::CreateInstance(...)`. + /// @param[in] kodiVersion [opt] Version used in Kodi for this instance, to + /// allow compatibility to older Kodi versions. + /// + /// @note Recommended to set `kodiVersion`. + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Here's example about the use of this:** + /// ~~~~~~~~~~~~~{.cpp} + /// class CMyScreenSaver : public kodi::addon::CInstanceScreensaver + /// { + /// public: + /// CMyScreenSaver(KODI_HANDLE instance, const std::string& kodiVersion) + /// : kodi::addon::CInstanceScreensaver(instance, kodiVersion) + /// { + /// ... + /// } + /// + /// ... + /// }; + /// + /// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, + /// const std::string& instanceID, + /// KODI_HANDLE instance, + /// const std::string& version, + /// KODI_HANDLE& addonInstance) + /// { + /// kodi::Log(ADDON_LOG_INFO, "Creating my screensaver"); + /// addonInstance = new CMyScreenSaver(instance, version); + /// return ADDON_STATUS_OK; + /// } + /// ~~~~~~~~~~~~~ + /// + explicit CInstanceScreensaver(KODI_HANDLE instance, const std::string& kodiVersion = "") + : IAddonInstance(ADDON_INSTANCE_SCREENSAVER, + !kodiVersion.empty() ? kodiVersion + : GetKodiTypeVersion(ADDON_INSTANCE_SCREENSAVER)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceScreensaver: Creation of multiple together " + "with single instance way is not allowed!"); + + SetAddonStruct(instance); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver + /// @brief Destructor. + /// + ~CInstanceScreensaver() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver + /// @brief Used to notify the screensaver that it has been started. + /// + /// @return true if the screensaver was started successfully, false otherwise + /// + virtual bool Start() { return true; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver + /// @brief Used to inform the screensaver that the rendering control was + /// stopped. + /// + virtual void Stop() {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver + /// @brief Used to indicate when the add-on should render + /// + virtual void Render() {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_screensaver_CB Information functions + /// @ingroup cpp_kodi_addon_screensaver + /// @brief **To get info about the device, display and several other parts** + /// + ///@{ + + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver_CB + /// @brief Device that represents the display adapter. + /// + /// @return A pointer to the device + /// + /// @note This is only available on **DirectX**, It us unused (`nullptr`) on + /// **OpenGL** + /// + /// This value can also be becomed by @ref kodi::gui::GetHWContext() and is + /// recommended to use. + /// + ///------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// .. + /// // Note: Device() there is used inside addon child class about + /// // kodi::addon::CInstanceVisualization + /// ID3D11DeviceContext1* context = static_cast(kodi::addon::CInstanceVisualization::Device()); + /// .. + /// ~~~~~~~~~~~~~ + /// + inline kodi::HardwareContext Device() { return m_instanceData->props->device; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver_CB + /// @brief Returns the X position of the rendering window. + /// + /// @return The X position, in pixels + /// + inline int X() { return m_instanceData->props->x; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver_CB + /// @brief Returns the Y position of the rendering window. + /// + /// @return The Y position, in pixels + /// + inline int Y() { return m_instanceData->props->y; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver_CB + /// @brief Returns the width of the rendering window. + /// + /// @return The width, in pixels + /// + inline int Width() { return m_instanceData->props->width; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver_CB + /// @brief Returns the height of the rendering window. + /// + /// @return The height, in pixels + /// + inline int Height() { return m_instanceData->props->height; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver_CB + /// @brief Pixel aspect ratio (often abbreviated PAR) is a ratio that + /// describes how the width of a pixel compares to the height of that pixel. + /// + /// @return The pixel aspect ratio used by the display + /// + inline float PixelRatio() { return m_instanceData->props->pixelRatio; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver_CB + /// @brief Used to get the name of the add-on defined in `addon.xml`. + /// + /// @return The add-on name + /// + inline std::string Name() { return m_instanceData->props->name; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// + /// @ingroup cpp_kodi_addon_screensaver_CB + /// @brief Used to get the full path where the add-on is installed. + /// + /// @return The add-on installation path + /// + inline std::string Presets() { return m_instanceData->props->presets; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_screensaver_CB + /// @brief Used to get the full path to the add-on's user profile. + /// + /// @note The trailing folder (consisting of the add-on's ID) is not created + /// by default. If it is needed, you must call kodi::vfs::CreateDirectory() + /// to create the folder. + /// + /// @return Path to the user profile + /// + inline std::string Profile() { return m_instanceData->props->profile; } + //---------------------------------------------------------------------------- + + ///@} + +private: + void SetAddonStruct(KODI_HANDLE instance) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstanceScreensaver: Creation with empty addon " + "structure not allowed, table must be given from Kodi!"); + + m_instanceData = static_cast(instance); + m_instanceData->toAddon->addonInstance = this; + m_instanceData->toAddon->Start = ADDON_Start; + m_instanceData->toAddon->Stop = ADDON_Stop; + m_instanceData->toAddon->Render = ADDON_Render; + } + + inline static bool ADDON_Start(AddonInstance_Screensaver* instance) + { + CInstanceScreensaver* thisClass = + static_cast(instance->toAddon->addonInstance); + thisClass->m_renderHelper = kodi::gui::GetRenderHelper(); + return thisClass->Start(); + } + + inline static void ADDON_Stop(AddonInstance_Screensaver* instance) + { + CInstanceScreensaver* thisClass = + static_cast(instance->toAddon->addonInstance); + thisClass->Stop(); + thisClass->m_renderHelper = nullptr; + } + + inline static void ADDON_Render(AddonInstance_Screensaver* instance) + { + CInstanceScreensaver* thisClass = + static_cast(instance->toAddon->addonInstance); + + if (!thisClass->m_renderHelper) + return; + thisClass->m_renderHelper->Begin(); + thisClass->Render(); + thisClass->m_renderHelper->End(); + } + + /* + * Background render helper holds here and in addon base. + * In addon base also to have for the others, and stored here for the worst + * case where this class is independent from base and base becomes closed + * before. + * + * This is on Kodi with GL unused and the calls to there are empty (no work) + * On Kodi with Direct X where angle is present becomes this used. + */ + std::shared_ptr m_renderHelper; + AddonInstance_Screensaver* m_instanceData; +}; + +} /* namespace addon */ +} /* namespace kodi */ +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/VFS.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/VFS.h new file mode 100644 index 0000000..177bf72 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/VFS.h @@ -0,0 +1,1226 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../AddonBase.h" +#include "../Filesystem.h" +#include "../c-api/addon-instance/vfs.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace addon +{ + +class CInstanceVFS; + +//============================================================================== +/// @ingroup cpp_kodi_addon_vfs_Defs +/// @brief **VFS add-on file handle**\n +/// This used to handle opened files of addon with related memory pointer about +/// class or structure and to have on further file control functions available. +/// +/// See @ref cpp_kodi_addon_vfs_filecontrol "file editing functions" for used +/// places. +/// +///@{ +using VFSFileHandle = VFS_FILE_HANDLE; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_vfs_Defs_VFSUrl class VFSUrl +/// @ingroup cpp_kodi_addon_vfs_Defs +/// @brief **VFS add-on URL data**\n +/// This class is used to inform the addon of the desired wanted connection. +/// +/// Used on mostly all addon functions to identify related target. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_vfs_Defs_VFSUrl_Help +/// +///@{ +class ATTRIBUTE_HIDDEN VFSUrl : public CStructHdl +{ + /*! \cond PRIVATE */ + friend class CInstanceVFS; + /*! \endcond */ + +public: + /// @defgroup cpp_kodi_addon_vfs_Defs_VFSUrl_Help Value Help + /// @ingroup cpp_kodi_addon_vfs_Defs_VFSUrl + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_vfs_Defs_VFSUrl : + /// | Name | Type | Get call + /// |------|------|---------- + /// | **URL** | `std::string` | @ref VFSUrl::GetURL "GetURL" + /// | **Domain name** | `std::string` | @ref VFSUrl::GetDomain "GetDomain" + /// | **Hostname** | `std::string` | @ref VFSUrl::GetHostname "GetHostname" + /// | **Filename** | `std::string` | @ref VFSUrl::GetFilename "GetFilename" + /// | **Network port** | `unsigned int` | @ref VFSUrl::GetPort "GetPort" + /// | **Special options** | `std::string` | @ref VFSUrl::GetOptions "GetOptions" + /// | **Username** | `std::string` | @ref VFSUrl::GetUsername "GetUsername" + /// | **Password** | `std::string` | @ref VFSUrl::GetPassword "GetPassword" + /// | **Get URL with user and password hidden** | `std::string` | @ref VFSUrl::GetRedacted "GetRedacted" + /// | **Sharename** | `std::string` | @ref VFSUrl::GetSharename "GetSharename" + /// | **Network protocol** | `std::string` | @ref VFSUrl::GetProtocol "GetProtocol" + /// + + /// @addtogroup cpp_kodi_addon_vfs_Defs_VFSUrl + ///@{ + + /// @brief Desired URL of the file system to be edited + /// + /// This includes all available parts of the access and is structured as + /// follows: + /// - + /// ``://``:```@```:``/``?`` + std::string GetURL() const { return m_cStructure->url; } + + /// @brief The associated domain name, which is optional and not available + /// in all cases. + std::string GetDomain() const { return m_cStructure->domain; } + + /// @brief This includes the network address (e.g. `192.168.0.123`) or if + /// the addon refers to file packages the path to it + /// (e.g. `/home/by_me/MyPacket.rar`). + std::string GetHostname() const { return m_cStructure->hostname; } + + /// @brief With this variable the desired path to a folder or file within + /// the hostname is given (e.g. `storage/videos/00001.ts`). + std::string GetFilename() const { return m_cStructure->filename; } + + /// @brief [Networking port](https://en.wikipedia.org/wiki/Port_(computer_networking)) + /// to use for protocol. + unsigned int GetPort() const { return m_cStructure->port; } + + /// @brief Special options on opened URL, this can e.g. on RAR packages + /// `?flags=8&nextvalue=123` to inform about to not cache a read. + /// + /// Available options from Kodi: + /// | Value: | Description: + /// |-----------|------------------- + /// | flags=8 | Used on RAR packages so that no data is cached from the requested source. + /// | cache=no | Used on ZIP packages so that no data from the requested source is stored in the cache. However, this is currently not available from addons! + /// + /// In addition, other addons can use the URLs given by them to give options + /// that fit the respective VFS addon and allow special operations. + /// + /// @note This procedure is not yet standardized and is currently not + /// exactly available which are handed over. + std::string GetOptions() const { return m_cStructure->options; } + + /// @brief Desired username. + std::string GetUsername() const { return m_cStructure->username; } + + /// @brief Desired password. + std::string GetPassword() const { return m_cStructure->password; } + + /// @brief The complete URL is passed on here, but the user name and + /// password are not shown and only appear to there as `USERNAME:PASSWORD`. + /// + /// As example `sftp://USERNAME:PASSWORD@192.168.178.123/storage/videos/00001.ts`. + std::string GetRedacted() const { return m_cStructure->redacted; } + + /// @brief The name which is taken as the basis by source and would be first + /// in folder view. + /// + /// As example on `sftp://dudu:isprivate@192.168.178.123/storage/videos/00001.ts` + /// becomes then `storage` used here. + std::string GetSharename() const { return m_cStructure->sharename; } + + /// @brief Protocol name used on this stream, e.g. `sftp`. + std::string GetProtocol() const { return m_cStructure->protocol; } + + ///@} + +private: + VFSUrl() = delete; + VFSUrl(const VFSUrl& channel) = delete; + VFSUrl(const VFSURL* channel) : CStructHdl(channel) {} + VFSUrl(VFSURL* channel) : CStructHdl(channel) {} +}; +///@} +//------------------------------------------------------------------------------ + +//############################################################################## +/// @defgroup cpp_kodi_addon_vfs_Defs Definitions, structures and enumerators +/// \ingroup cpp_kodi_addon_vfs +/// @brief **VFS add-on general variables** +/// +/// Used to exchange the available options between Kodi and addon. +/// +/// + +//============================================================================== +/// +/// \addtogroup cpp_kodi_addon_vfs +/// @brief \cpp_class{ kodi::addon::CInstanceVFS } +/// **Virtual Filesystem (VFS) add-on instance** +/// +/// This instance type is used to allow Kodi various additional file system +/// types. Be it a special file system, a compressed package or a system +/// available over the network, everything is possible with it. +/// +/// This usage can be requested under various conditions, for example explicitly +/// by another addon, by a Mimetype protocol defined in `addon.xml` or supported +/// file extensions. +/// +/// Include the header @ref VFS.h "#include " +/// to use this class. +/// +/// ---------------------------------------------------------------------------- +/// +/// Here is an example of what the `addon.xml.in` would look like for an VFS addon: +/// +/// ~~~~~~~~~~~~~{.xml} +/// +/// +/// @ADDON_DEPENDS@ +/// +/// +/// My VFS addon summary +/// My VFS description +/// @PLATFORM@ +/// +/// +/// ~~~~~~~~~~~~~ +/// +/// @note Regarding boolean values with "false", these can also be omitted, +/// since this would be the default. +/// +/// +/// ### Standard values that can be declared for processing in `addon.xml`. +/// +/// These values are used by Kodi to identify associated streams and file +/// extensions and then to select the associated addon. +/// +/// \table_start +/// \table_h3{ Labels, Type, Description } +/// \table_row3{ `point`, +/// \anchor cpp_kodi_addon_vfs_point +/// string, +/// The identification of the addon instance to VFS is mandatory `kodi.vfs`. +/// In addition\, the instance declared in the first `` is also the main type of addon. +/// } +/// \table_row3{ `defaultPort`, +/// \anchor cpp_kodi_addon_vfs_defaultPort +/// integer, +/// Default [networking port](https://en.wikipedia.org/wiki/Port_(computer_networking)) +/// to use for protocol. +/// } +/// \table_row3{ `directories`, +/// \anchor cpp_kodi_addon_vfs_directories +/// boolean, +/// VFS entry can list directories. +/// } +/// \table_row3{ `extensions`, +/// \anchor cpp_kodi_addon_vfs_extensions +/// string, +/// Extensions for VFS entry.\n +/// It is possible to declare several using `|`\, e.g. `.abc|.def|.ghi`. +/// } +/// \table_row3{ `encodedhostname`, +/// \anchor cpp_kodi_addon_vfs_encodedhostname +/// boolean, +/// URL protocol from add-ons use encoded hostnames. +/// } +/// \table_row3{ `filedirectories`, +/// \anchor cpp_kodi_addon_vfs_filedirectories +/// boolean, +/// VFS entry contains file directories. +/// } +/// \table_row3{ `files`, +/// \anchor cpp_kodi_addon_vfs_directories +/// boolean, +/// Set to declare that VFS provides files. +/// } +/// \table_row3{ `protocols`, +/// \anchor cpp_kodi_addon_vfs_protocols +/// boolean, +/// Protocols for VFS entry.\n +/// It is possible to declare several using `|`\, e.g. `myprot1|myprot2`.\n +/// @note This field also used to show on GUI\, see `supportBrowsing` below about *2:. +/// When used there\, however\, only a **single** protocol is possible! +/// } +/// \table_row3{ `supportWrite`, +/// \anchor cpp_kodi_addon_vfs_supportWrite +/// boolean, +/// Protocol supports write operations. +/// } +/// \table_row3{ `zeroconf`, +/// \anchor cpp_kodi_addon_vfs_zeroconf +/// string, +/// [Zero conf](https://en.wikipedia.org/wiki/Zero-configuration_networking) announce string for VFS protocol. +/// } +/// \table_row3{ `library_@PLATFORM@`, +/// \anchor cpp_kodi_addon_vfs_library +/// string, +/// The runtime library used for the addon. This is usually declared by `cmake` and correctly displayed in the translated `addon.xml`. +/// } +/// \table_end +/// +/// +/// ### User selectable parts of the addon. +/// +/// The following table describes the values that can be defined by `addon.xml` +/// and which part they relate to for user input. +/// +/// \table_start +/// \table_h3{ Labels, Type, Description } +/// \table_row3{ `supportBrowsing`, +/// \anchor cpp_kodi_addon_vfs_protocol_supportBrowsing +/// boolean, +/// Protocol supports server browsing. Used to open related sources by users in the window.\n\n +/// | Associated places in Kodi: | +/// | :---- | +/// | \image html cpp_kodi_addon_vfs_protocol_1.png | +///
+/// *1: The entry in the menu represented by this option corresponds to the text given with `label`. +/// When the button is pressed\, @ref CInstanceVFS::GetDirectory is called on the add-on to get its content.\n +/// *2: Protocol name of the stream defined with `protocols` in xml.\n +/// @remark See also `supportDialog` about *3:. +/// } +/// \table_row3{ `supportDialog`, +/// \anchor cpp_kodi_addon_vfs_protocol_supportDialog +/// boolean, +/// To point out that Kodi assigns a dialog to this VFS in order to compare it with other values e.g. query supportPassword in it.\n +/// This will be available when adding sources in Kodi under "Add network location...".\n\n +/// | Associated places in Kodi: | +/// | :---- | +/// | \image html cpp_kodi_addon_vfs_protocol_2.png | +///
+/// *1: Field for selecting the VFS handler\, the addon will be available if `supportDialog` is set to `true`.\n +/// *2: To set the associated server address. **Note:** *This field is always activated and cannot be changed by the addon.*\n +/// *3: If `supportBrowsing` is set to `true`\, the button for opening a file selection dialog is given here too\, as in the file window.\n +/// *4: This field is available if `supportPath` is set to `true`.\n +/// *5: To edit the connection port. This field is available if `supportPort` is set to `true`.\n +/// *6: This sets the required username and is available when `supportUsername` is set to `true`.\n +/// *7: This sets the required password and is available when `supportPassword` is set to `true`. +/// } +/// \table_row3{ `supportPath`, +/// \anchor cpp_kodi_addon_vfs_protocol_supportPath +/// boolean, +/// Protocol has path in addition to server name (see `supportDialog` about *4:). +/// } +/// \table_row3{ `supportPort`, +/// \anchor cpp_kodi_addon_vfs_protocol_supportPort +/// boolean, +/// Protocol supports port customization (see `supportDialog` about *5:). +/// } +/// \table_row3{ `supportUsername`, +/// \anchor cpp_kodi_addon_vfs_protocol_supportUsername +/// boolean, +/// Protocol uses logins (see `supportDialog` about *6:). +/// } +/// \table_row3{ `supportPassword`, +/// \anchor cpp_kodi_addon_vfs_protocol_supportPassword +/// boolean, +/// Protocol supports passwords (see `supportDialog` about *7:). +/// } +/// \table_row3{ `protocols`, +/// \anchor cpp_kodi_addon_vfs_protocol_protocols +/// string, +/// Protocols for VFS entry. +/// @note This field is not editable and only used on GUI to show his name\, see `supportBrowsing` about *2: +/// } +/// \table_row3{ `label`, +/// \anchor cpp_kodi_addon_vfs_protocol_label +/// integer, +/// The text identification number used in Kodi for display in the menu at `supportDialog` +/// as a selection option and at `supportBrowsing` (see his image reference *1) as a menu entry.\n +/// This can be a text identifier in Kodi or from addon.\n +/// @remark For addon within 30000-30999 or 32000-32999. +/// } +/// \table_end +/// +/// @remark For more detailed description of the `addon.xml`, see also https://kodi.wiki/view/Addon.xml. +/// +/// +/// -------------------------------------------------------------------------- +/// +/// +/// **Example:** +/// +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class CMyVFS : public kodi::addon::CInstanceVFS +/// { +/// public: +/// CMyVFS(KODI_HANDLE instance, const std::string& kodiVersion); +/// +/// // Add all your required functions, the most CInstanceVFS functions of +/// // must be included to have addon working correctly. +/// ... +/// }; +/// +/// CMyVFS::CMyVFS(KODI_HANDLE instance, const std::string& kodiVersion) +/// : kodi::addon::CInstanceVFS(instance, kodiVersion) +/// { +/// ... +/// } +/// +/// ... +/// +/// //---------------------------------------------------------------------- +/// +/// class CMyAddon : public kodi::addon::CAddonBase +/// { +/// public: +/// CMyAddon() { } +/// ADDON_STATUS CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) override; +/// }; +/// +/// // If you use only one instance in your add-on, can be instanceType and +/// // instanceID ignored +/// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) +/// { +/// if (instanceType == ADDON_INSTANCE_VFS) +/// { +/// kodi::Log(ADDON_LOG_INFO, "Creating my VFS instance"); +/// addonInstance = new CMyVFS(instance, version); +/// return ADDON_STATUS_OK; +/// } +/// else if (...) +/// { +/// ... +/// } +/// return ADDON_STATUS_UNKNOWN; +/// } +/// +/// ADDONCREATOR(CMyAddon) +/// ~~~~~~~~~~~~~ +/// +/// The destruction of the example class `CMyVFS` is called from +/// Kodi's header. Manually deleting the add-on instance is not required. +/// +//------------------------------------------------------------------------------ +class ATTRIBUTE_HIDDEN CInstanceVFS : public IAddonInstance +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs + /// @brief VFS class constructor used to support multiple instance + /// types + /// + /// @param[in] instance The instance value given to + /// `kodi::addon::CAddonBase::CreateInstance(...)`. + /// @param[in] kodiVersion [opt] given from Kodi by @ref CAddonBase::CreateInstance + /// to identify his instance API version + /// + /// @note Instance path as a single is not supported by this type. It must + /// ensure that it can be called up several times. + /// + /// @warning Only use `instance` from the @ref CAddonBase::CreateInstance or + /// @ref CAddonBase::CreateInstance call. + /// + explicit CInstanceVFS(KODI_HANDLE instance, const std::string& kodiVersion = "") + : IAddonInstance(ADDON_INSTANCE_VFS, + !kodiVersion.empty() ? kodiVersion : GetKodiTypeVersion(ADDON_INSTANCE_VFS)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceVFS: Creation of multiple together with single " + "instance way is not allowed!"); + + SetAddonStruct(instance); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs + /// @brief Destructor + /// + ~CInstanceVFS() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_vfs_general 1. General access functions + /// @ingroup cpp_kodi_addon_vfs + /// @brief **General access functions** + /// + /// This functions which are intended for getting folders, editing storage + /// locations and file system queries. + /// + + //============================================================================ + /// @defgroup cpp_kodi_addon_vfs_filecontrol 2. File editing functions + /// @ingroup cpp_kodi_addon_vfs + /// @brief **File editing functions.** + /// + /// This value represents the addon-side handlers and to be able to identify + /// his own parts in the event of further access. + /// + + //@{ + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief Open a file for input + /// + /// @param[in] url The URL of the file + /// @return Context for the opened file + /// + /// + /// ---------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_vfs_Defs_VFSUrl_Help + /// + virtual kodi::addon::VFSFileHandle Open(const kodi::addon::VFSUrl& url) { return nullptr; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief Open a file for output + /// + /// @param[in] url The URL of the file + /// @param[in] overWrite Whether or not to overwrite an existing file + /// @return Context for the opened file + /// + virtual kodi::addon::VFSFileHandle OpenForWrite(const kodi::addon::VFSUrl& url, bool overWrite) + { + return nullptr; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief Close a file + /// + /// @param[in] context The context of the file + /// @return True on success, false on failure + /// + virtual bool Close(kodi::addon::VFSFileHandle context) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief Read from a file + /// + /// @param[in] context The context of the file + /// @param[out] buffer The buffer to read data into + /// @param[in] uiBufSize Number of bytes to read + /// @return Number of bytes read + /// + virtual ssize_t Read(kodi::addon::VFSFileHandle context, uint8_t* buffer, size_t uiBufSize) + { + return -1; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief Write to a file + /// + /// @param[in] context The context of the file + /// @param[in] buffer The buffer to read data from + /// @param[in] uiBufSize Number of bytes to write + /// @return Number of bytes written + /// + virtual ssize_t Write(kodi::addon::VFSFileHandle context, const uint8_t* buffer, size_t uiBufSize) + { + return -1; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief Seek in a file + /// + /// @param[in] context The context of the file + /// @param[in] position The position to seek to + /// @param[in] whence Position in file 'position' is relative to (SEEK_CUR, SEEK_SET, SEEK_END): + /// | Value | int | Description | + /// |:--------:|:---:|:----------------------------------------------------| + /// | SEEK_SET | 0 | position is relative to the beginning of the file. This is probably what you had in mind anyway, and is the most commonly used value for whence. + /// | SEEK_CUR | 1 | position is relative to the current file pointer position. So, in effect, you can say, "Move to my current position plus 30 bytes," or, "move to my current position minus 20 bytes." + /// | SEEK_END | 2 | position is relative to the end of the file. Just like SEEK_SET except from the other end of the file. Be sure to use negative values for offset if you want to back up from the end of the file, instead of going past the end into oblivion. + /// @return Offset in file after seek + /// + virtual int64_t Seek(kodi::addon::VFSFileHandle context, int64_t position, int whence) + { + return -1; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief Truncate a file + /// + /// @param[in] context The context of the file + /// @param[in] size The size to truncate the file to + /// @return 0 on success, -1 on error + /// + virtual int Truncate(kodi::addon::VFSFileHandle context, int64_t size) { return -1; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief Get total size of a file + /// + /// @param[in] context The context of the file + /// @return Total file size + /// + virtual int64_t GetLength(kodi::addon::VFSFileHandle context) { return 0; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief Get current position in a file + /// + /// @param[in] context The context of the file + /// @return Current position + /// + virtual int64_t GetPosition(kodi::addon::VFSFileHandle context) { return 0; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief Get chunk size of a file + /// + /// @param[in] context The context of the file + /// @return Chunk size + /// + virtual int GetChunkSize(kodi::addon::VFSFileHandle context) { return 1; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief To check seek possible on current stream by file. + /// + /// @return true if seek possible, false if not + /// + virtual bool IoControlGetSeekPossible(kodi::addon::VFSFileHandle context) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief To check a running stream on file for state of his cache. + /// + /// @param[in] status Information about current cache status + /// @return true if successfull done, false otherwise + /// + /// + /// @copydetails cpp_kodi_vfs_Defs_CacheStatus_Help + /// + virtual bool IoControlGetCacheStatus(kodi::addon::VFSFileHandle context, + kodi::vfs::CacheStatus& status) + { + return false; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief Unsigned int with speed limit for caching in bytes per second. + /// + /// @param[in] rate Cache rate size to use + /// @return true if successfull done, false otherwise + /// + virtual bool IoControlSetCacheRate(kodi::addon::VFSFileHandle context, unsigned int rate) + { + return false; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_filecontrol + /// @brief Enable/disable retry within the protocol handler (if supported). + /// + /// @param[in] retry To set the retry, true for use, false for not + /// @return true if successfull done, false otherwise + /// + virtual bool IoControlSetRetry(kodi::addon::VFSFileHandle context, bool retry) { return false; } + //---------------------------------------------------------------------------- + //@} + + //@{ + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_general + /// @brief Stat a file + /// + /// @param[in] url The URL of the file + /// @param[in] buffer The buffer to store results in + /// @return -1 on error, 0 otherwise + /// + /// + /// ---------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_vfs_Defs_VFSUrl_Help + /// + virtual int Stat(const kodi::addon::VFSUrl& url, kodi::vfs::FileStatus& buffer) { return 0; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_general + /// @brief Check for file existence + /// + /// @param[in] url The URL of the file + /// @return True if file exists, false otherwise + /// + virtual bool Exists(const kodi::addon::VFSUrl& url) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_general + /// @brief Clear out any idle connections + /// + virtual void ClearOutIdle() {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_general + /// @brief Disconnect all connections + /// + virtual void DisconnectAll() {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_general + /// @brief Delete a file + /// + /// @param[in] url The URL of the file + /// @return True if deletion was successful, false otherwise + /// + virtual bool Delete(const kodi::addon::VFSUrl& url) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_general + /// @brief Rename a file + /// + /// @param[in] url The URL of the source file + /// @param[in] url2 The URL of the destination file + /// @return True if deletion was successful, false otherwise + /// + virtual bool Rename(const kodi::addon::VFSUrl& url, const kodi::addon::VFSUrl& url2) + { + return false; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_general + /// @brief Check for directory existence + /// + /// @param[in] url The URL of the file + /// @return True if directory exists, false otherwise + /// + virtual bool DirectoryExists(const kodi::addon::VFSUrl& url) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_general + /// @brief Remove a directory + /// + /// @param[in] url The URL of the directory + /// @return True if removal was successful, false otherwise + /// + virtual bool RemoveDirectory(const kodi::addon::VFSUrl& url) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_general + /// @brief Create a directory + /// + /// @param[in] url The URL of the file + /// @return True if creation was successful, false otherwise + /// + virtual bool CreateDirectory(const kodi::addon::VFSUrl& url) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_vfs_general_cb_GetDirectory Callbacks GetDirectory() + /// @ingroup cpp_kodi_addon_vfs_general + /// @brief Callback functions on GetDirectory() + /// + /// This functions becomes available during call of GetDirectory() from + /// Kodi. + /// + /// If GetDirectory() returns false becomes the parts from here used on + /// next call of the function. + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// + /// #include + /// + /// ... + /// + /// bool CMyVFS::GetDirectory(const kodi::addon::VFSUrl& url, + /// std::vector& items, + /// CVFSCallbacks callbacks) + /// { + /// std::string neededString; + /// callbacks.GetKeyboardInput("Test", neededString, true); + /// if (neededString.empty()) + /// return false; + /// + /// // Do the work + /// ... + /// return true; + /// } + /// ~~~~~~~~~~~~~ + /// + class CVFSCallbacks + { + public: + /// @ingroup cpp_kodi_addon_vfs_general_cb_GetDirectory + /// @brief Require keyboard input + /// + /// Becomes called if GetDirectory() returns false and GetDirectory() + /// becomes after entry called again. + /// + /// @param[in] heading The heading of the keyboard dialog + /// @param[out] input The resulting string. Returns string after + /// second call! + /// @param[in] hiddenInput To show input only as "*" on dialog + /// @return True if input was received, false otherwise + /// + bool GetKeyboardInput(const std::string& heading, std::string& input, bool hiddenInput = false) + { + char* cInput = nullptr; + bool ret = m_cb->get_keyboard_input(m_cb->ctx, heading.c_str(), &cInput, hiddenInput); + if (cInput) + { + input = cInput; + ::kodi::addon::CAddonBase::m_interface->toKodi->free_string( + ::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase, cInput); + } + return ret; + } + + /// @ingroup cpp_kodi_addon_vfs_general_cb_GetDirectory + /// @brief Display an error dialog + /// + /// @param[in] heading The heading of the error dialog + /// @param[in] line1 The first line of the error dialog + /// @param[in] line2 [opt] The second line of the error dialog + /// @param[in] line3 [opt] The third line of the error dialog + /// + void SetErrorDialog(const std::string& heading, + const std::string& line1, + const std::string& line2 = "", + const std::string& line3 = "") + { + m_cb->set_error_dialog(m_cb->ctx, heading.c_str(), line1.c_str(), line2.c_str(), + line3.c_str()); + } + + /// @ingroup cpp_kodi_addon_vfs_general_cb_GetDirectory + /// @brief Prompt the user for authentication of a URL + /// + /// @param[in] url The URL + void RequireAuthentication(const std::string& url) + { + m_cb->require_authentication(m_cb->ctx, url.c_str()); + } + + explicit CVFSCallbacks(const VFSGetDirectoryCallbacks* cb) : m_cb(cb) {} + + private: + const VFSGetDirectoryCallbacks* m_cb; + }; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_general + /// @brief List a directory + /// + /// @param[in] url The URL of the directory + /// @param[out] entries The entries in the directory, see + /// @ref cpp_kodi_vfs_CDirEntry "kodi::vfs::CDirEntry" + /// about his content + /// @param[in] callbacks A callback structure + /// @return Context for the directory listing + /// + /// + /// -------------------------------------------------------------------------- + /// + /// ### Callbacks: + /// @copydetails cpp_kodi_addon_vfs_general_cb_GetDirectory + /// + /// **Available callback functions** + /// | Function: | Description + /// |--|-- + /// | CVFSCallbacks::GetKeyboardInput | @copybrief CVFSCallbacks::GetKeyboardInput @copydetails CVFSCallbacks::GetKeyboardInput + /// | CVFSCallbacks::SetErrorDialog | @copybrief CVFSCallbacks::SetErrorDialog @copydetails CVFSCallbacks::SetErrorDialog + /// | CVFSCallbacks::RequireAuthentication | @copybrief CVFSCallbacks::RequireAuthentication @copydetails CVFSCallbacks::RequireAuthentication + /// + virtual bool GetDirectory(const kodi::addon::VFSUrl& url, + std::vector& entries, + CVFSCallbacks callbacks) + { + return false; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_vfs_general + /// @brief Check if file should be presented as a directory (multiple streams) + /// + /// @param[in] url The URL of the file + /// @param[out] entries The entries in the directory, see + /// @ref cpp_kodi_vfs_CDirEntry "kodi::vfs::CDirEntry" + /// about his content + /// @param[out] rootPath Path to root directory if multiple entries + /// @return Context for the directory listing + /// + virtual bool ContainsFiles(const kodi::addon::VFSUrl& url, + std::vector& entries, + std::string& rootPath) + { + return false; + } + //---------------------------------------------------------------------------- + //@} + +private: + void SetAddonStruct(KODI_HANDLE instance) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstanceVFS: Creation with empty addon structure not " + "allowed, table must be given from Kodi!"); + + m_instanceData = static_cast(instance); + m_instanceData->toAddon->addonInstance = this; + m_instanceData->toAddon->open = ADDON_Open; + m_instanceData->toAddon->open_for_write = ADDON_OpenForWrite; + m_instanceData->toAddon->read = ADDON_Read; + m_instanceData->toAddon->write = ADDON_Write; + m_instanceData->toAddon->seek = ADDON_Seek; + m_instanceData->toAddon->truncate = ADDON_Truncate; + m_instanceData->toAddon->get_length = ADDON_GetLength; + m_instanceData->toAddon->get_position = ADDON_GetPosition; + m_instanceData->toAddon->get_chunk_size = ADDON_GetChunkSize; + m_instanceData->toAddon->io_control_get_seek_possible = ADDON_IoControlGetSeekPossible; + m_instanceData->toAddon->io_control_get_cache_status = ADDON_IoControlGetCacheStatus; + m_instanceData->toAddon->io_control_set_cache_rate = ADDON_IoControlSetCacheRate; + m_instanceData->toAddon->io_control_set_retry = ADDON_IoControlSetRetry; + m_instanceData->toAddon->stat = ADDON_Stat; + m_instanceData->toAddon->close = ADDON_Close; + m_instanceData->toAddon->exists = ADDON_Exists; + m_instanceData->toAddon->clear_out_idle = ADDON_ClearOutIdle; + m_instanceData->toAddon->disconnect_all = ADDON_DisconnectAll; + m_instanceData->toAddon->delete_it = ADDON_Delete; + m_instanceData->toAddon->rename = ADDON_Rename; + m_instanceData->toAddon->directory_exists = ADDON_DirectoryExists; + m_instanceData->toAddon->remove_directory = ADDON_RemoveDirectory; + m_instanceData->toAddon->create_directory = ADDON_CreateDirectory; + m_instanceData->toAddon->get_directory = ADDON_GetDirectory; + m_instanceData->toAddon->free_directory = ADDON_FreeDirectory; + m_instanceData->toAddon->contains_files = ADDON_ContainsFiles; + } + + inline static VFS_FILE_HANDLE ADDON_Open(const AddonInstance_VFSEntry* instance, + const VFSURL* url) + { + return static_cast(instance->toAddon->addonInstance)->Open(url); + } + + inline static VFS_FILE_HANDLE ADDON_OpenForWrite(const AddonInstance_VFSEntry* instance, + const VFSURL* url, + bool overWrite) + { + return static_cast(instance->toAddon->addonInstance) + ->OpenForWrite(url, overWrite); + } + + inline static ssize_t ADDON_Read(const AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + uint8_t* buffer, + size_t uiBufSize) + { + return static_cast(instance->toAddon->addonInstance) + ->Read(context, buffer, uiBufSize); + } + + inline static ssize_t ADDON_Write(const AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + const uint8_t* buffer, + size_t uiBufSize) + { + return static_cast(instance->toAddon->addonInstance) + ->Write(context, buffer, uiBufSize); + } + + inline static int64_t ADDON_Seek(const AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + int64_t position, + int whence) + { + return static_cast(instance->toAddon->addonInstance) + ->Seek(context, position, whence); + } + + inline static int ADDON_Truncate(const AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + int64_t size) + { + return static_cast(instance->toAddon->addonInstance)->Truncate(context, size); + } + + inline static int64_t ADDON_GetLength(const AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context) + { + return static_cast(instance->toAddon->addonInstance)->GetLength(context); + } + + inline static int64_t ADDON_GetPosition(const AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context) + { + return static_cast(instance->toAddon->addonInstance)->GetPosition(context); + } + + inline static int ADDON_GetChunkSize(const AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context) + { + return static_cast(instance->toAddon->addonInstance)->GetChunkSize(context); + } + + inline static bool ADDON_IoControlGetSeekPossible(const AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context) + { + return static_cast(instance->toAddon->addonInstance) + ->IoControlGetSeekPossible(context); + } + + inline static bool ADDON_IoControlGetCacheStatus(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + VFS_CACHE_STATUS_DATA* status) + { + kodi::vfs::CacheStatus cppStatus(status); + return static_cast(instance->toAddon->addonInstance) + ->IoControlGetCacheStatus(context, cppStatus); + } + + inline static bool ADDON_IoControlSetCacheRate(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + unsigned int rate) + { + return static_cast(instance->toAddon->addonInstance) + ->IoControlSetCacheRate(context, rate); + } + + inline static bool ADDON_IoControlSetRetry(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + bool retry) + { + return static_cast(instance->toAddon->addonInstance) + ->IoControlSetRetry(context, retry); + } + + inline static int ADDON_Stat(const AddonInstance_VFSEntry* instance, + const VFSURL* url, + struct STAT_STRUCTURE* buffer) + { + kodi::vfs::FileStatus cppBuffer(buffer); + return static_cast(instance->toAddon->addonInstance)->Stat(url, cppBuffer); + } + + inline static bool ADDON_Close(const AddonInstance_VFSEntry* instance, VFS_FILE_HANDLE context) + { + return static_cast(instance->toAddon->addonInstance)->Close(context); + } + + inline static bool ADDON_Exists(const AddonInstance_VFSEntry* instance, const VFSURL* url) + { + return static_cast(instance->toAddon->addonInstance)->Exists(url); + } + + inline static void ADDON_ClearOutIdle(const AddonInstance_VFSEntry* instance) + { + return static_cast(instance->toAddon->addonInstance)->ClearOutIdle(); + } + + inline static void ADDON_DisconnectAll(const AddonInstance_VFSEntry* instance) + { + return static_cast(instance->toAddon->addonInstance)->DisconnectAll(); + } + + inline static bool ADDON_Delete(const AddonInstance_VFSEntry* instance, const VFSURL* url) + { + return static_cast(instance->toAddon->addonInstance)->Delete(url); + } + + inline static bool ADDON_Rename(const AddonInstance_VFSEntry* instance, + const VFSURL* url, + const VFSURL* url2) + { + return static_cast(instance->toAddon->addonInstance)->Rename(url, url2); + } + + inline static bool ADDON_DirectoryExists(const AddonInstance_VFSEntry* instance, + const VFSURL* url) + { + return static_cast(instance->toAddon->addonInstance)->DirectoryExists(url); + } + + inline static bool ADDON_RemoveDirectory(const AddonInstance_VFSEntry* instance, + const VFSURL* url) + { + return static_cast(instance->toAddon->addonInstance)->RemoveDirectory(url); + } + + inline static bool ADDON_CreateDirectory(const AddonInstance_VFSEntry* instance, + const VFSURL* url) + { + return static_cast(instance->toAddon->addonInstance)->CreateDirectory(url); + } + + inline static bool ADDON_GetDirectory(const AddonInstance_VFSEntry* instance, + const VFSURL* url, + VFSDirEntry** retEntries, + int* num_entries, + VFSGetDirectoryCallbacks* callbacks) + { + std::vector addonEntries; + bool ret = static_cast(instance->toAddon->addonInstance) + ->GetDirectory(url, addonEntries, CVFSCallbacks(callbacks)); + if (ret) + { + VFSDirEntry* entries = + static_cast(malloc(sizeof(VFSDirEntry) * addonEntries.size())); + for (unsigned int i = 0; i < addonEntries.size(); ++i) + { + entries[i].label = strdup(addonEntries[i].Label().c_str()); + entries[i].title = strdup(addonEntries[i].Title().c_str()); + entries[i].path = strdup(addonEntries[i].Path().c_str()); + entries[i].folder = addonEntries[i].IsFolder(); + entries[i].size = addonEntries[i].Size(); + entries[i].date_time = addonEntries[i].DateTime(); + + entries[i].num_props = 0; + const std::map& props = addonEntries[i].GetProperties(); + if (!props.empty()) + { + entries[i].properties = + static_cast(malloc(sizeof(VFSProperty) * props.size())); + for (const auto& prop : props) + { + entries[i].properties[entries[i].num_props].name = strdup(prop.first.c_str()); + entries[i].properties[entries[i].num_props].val = strdup(prop.second.c_str()); + ++entries[i].num_props; + } + } + else + entries[i].properties = nullptr; + } + *retEntries = entries; + *num_entries = static_cast(addonEntries.size()); + } + return ret; + } + + inline static void ADDON_FreeDirectory(const AddonInstance_VFSEntry* instance, + VFSDirEntry* entries, + int num_entries) + { + for (int i = 0; i < num_entries; ++i) + { + if (entries[i].properties) + { + for (unsigned int j = 0; j < entries[i].num_props; ++j) + { + free(entries[i].properties[j].name); + free(entries[i].properties[j].val); + } + free(entries[i].properties); + } + free(entries[i].label); + free(entries[i].title); + free(entries[i].path); + } + free(entries); + } + + inline static bool ADDON_ContainsFiles(const AddonInstance_VFSEntry* instance, + const VFSURL* url, + VFSDirEntry** retEntries, + int* num_entries, + char* rootpath) + { + std::string cppRootPath; + std::vector addonEntries; + bool ret = static_cast(instance->toAddon->addonInstance) + ->ContainsFiles(url, addonEntries, cppRootPath); + if (ret) + { + strncpy(rootpath, cppRootPath.c_str(), ADDON_STANDARD_STRING_LENGTH); + + VFSDirEntry* entries = + static_cast(malloc(sizeof(VFSDirEntry) * addonEntries.size())); + for (size_t i = 0; i < addonEntries.size(); ++i) + { + entries[i].label = strdup(addonEntries[i].Label().c_str()); + entries[i].title = strdup(addonEntries[i].Title().c_str()); + entries[i].path = strdup(addonEntries[i].Path().c_str()); + entries[i].folder = addonEntries[i].IsFolder(); + entries[i].size = addonEntries[i].Size(); + entries[i].date_time = addonEntries[i].DateTime(); + + entries[i].num_props = 0; + const std::map& props = addonEntries[i].GetProperties(); + if (!props.empty()) + { + entries[i].properties = + static_cast(malloc(sizeof(VFSProperty) * props.size())); + for (const auto& prop : props) + { + entries[i].properties[entries[i].num_props].name = strdup(prop.first.c_str()); + entries[i].properties[entries[i].num_props].val = strdup(prop.second.c_str()); + ++entries[i].num_props; + } + } + else + entries[i].properties = nullptr; + } + *retEntries = entries; + *num_entries = static_cast(addonEntries.size()); + } + return ret; + } + + AddonInstance_VFSEntry* m_instanceData; +}; + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/VideoCodec.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/VideoCodec.h new file mode 100644 index 0000000..12893db --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/VideoCodec.h @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../AddonBase.h" +#include "../StreamCrypto.h" +#include "../StreamCodec.h" + +#ifdef BUILD_KODI_ADDON +#include "../DemuxPacket.h" +#else +#include "cores/VideoPlayer/Interface/Addon/DemuxPacket.h" +#endif + +extern "C" +{ + enum VIDEOCODEC_FORMAT + { + UnknownVideoFormat = 0, + VideoFormatYV12, + VideoFormatI420, + MaxVideoFormats + }; + + + struct VIDEOCODEC_INITDATA + { + enum Codec { + CodecUnknown = 0, + CodecVp8, + CodecH264, + CodecVp9 + } codec; + + STREAMCODEC_PROFILE codecProfile; + + //UnknownVideoFormat is terminator + VIDEOCODEC_FORMAT *videoFormats; + + uint32_t width, height; + + const uint8_t *extraData; + unsigned int extraDataSize; + + CRYPTO_INFO cryptoInfo; + }; + + struct VIDEOCODEC_PICTURE + { + enum VideoPlane { + YPlane = 0, + UPlane, + VPlane, + MaxPlanes = 3, + }; + + enum Flags : uint32_t { + FLAG_DROP, + FLAG_DRAIN + }; + + VIDEOCODEC_FORMAT videoFormat; + uint32_t flags; + + uint32_t width, height; + + uint8_t *decodedData; + size_t decodedDataSize; + + uint32_t planeOffsets[VideoPlane::MaxPlanes]; + uint32_t stride[VideoPlane::MaxPlanes]; + + int64_t pts; + + KODI_HANDLE videoBufferHandle; //< will be passed in release_frame_buffer + }; + + enum VIDEOCODEC_RETVAL + { + VC_NONE = 0, //< noop + VC_ERROR, //< an error occurred, no other messages will be returned + VC_BUFFER, //< the decoder needs more data + VC_PICTURE, //< the decoder got a picture + VC_EOF, //< the decoder signals EOF + }; + + // this are properties given to the addon on create + // at this time we have no parameters for the addon + typedef struct AddonProps_VideoCodec + { + int dummy; + } AddonProps_VideoCodec; + + struct AddonInstance_VideoCodec; + typedef struct KodiToAddonFuncTable_VideoCodec + { + KODI_HANDLE addonInstance; + + //! \brief Opens a codec + bool (__cdecl* open) (const AddonInstance_VideoCodec* instance, VIDEOCODEC_INITDATA *initData); + + //! \brief Reconfigures a codec + bool (__cdecl* reconfigure) (const AddonInstance_VideoCodec* instance, VIDEOCODEC_INITDATA *initData); + + //! \brief Feed codec if requested from GetPicture() (return VC_BUFFER) + bool (__cdecl* add_data) (const AddonInstance_VideoCodec* instance, const DemuxPacket *packet); + + //! \brief Get a decoded picture / request new data + VIDEOCODEC_RETVAL (__cdecl* get_picture) (const AddonInstance_VideoCodec* instance, VIDEOCODEC_PICTURE *picture); + + //! \brief Get the name of this video decoder + const char *(__cdecl* get_name) (const AddonInstance_VideoCodec* instance); + + //! \brief Reset the codec + void (__cdecl* reset)(const AddonInstance_VideoCodec* instance); + } KodiToAddonFuncTable_VideoCodec; + + typedef struct AddonToKodiFuncTable_VideoCodec + { + KODI_HANDLE kodiInstance; + bool(*get_frame_buffer)(void* kodiInstance, VIDEOCODEC_PICTURE *picture); + void(*release_frame_buffer)(void* kodiInstance, void *buffer); + } AddonToKodiFuncTable_VideoCodec; + + typedef struct AddonInstance_VideoCodec + { + AddonProps_VideoCodec* props; + AddonToKodiFuncTable_VideoCodec* toKodi; + KodiToAddonFuncTable_VideoCodec* toAddon; + } AddonInstance_VideoCodec; +} + +namespace kodi +{ + namespace addon + { + + class ATTRIBUTE_HIDDEN CInstanceVideoCodec : public IAddonInstance + { + public: + explicit CInstanceVideoCodec(KODI_HANDLE instance, const std::string& kodiVersion = "") + : IAddonInstance(ADDON_INSTANCE_VIDEOCODEC, + !kodiVersion.empty() ? kodiVersion + : GetKodiTypeVersion(ADDON_INSTANCE_VIDEOCODEC)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceVideoCodec: Creation of multiple together with single instance way is not allowed!"); + + SetAddonStruct(instance); + } + + ~CInstanceVideoCodec() override = default; + + //! \copydoc CInstanceVideoCodec::Open + virtual bool Open(VIDEOCODEC_INITDATA &initData) { return false; }; + + //! \copydoc CInstanceVideoCodec::Reconfigure + virtual bool Reconfigure(VIDEOCODEC_INITDATA &initData) { return false; }; + + //! \copydoc CInstanceVideoCodec::AddData + virtual bool AddData(const DemuxPacket &packet) { return false; }; + + //! \copydoc CInstanceVideoCodec::GetPicture + virtual VIDEOCODEC_RETVAL GetPicture(VIDEOCODEC_PICTURE &picture) { return VC_ERROR; }; + + //! \copydoc CInstanceVideoCodec::GetName + virtual const char *GetName() { return nullptr; }; + + //! \copydoc CInstanceVideoCodec::Reset + virtual void Reset() {}; + + /*! + * @brief AddonToKodi interface + */ + + //! \copydoc CInstanceVideoCodec::GetFrameBuffer + bool GetFrameBuffer(VIDEOCODEC_PICTURE &picture) + { + return m_instanceData->toKodi->get_frame_buffer(m_instanceData->toKodi->kodiInstance, + &picture); + } + + //! \copydoc CInstanceVideoCodec::ReleaseFrameBuffer + void ReleaseFrameBuffer(void *buffer) + { + return m_instanceData->toKodi->release_frame_buffer(m_instanceData->toKodi->kodiInstance, + buffer); + } + + private: + void SetAddonStruct(KODI_HANDLE instance) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstanceVideoCodec: Creation with empty addon structure not allowed, table must be given from Kodi!"); + + m_instanceData = static_cast(instance); + + m_instanceData->toAddon->addonInstance = this; + m_instanceData->toAddon->open = ADDON_Open; + m_instanceData->toAddon->reconfigure = ADDON_Reconfigure; + m_instanceData->toAddon->add_data = ADDON_AddData; + m_instanceData->toAddon->get_picture = ADDON_GetPicture; + m_instanceData->toAddon->get_name = ADDON_GetName; + m_instanceData->toAddon->reset = ADDON_Reset; + } + + inline static bool ADDON_Open(const AddonInstance_VideoCodec* instance, VIDEOCODEC_INITDATA *initData) + { + return static_cast(instance->toAddon->addonInstance)->Open(*initData); + } + + inline static bool ADDON_Reconfigure(const AddonInstance_VideoCodec* instance, VIDEOCODEC_INITDATA *initData) + { + return static_cast(instance->toAddon->addonInstance) + ->Reconfigure(*initData); + } + + inline static bool ADDON_AddData(const AddonInstance_VideoCodec* instance, const DemuxPacket *packet) + { + return static_cast(instance->toAddon->addonInstance) + ->AddData(*packet); + } + + inline static VIDEOCODEC_RETVAL ADDON_GetPicture(const AddonInstance_VideoCodec* instance, VIDEOCODEC_PICTURE *picture) + { + return static_cast(instance->toAddon->addonInstance) + ->GetPicture(*picture); + } + + inline static const char *ADDON_GetName(const AddonInstance_VideoCodec* instance) + { + return static_cast(instance->toAddon->addonInstance)->GetName(); + } + + inline static void ADDON_Reset(const AddonInstance_VideoCodec* instance) + { + return static_cast(instance->toAddon->addonInstance)->Reset(); + } + + AddonInstance_VideoCodec* m_instanceData; + }; + } // namespace addon +} // namespace kodi diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Visualization.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Visualization.h new file mode 100644 index 0000000..7b1db65 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/Visualization.h @@ -0,0 +1,992 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../AddonBase.h" +#include "../c-api/addon-instance/visualization.h" +#include "../gui/renderHelper.h" + +#ifdef __cplusplus +namespace kodi +{ +namespace addon +{ + + +//============================================================================== +/// @defgroup cpp_kodi_addon_visualization_Defs_VisualizationTrack class VisualizationTrack +/// @ingroup cpp_kodi_addon_visualization_Defs +/// @brief **Info tag data structure**\n +/// Representation of available information of processed audio file. +/// +/// This is used to store all the necessary data of audio stream and to have on +/// e.g. GUI for information. +/// +/// Called from @ref kodi::addon::CInstanceVisualization::UpdateTrack() with the +/// information of the currently-playing song. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_visualization_Defs_VisualizationTrack_Help +/// +///@{ +class VisualizationTrack +{ + /*! \cond PRIVATE */ + friend class CInstanceVisualization; + /*! \endcond */ + +public: + /*! \cond PRIVATE */ + VisualizationTrack() = default; + VisualizationTrack(const VisualizationTrack& tag) + { + *this = tag; + } + + VisualizationTrack& operator=(const VisualizationTrack& right) + { + if (&right == this) + return *this; + + m_title = right.m_title; + m_artist = right.m_artist; + m_album = right.m_album; + m_albumArtist = right.m_albumArtist; + m_genre = right.m_genre; + m_comment = right.m_comment; + m_lyrics = right.m_lyrics; + + m_trackNumber = right.m_trackNumber; + m_discNumber = right.m_discNumber; + m_duration = right.m_duration; + m_year = right.m_year; + m_rating = right.m_rating; + return *this; + } + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_visualization_Defs_VisualizationTrack_Help Value Help + /// @ingroup cpp_kodi_addon_visualization_Defs_VisualizationTrack + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_visualization_Defs_VisualizationTrack : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **Title of the current song.** | `std::string` | @ref VisualizationTrack::SetTitle "SetTitle" | @ref VisualizationTrack::GetTitle "GetTitle" + /// | **Artist names, as a single string** | `std::string` | @ref VisualizationTrack::SetArtist "SetArtist" | @ref VisualizationTrack::GetArtist "GetArtist" + /// | **Album that the current song is from.** | `std::string` | @ref VisualizationTrack::SetAlbum "SetAlbum" | @ref VisualizationTrack::GetAlbum "GetAlbum" + /// | **Album artist names, as a single string** | `std::string` | @ref VisualizationTrack::SetAlbumArtist "SetAlbumArtist" | @ref VisualizationTrack::GetAlbumArtist "GetAlbumArtist" + /// | **The genre name from the music tag, if present** | `std::string` | @ref VisualizationTrack::SetGenre "SetGenre" | @ref VisualizationTrack::GetGenre "GetGenre" + /// | **Duration of the current song, in seconds** | `int` | @ref VisualizationTrack::SetDuration "SetDuration" | @ref VisualizationTrack::GetDuration "GetDuration" + /// | **Track number of the current song** | `int` | @ref VisualizationTrack::SetTrack "SetTrack" | @ref VisualizationTrack::GetTrack "GetTrack" + /// | **Disc number of the current song stored in the ID tag info** | `int` | @ref VisualizationTrack::SetDisc "SetDisc" | @ref VisualizationTrack::GetDisc "GetDisc" + /// | **Year that the current song was released** | `int` | @ref VisualizationTrack::SetYear "SetYear" | @ref VisualizationTrack::GetYear "GetYear" + /// | **Lyrics of the current song, if available** | `std::string` | @ref VisualizationTrack::SetLyrics "SetLyrics" | @ref VisualizationTrack::GetLyrics "GetLyrics" + /// | **The user-defined rating of the current song** | `int` | @ref VisualizationTrack::SetRating "SetRating" | @ref VisualizationTrack::GetRating "GetRating" + /// | **Comment of the current song stored in the ID tag info** | `std::string` | @ref VisualizationTrack::SetComment "SetComment" | @ref VisualizationTrack::GetComment "GetComment" + /// + + /// @addtogroup cpp_kodi_addon_visualization_Defs_VisualizationTrack + ///@{ + + /// @brief Set title of the current song. + void SetTitle(const std::string& title) { m_title = title; } + + /// @brief Get title of the current song. + const std::string& GetTitle() const { return m_title; } + + /// @brief Set artist names, as a single string- + void SetArtist(const std::string& artist) { m_artist = artist; } + + /// @brief Get artist names, as a single string- + const std::string& GetArtist() const { return m_artist; } + + /// @brief Set Album that the current song is from. + void SetAlbum(const std::string& album) { m_album = album; } + + /// @brief Get Album that the current song is from. + const std::string& GetAlbum() const { return m_album; } + + /// @brief Set album artist names, as a single stringalbum artist name + void SetAlbumArtist(const std::string& albumArtist) { m_albumArtist = albumArtist; } + + /// @brief Get album artist names, as a single string- + const std::string& GetAlbumArtist() const { return m_albumArtist; } + + /// @brief Set genre name from music as string if present. + void SetGenre(const std::string& genre) { m_genre = genre; } + + /// @brief Get genre name from music as string if present. + const std::string& GetGenre() const { return m_genre; } + + /// @brief Set the duration of music as integer from info. + void SetDuration(int duration) { m_duration = duration; } + + /// @brief Get the duration of music as integer from info. + int GetDuration() const { return m_duration; } + + /// @brief Set track number (if present) from music info as integer. + void SetTrack(int trackNumber) { m_trackNumber = trackNumber; } + + /// @brief Get track number (if present). + int GetTrack() const { return m_trackNumber; } + + /// @brief Set disk number (if present) from music info as integer. + void SetDisc(int discNumber) { m_discNumber = discNumber; } + + /// @brief Get disk number (if present) + int GetDisc() const { return m_discNumber; } + + /// @brief Set year that the current song was released. + void SetYear(int year) { m_year = year; } + + /// @brief Get year that the current song was released. + int GetYear() const { return m_year; } + + /// @brief Set string from lyrics. + void SetLyrics(const std::string& lyrics) { m_lyrics = lyrics; } + + /// @brief Get string from lyrics. + const std::string& GetLyrics() const { return m_lyrics; } + + /// @brief Set the user-defined rating of the current song. + void SetRating(int rating) { m_rating = rating; } + + /// @brief Get the user-defined rating of the current song. + int GetRating() const { return m_rating; } + + /// @brief Set additional information comment (if present). + void SetComment(const std::string& comment) { m_comment = comment; } + + /// @brief Get additional information comment (if present). + const std::string& GetComment() const { return m_comment; } + + ///@} + +private: + VisualizationTrack(const VIS_TRACK* tag) + { + if (!tag) + return; + + m_title = tag->title ? tag->title : ""; + m_artist = tag->artist ? tag->artist : ""; + m_album = tag->album ? tag->album : ""; + m_albumArtist = tag->albumArtist ? tag->albumArtist : ""; + m_genre = tag->genre ? tag->genre : ""; + m_comment = tag->comment ? tag->comment : ""; + m_lyrics = tag->lyrics ? tag->lyrics : ""; + + m_trackNumber = tag->trackNumber; + m_discNumber = tag->discNumber; + m_duration = tag->duration; + m_year = tag->year; + m_rating = tag->rating; + } + + std::string m_title; + std::string m_artist; + std::string m_album; + std::string m_albumArtist; + std::string m_genre; + std::string m_comment; + std::string m_lyrics; + + int m_trackNumber = 0; + int m_discNumber = 0; + int m_duration = 0; + int m_year = 0; + int m_rating = 0; +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_visualization_Defs Definitions, structures and enumerators +/// @ingroup cpp_kodi_addon_visualization +/// @brief **Visualization add-on instance definition values**\n +/// All visualization functions associated data structures. +/// +/// Used to exchange the available options between Kodi and addon. +/// + +//============================================================================== +/// @addtogroup cpp_kodi_addon_visualization +/// @brief \cpp_class{ kodi::addon::CInstanceVisualization } +/// **Visualization add-on instance**\n +/// [Music visualization](https://en.wikipedia.org/wiki/Music_visualization), +/// or music visualisation, is a feature in Kodi that generates animated +/// imagery based on a piece of music. The imagery is usually generated and +/// rendered in real time synchronized to the music. +/// +/// Visualization techniques range from simple ones (e.g., a simulation of an +/// oscilloscope display) to elaborate ones, which often include a plurality +/// of composited effects. The changes in the music's loudness and frequency +/// spectrum are among the properties used as input to the visualization. +/// +/// Include the header @ref Visualization.h "#include " +/// to use this class. +/// +/// This interface allows the creation of visualizations for Kodi, based upon +/// **DirectX** or/and **OpenGL** rendering with `C++` code. +/// +/// Additionally, there are several @ref cpp_kodi_addon_visualization_CB "other functions" +/// available in which the child class can ask about the current hardware, +/// including the device, display and several other parts. +/// +/// ---------------------------------------------------------------------------- +/// +/// **Here's an example on addon.xml:** +/// ~~~~~~~~~~~~~{.xml} +/// +/// +/// @ADDON_DEPENDS@ +/// +/// +/// My visualization addon addon +/// My visualization addon description +/// @PLATFORM@ +/// +/// +/// ~~~~~~~~~~~~~ +/// +/// Description to visualization related addon.xml values: +/// | Name | Description +/// |:------------------------------|---------------------------------------- +/// | `point` | Addon type specification
At all addon types and for this kind always "xbmc.player.musicviz". +/// | `library_@PLATFORM@` | Sets the used library name, which is automatically set by cmake at addon build. +/// +/// -------------------------------------------------------------------------- +/// +/// **Here is an example of the minimum required code to start a visualization:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class CMyVisualization : public kodi::addon::CAddonBase, +/// public kodi::addon::CInstanceVisualization +/// { +/// public: +/// CMyVisualization(); +/// +/// bool Start(int channels, int samplesPerSec, int bitsPerSample, std::string songName) override; +/// void AudioData(const float* audioData, int audioDataLength, float* freqData, int freqDataLength) override; +/// void Render() override; +/// }; +/// +/// CMyVisualization::CMyVisualization() +/// { +/// ... +/// } +/// +/// bool CMyVisualization::Start(int channels, int samplesPerSec, int bitsPerSample, std::string songName) +/// { +/// ... +/// return true; +/// } +/// +/// void CMyVisualization::AudioData(const float* audioData, int audioDataLength, float* freqData, int freqDataLength) +/// { +/// ... +/// } +/// +/// void CMyVisualization::Render() +/// { +/// ... +/// } +/// +/// ADDONCREATOR(CMyVisualization) +/// ~~~~~~~~~~~~~ +/// +/// +/// -------------------------------------------------------------------------- +/// +/// +/// **Here is another example where the visualization is used together with +/// other instance types:** +/// +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class CMyVisualization : public kodi::addon::CInstanceVisualization +/// { +/// public: +/// CMyVisualization(KODI_HANDLE instance, const std::string& version); +/// +/// bool Start(int channels, int samplesPerSec, int bitsPerSample, std::string songName) override; +/// void AudioData(const float* audioData, int audioDataLength, float* freqData, int freqDataLength) override; +/// void Render() override; +/// }; +/// +/// CMyVisualization::CMyVisualization(KODI_HANDLE instance, const std::string& version) +/// : kodi::addon::CInstanceAudioDecoder(instance, version) +/// { +/// ... +/// } +/// +/// bool CMyVisualization::Start(int channels, int samplesPerSec, int bitsPerSample, std::string songName) +/// { +/// ... +/// return true; +/// } +/// +/// void CMyVisualization::AudioData(const float* audioData, int audioDataLength, float* freqData, int freqDataLength) +/// { +/// ... +/// } +/// +/// void CMyVisualization::Render() +/// { +/// ... +/// } +/// +/// +/// //---------------------------------------------------------------------- +/// +/// class CMyAddon : public kodi::addon::CAddonBase +/// { +/// public: +/// CMyAddon() { } +/// ADDON_STATUS CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) override; +/// }; +/// +/// // If you use only one instance in your add-on, can be instanceType and +/// // instanceID ignored +/// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, +/// const std::string& instanceID, +/// KODI_HANDLE instance, +/// const std::string& version, +/// KODI_HANDLE& addonInstance) +/// { +/// if (instanceType == ADDON_INSTANCE_VISUALIZATION) +/// { +/// kodi::Log(ADDON_LOG_INFO, "Creating my visualization"); +/// addonInstance = new CMyVisualization(instance, version); +/// return ADDON_STATUS_OK; +/// } +/// else if (...) +/// { +/// ... +/// } +/// return ADDON_STATUS_UNKNOWN; +/// } +/// +/// ADDONCREATOR(CMyAddon) +/// ~~~~~~~~~~~~~ +/// +/// The destruction of the example class `CMyVisualization` is called from +/// Kodi's header. Manually deleting the add-on instance is not required. +/// +class ATTRIBUTE_HIDDEN CInstanceVisualization : public IAddonInstance +{ +public: + //============================================================================ + /// + /// @ingroup cpp_kodi_addon_visualization + /// @brief Visualization class constructor + /// + /// Used by an add-on that only supports visualizations. + /// + CInstanceVisualization() + : IAddonInstance(ADDON_INSTANCE_VISUALIZATION, GetKodiTypeVersion(ADDON_INSTANCE_VISUALIZATION)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error( + "kodi::addon::CInstanceVisualization: Cannot create multiple instances of add-on."); + + SetAddonStruct(CAddonBase::m_interface->firstKodiInstance); + CAddonBase::m_interface->globalSingleInstance = this; + } + //---------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_addon_visualization + /// @brief Visualization class constructor used to support multiple instance + /// types. + /// + /// @param[in] instance The instance value given to + /// `kodi::addon::CAddonBase::CreateInstance(...)`. + /// @param[in] kodiVersion [opt] Version used in Kodi for this instance, to + /// allow compatibility to older Kodi versions. + /// + /// @note Recommended to set `kodiVersion`. + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Here's example about the use of this:** + /// ~~~~~~~~~~~~~{.cpp} + /// class CMyVisualization : public kodi::addon::CInstanceAudioDecoder + /// { + /// public: + /// CMyVisualization(KODI_HANDLE instance, const std::string& kodiVersion) + /// : kodi::addon::CInstanceAudioDecoder(instance, kodiVersion) + /// { + /// ... + /// } + /// + /// ... + /// }; + /// + /// ADDON_STATUS CMyAddon::CreateInstance(int instanceType, + /// const std::string& instanceID, + /// KODI_HANDLE instance, + /// const std::string& version, + /// KODI_HANDLE& addonInstance) + /// { + /// kodi::Log(ADDON_LOG_INFO, "Creating my visualization"); + /// addonInstance = new CMyVisualization(instance, version); + /// return ADDON_STATUS_OK; + /// } + /// ~~~~~~~~~~~~~ + /// + explicit CInstanceVisualization(KODI_HANDLE instance, const std::string& kodiVersion = "") + : IAddonInstance(ADDON_INSTANCE_VISUALIZATION, + !kodiVersion.empty() ? kodiVersion + : GetKodiTypeVersion(ADDON_INSTANCE_VISUALIZATION)) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceVisualization: Creation of multiple together " + "with single instance way is not allowed!"); + + SetAddonStruct(instance); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Destructor. + /// + ~CInstanceVisualization() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Used to notify the visualization that a new song has been started. + /// + /// @param[in] channels Number of channels in the stream + /// @param[in] samplesPerSec Samples per second of stream + /// @param[in] bitsPerSample Number of bits in one sample + /// @param[in] songName The name of the currently-playing song + /// @return true if start successful done + /// + virtual bool Start(int channels, int samplesPerSec, int bitsPerSample, std::string songName) + { + return true; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Used to inform the visualization that the rendering control was + /// stopped. + /// + virtual void Stop() {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Pass audio data to the visualization. + /// + /// @param[in] audioData The raw audio data + /// @param[in] audioDataLength Length of the audioData array + /// @param[in] freqData The [FFT](https://en.wikipedia.org/wiki/Fast_Fourier_transform) + /// of the audio data + /// @param[in] freqDataLength Length of frequency data array + /// + /// Values **freqData** and **freqDataLength** are used if GetInfo() returns + /// true for the `wantsFreq` parameter. Otherwise, **freqData** is set to + /// `nullptr` and **freqDataLength** is `0`. + /// + virtual void AudioData(const float* audioData, + int audioDataLength, + float* freqData, + int freqDataLength) + { + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Used to inform Kodi that the rendered region is dirty and need an + /// update. + /// + /// @return True if dirty + /// + virtual bool IsDirty() { return true; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Used to indicate when the add-on should render. + /// + virtual void Render() {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Used to get the number of buffers from the current visualization. + /// + /// @param[out] wantsFreq Indicates whether the add-on wants FFT data. If set + /// to true, the **freqData** and **freqDataLength** + /// parameters of @ref AudioData() are used + /// @param[out] syncDelay The number of buffers to delay before calling + /// @ref AudioData() + /// + /// @note If this function is not implemented, it will default to + /// `wantsFreq` = false and `syncDelay` = 0. + /// + virtual void GetInfo(bool& wantsFreq, int& syncDelay) + { + wantsFreq = false; + syncDelay = 0; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Used to get a list of visualization presets the user can select. + /// from + /// + /// @param[out] presets The vector list containing the names of presets that + /// the user can select + /// @return Return true if successful, or false if there are no presets to + /// choose from + /// + virtual bool GetPresets(std::vector& presets) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Get the index of the current preset. + /// + /// @return Index number of the current preset + /// + virtual int GetActivePreset() { return -1; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Check if the add-on is locked to the current preset. + /// + /// @return True if locked to the current preset + /// + virtual bool IsLocked() { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Load the previous visualization preset. + /// + /// @return Return true if the previous preset was loaded + /// + virtual bool PrevPreset() { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Load the next visualization preset. + /// + /// @return Return true if the next preset was loaded + /// + virtual bool NextPreset() { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Load a visualization preset. + /// + /// This function is called after a new preset is selected. + /// + /// @param[in] select Preset index to use + /// @return Return true if the preset is loaded + /// + virtual bool LoadPreset(int select) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Switch to a new random preset. + /// + /// @return Return true if a random preset was loaded + /// + virtual bool RandomPreset() { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Lock the current visualization preset, preventing it from changing. + /// + /// @param[in] lockUnlock If set to true, the preset should be locked + /// @return Return true if the current preset is locked + /// + virtual bool LockPreset(bool lockUnlock) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Used to increase/decrease the visualization preset rating. + /// + /// @param[in] plusMinus If set to true the rating is increased, otherwise + /// decreased + /// @return Return true if the rating is modified + /// + virtual bool RatePreset(bool plusMinus) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Inform the visualization of the current album art image. + /// + /// @param[in] albumart Path to the current album art image + /// @return Return true if the image is used + /// + virtual bool UpdateAlbumart(std::string albumart) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization + /// @brief Inform the visualization of the current track's tag information. + /// + /// @param[in] track Visualization track information structure + /// @return Return true if the track information is used + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_visualization_Defs_VisualizationTrack_Help + /// + ///------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// + /// #include + /// + /// class CMyVisualization : public kodi::addon::CInstanceVisualization + /// { + /// public: + /// CMyVisualization(KODI_HANDLE instance, const std::string& version); + /// + /// ... + /// + /// private: + /// kodi::addon::VisualizationTrack m_runningTrack; + /// }; + /// + /// bool CMyVisualization::UpdateTrack(const kodi::addon::VisualizationTrack& track) + /// { + /// m_runningTrack = track; + /// return true; + /// } + /// + /// ~~~~~~~~~~~~~ + /// + virtual bool UpdateTrack(const kodi::addon::VisualizationTrack& track) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_visualization_CB Information functions + /// @ingroup cpp_kodi_addon_visualization + /// @brief **To get info about the device, display and several other parts**\n + /// These are functions to query any values or to transfer them to Kodi. + /// + ///@{ + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization_CB + /// @brief To transfer available presets on addon. + /// + /// Used if @ref GetPresets not possible to use, e.g. where available presets + /// are only known during @ref Start call. + /// + /// @param[in] presets List to store available presets. + /// + /// @note The function should only be called once, if possible + /// + inline void TransferPresets(const std::vector& presets) + { + m_instanceData->toKodi->clear_presets(m_instanceData->toKodi->kodiInstance); + for (auto it : presets) + m_instanceData->toKodi->transfer_preset(m_instanceData->toKodi->kodiInstance, it.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization_CB + /// @brief Device that represents the display adapter. + /// + /// @return A pointer to the used device with @ref cpp_kodi_Defs_HardwareContext "HardwareContext" + /// + /// @note This is only available on **DirectX**, It us unused (`nullptr`) on + /// **OpenGL** + /// + ///------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// .. + /// // Note: Device() there is used inside addon child class about + /// // kodi::addon::CInstanceVisualization + /// ID3D11DeviceContext1* context = static_cast(kodi::addon::CInstanceVisualization::Device()); + /// .. + /// ~~~~~~~~~~~~~ + /// + inline kodi::HardwareContext Device() { return m_instanceData->props->device; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization_CB + /// @brief Returns the X position of the rendering window. + /// + /// @return The X position, in pixels + /// + inline int X() { return m_instanceData->props->x; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization_CB + /// @brief Returns the Y position of the rendering window. + /// + /// @return The Y position, in pixels + /// + inline int Y() { return m_instanceData->props->y; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization_CB + /// @brief Returns the width of the rendering window. + /// + /// @return The width, in pixels + /// + inline int Width() { return m_instanceData->props->width; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization_CB + /// @brief Returns the height of the rendering window. + /// + /// @return The height, in pixels + /// + inline int Height() { return m_instanceData->props->height; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization_CB + /// @brief Pixel aspect ratio (often abbreviated PAR) is a ratio that + /// describes how the width of a pixel compares to the height of that pixel. + /// + /// @return The pixel aspect ratio used by the display + /// + inline float PixelRatio() { return m_instanceData->props->pixelRatio; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization_CB + /// @brief Used to get the name of the add-on defined in `addon.xml`. + /// + /// @return The add-on name + /// + inline std::string Name() { return m_instanceData->props->name; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization_CB + /// @brief Used to get the full path where the add-on is installed. + /// + /// @return The add-on installation path + /// + inline std::string Presets() { return m_instanceData->props->presets; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_visualization_CB + /// @brief Used to get the full path to the add-on's user profile. + /// + /// @note The trailing folder (consisting of the add-on's ID) is not created + /// by default. If it is needed, you must call kodi::vfs::CreateDirectory() + /// to create the folder. + /// + /// @return Path to the user profile + /// + inline std::string Profile() { return m_instanceData->props->profile; } + //---------------------------------------------------------------------------- + + ///@} + +private: + void SetAddonStruct(KODI_HANDLE instance) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstanceVisualization: Null pointer instance passed."); + + m_instanceData = static_cast(instance); + m_instanceData->toAddon->addonInstance = this; + m_instanceData->toAddon->start = ADDON_Start; + m_instanceData->toAddon->stop = ADDON_Stop; + m_instanceData->toAddon->audio_data = ADDON_AudioData; + m_instanceData->toAddon->is_dirty = ADDON_IsDirty; + m_instanceData->toAddon->render = ADDON_Render; + m_instanceData->toAddon->get_info = ADDON_GetInfo; + m_instanceData->toAddon->prev_preset = ADDON_PrevPreset; + m_instanceData->toAddon->next_preset = ADDON_NextPreset; + m_instanceData->toAddon->load_preset = ADDON_LoadPreset; + m_instanceData->toAddon->random_preset = ADDON_RandomPreset; + m_instanceData->toAddon->lock_preset = ADDON_LockPreset; + m_instanceData->toAddon->rate_preset = ADDON_RatePreset; + m_instanceData->toAddon->update_albumart = ADDON_UpdateAlbumart; + m_instanceData->toAddon->update_track = ADDON_UpdateTrack; + m_instanceData->toAddon->get_presets = ADDON_GetPresets; + m_instanceData->toAddon->get_active_preset = ADDON_GetActivePreset; + m_instanceData->toAddon->is_locked = ADDON_IsLocked; + } + + inline static bool ADDON_Start(const AddonInstance_Visualization* addon, + int channels, + int samplesPerSec, + int bitsPerSample, + const char* songName) + { + CInstanceVisualization* thisClass = + static_cast(addon->toAddon->addonInstance); + thisClass->m_renderHelper = kodi::gui::GetRenderHelper(); + return thisClass->Start(channels, samplesPerSec, bitsPerSample, songName); + } + + inline static void ADDON_Stop(const AddonInstance_Visualization* addon) + { + CInstanceVisualization* thisClass = + static_cast(addon->toAddon->addonInstance); + thisClass->Stop(); + thisClass->m_renderHelper = nullptr; + } + + inline static void ADDON_AudioData(const AddonInstance_Visualization* addon, + const float* audioData, + int audioDataLength, + float* freqData, + int freqDataLength) + { + static_cast(addon->toAddon->addonInstance) + ->AudioData(audioData, audioDataLength, freqData, freqDataLength); + } + + inline static bool ADDON_IsDirty(const AddonInstance_Visualization* addon) + { + return static_cast(addon->toAddon->addonInstance)->IsDirty(); + } + + inline static void ADDON_Render(const AddonInstance_Visualization* addon) + { + CInstanceVisualization* thisClass = + static_cast(addon->toAddon->addonInstance); + if (!thisClass->m_renderHelper) + return; + thisClass->m_renderHelper->Begin(); + thisClass->Render(); + thisClass->m_renderHelper->End(); + } + + inline static void ADDON_GetInfo(const AddonInstance_Visualization* addon, VIS_INFO* info) + { + static_cast(addon->toAddon->addonInstance) + ->GetInfo(info->bWantsFreq, info->iSyncDelay); + } + + inline static unsigned int ADDON_GetPresets(const AddonInstance_Visualization* addon) + { + CInstanceVisualization* thisClass = + static_cast(addon->toAddon->addonInstance); + std::vector presets; + if (thisClass->GetPresets(presets)) + { + for (auto it : presets) + thisClass->m_instanceData->toKodi->transfer_preset(addon->toKodi->kodiInstance, it.c_str()); + } + + return static_cast(presets.size()); + } + + inline static int ADDON_GetActivePreset(const AddonInstance_Visualization* addon) + { + return static_cast(addon->toAddon->addonInstance)->GetActivePreset(); + } + + inline static bool ADDON_PrevPreset(const AddonInstance_Visualization* addon) + { + return static_cast(addon->toAddon->addonInstance)->PrevPreset(); + } + + inline static bool ADDON_NextPreset(const AddonInstance_Visualization* addon) + { + return static_cast(addon->toAddon->addonInstance)->NextPreset(); + } + + inline static bool ADDON_LoadPreset(const AddonInstance_Visualization* addon, int select) + + { + return static_cast(addon->toAddon->addonInstance)->LoadPreset(select); + } + + inline static bool ADDON_RandomPreset(const AddonInstance_Visualization* addon) + { + return static_cast(addon->toAddon->addonInstance)->RandomPreset(); + } + + inline static bool ADDON_LockPreset(const AddonInstance_Visualization* addon) + { + CInstanceVisualization* thisClass = + static_cast(addon->toAddon->addonInstance); + thisClass->m_presetLockedByUser = !thisClass->m_presetLockedByUser; + return thisClass->LockPreset(thisClass->m_presetLockedByUser); + } + + inline static bool ADDON_RatePreset(const AddonInstance_Visualization* addon, bool plus_minus) + { + return static_cast(addon->toAddon->addonInstance) + ->RatePreset(plus_minus); + } + + inline static bool ADDON_IsLocked(const AddonInstance_Visualization* addon) + { + return static_cast(addon->toAddon->addonInstance)->IsLocked(); + } + + inline static bool ADDON_UpdateAlbumart(const AddonInstance_Visualization* addon, + const char* albumart) + { + return static_cast(addon->toAddon->addonInstance) + ->UpdateAlbumart(albumart); + } + + inline static bool ADDON_UpdateTrack(const AddonInstance_Visualization* addon, + const VIS_TRACK* track) + { + VisualizationTrack cppTrack(track); + return static_cast(addon->toAddon->addonInstance) + ->UpdateTrack(cppTrack); + } + + std::shared_ptr m_renderHelper; + bool m_presetLockedByUser = false; + AddonInstance_Visualization* m_instanceData; +}; + +} /* namespace addon */ +} /* namespace kodi */ +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/peripheral/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/peripheral/CMakeLists.txt new file mode 100644 index 0000000..d6fba69 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/peripheral/CMakeLists.txt @@ -0,0 +1,5 @@ +set(HEADERS PeripheralUtils.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_addon-instance_peripheral) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/peripheral/PeripheralUtils.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/peripheral/PeripheralUtils.h new file mode 100644 index 0000000..febaeb9 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/peripheral/PeripheralUtils.h @@ -0,0 +1,1277 @@ +/* + * Copyright (C) 2014-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/addon-instance/peripheral.h" + +#ifdef __cplusplus + +#include // Requires c++11 +#include +#include +#include +#include +#include + +#define PERIPHERAL_SAFE_DELETE(x) \ + do \ + { \ + delete (x); \ + (x) = NULL; \ + } while (0) +#define PERIPHERAL_SAFE_DELETE_ARRAY(x) \ + do \ + { \ + delete[](x); \ + (x) = NULL; \ + } while (0) + +namespace kodi +{ +namespace addon +{ + +class CInstancePeripheral; + +/*! + * Utility class to manipulate arrays of peripheral types. + */ +template +class PeripheralVector +{ +public: + static void ToStructs(const std::vector& vecObjects, THE_STRUCT** pStructs) + { + if (!pStructs) + return; + + if (vecObjects.empty()) + { + *pStructs = NULL; + } + else + { + (*pStructs) = new THE_STRUCT[vecObjects.size()]; + for (unsigned int i = 0; i < vecObjects.size(); i++) + vecObjects.at(i).ToStruct((*pStructs)[i]); + } + } + + static void ToStructs(const std::vector& vecObjects, THE_STRUCT** pStructs) + { + if (!pStructs) + return; + + if (vecObjects.empty()) + { + *pStructs = NULL; + } + else + { + *pStructs = new THE_STRUCT[vecObjects.size()]; + for (unsigned int i = 0; i < vecObjects.size(); i++) + vecObjects.at(i)->ToStruct((*pStructs)[i]); + } + } + + static void ToStructs(const std::vector>& vecObjects, + THE_STRUCT** pStructs) + { + if (!pStructs) + return; + + if (vecObjects.empty()) + { + *pStructs = NULL; + } + else + { + *pStructs = new THE_STRUCT[vecObjects.size()]; + for (unsigned int i = 0; i < vecObjects.size(); i++) + vecObjects.at(i)->ToStruct((*pStructs)[i]); + } + } + + static void FreeStructs(unsigned int structCount, THE_STRUCT* structs) + { + if (structs) + { + for (unsigned int i = 0; i < structCount; i++) + THE_CLASS::FreeStruct(structs[i]); + } + PERIPHERAL_SAFE_DELETE_ARRAY(structs); + } +}; + +//============================================================================== +/// @defgroup cpp_kodi_addon_peripheral_Defs_PeripheralCapabilities class PeripheralCapabilities +/// @ingroup cpp_kodi_addon_peripheral_Defs_General +/// @brief **%Peripheral add-on capabilities**\n +/// This class is needed to tell Kodi which options are supported on the addon. +/// +/// If a capability is set to **true**, then the corresponding methods from +/// @ref cpp_kodi_addon_peripheral "kodi::addon::CInstancePeripheral" need to be +/// implemented. +/// +/// As default them all set to **false**. +/// +/// Used on @ref kodi::addon::CInstancePeripheral::GetCapabilities(). +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_peripheral_Defs_PeripheralCapabilities_Help +/// +///@{ +class PeripheralCapabilities : public CStructHdl +{ + /*! \cond PRIVATE */ + friend class CInstancePeripheral; + /*! \endcond */ + +public: + /*! \cond PRIVATE */ + PeripheralCapabilities() + { + m_cStructure->provides_joysticks = false; + m_cStructure->provides_joystick_rumble = false; + m_cStructure->provides_joystick_power_off = false; + m_cStructure->provides_buttonmaps = false; + } + + PeripheralCapabilities(const PeripheralCapabilities& data) : CStructHdl(data) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_peripheral_Defs_PeripheralCapabilities_Help Value Help + /// @ingroup cpp_kodi_addon_peripheral_Defs_PeripheralCapabilities + /// ---------------------------------------------------------------------------- + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_peripheral_Defs_PeripheralCapabilities : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **Provides joysticks** | `boolean` | @ref PeripheralCapabilities::SetProvidesJoysticks "SetProvidesJoysticks" | @ref PeripheralCapabilities::GetProvidesJoysticks "GetProvidesJoysticks" + /// | **Provides joystick rumble** | `boolean` | @ref PeripheralCapabilities::SetProvidesJoystickRumble "SetProvidesJoystickRumble" | @ref PeripheralCapabilities::GetProvidesJoystickRumble "GetProvidesJoystickRumble" + /// | **Provides joystick power off** | `boolean` | @ref PeripheralCapabilities::SetProvidesJoystickPowerOff "SetProvidesJoystickPowerOff" | @ref PeripheralCapabilities::GetProvidesJoystickPowerOff "GetProvidesJoystickPowerOff" + /// | **Provides button maps** | `boolean` | @ref PeripheralCapabilities::SetProvidesButtonmaps "SetProvidesButtonmaps" | @ref PeripheralCapabilities::GetProvidesButtonmaps "GetProvidesButtonmaps" + + /// @addtogroup cpp_kodi_addon_peripheral_Defs_PeripheralCapabilities + ///@{ + + /// @brief Set true if the add-on provides joysticks. + void SetProvidesJoysticks(bool providesJoysticks) + { + m_cStructure->provides_joysticks = providesJoysticks; + } + + /// @brief To get with @ref SetProvidesJoysticks changed values. + bool GetProvidesJoysticks() const { return m_cStructure->provides_joysticks; } + + /// @brief Set true if the add-on provides joystick rumble. + void SetProvidesJoystickRumble(bool providesJoystickRumble) + { + m_cStructure->provides_joystick_rumble = providesJoystickRumble; + } + + /// @brief To get with @ref SetProvidesJoystickRumble changed values. + bool GetProvidesJoystickRumble() const { return m_cStructure->provides_joystick_rumble; } + + /// @brief Set true if the add-on provides power off about joystick. + void SetProvidesJoystickPowerOff(bool providesJoystickPowerOff) + { + m_cStructure->provides_joystick_power_off = providesJoystickPowerOff; + } + + /// @brief To get with @ref SetProvidesJoystickPowerOff changed values. + bool GetProvidesJoystickPowerOff() const { return m_cStructure->provides_joystick_power_off; } + + /// @brief Set true if the add-on provides button maps. + void SetProvidesButtonmaps(bool providesButtonmaps) + { + m_cStructure->provides_buttonmaps = providesButtonmaps; + } + + /// @brief To get with @ref SetProvidesButtonmaps changed values. + bool GetProvidesButtonmaps() const { return m_cStructure->provides_buttonmaps; } + + ///@} + +private: + PeripheralCapabilities(const PERIPHERAL_CAPABILITIES* data) : CStructHdl(data) {} + PeripheralCapabilities(PERIPHERAL_CAPABILITIES* data) : CStructHdl(data) {} +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_peripheral_Defs_Peripheral_Peripheral class Peripheral +/// @ingroup cpp_kodi_addon_peripheral_Defs_Peripheral +/// @brief **Wrapper class providing peripheral information**\n +/// Classes can extend %Peripheral to inherit peripheral properties. +/// +/// Used on @ref kodi::addon::CInstancePeripheral::PerformDeviceScan(). +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_peripheral_Defs_Peripheral_Peripheral_Help +/// +///@{ +class Peripheral +{ +public: + /// @defgroup cpp_kodi_addon_peripheral_Defs_Peripheral_Peripheral_Help Value Help + /// @ingroup cpp_kodi_addon_peripheral_Defs_Peripheral_Peripheral + /// ---------------------------------------------------------------------------- + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_peripheral_Defs_Peripheral_Peripheral : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **%Peripheral type** | @ref PERIPHERAL_TYPE | @ref Peripheral::SetType "SetType" | @ref Peripheral::Type "Type" + /// | **%Peripheral name** | `const std::string&` | @ref Peripheral::SetName "SetName" | @ref Peripheral::Name "Name" + /// | **%Peripheral vendor id** | `uint16_t` | @ref Peripheral::SetVendorID "SetVendorID" | @ref Peripheral::VendorID "VendorID" + /// | **%Peripheral product id** | `uint16_t` | @ref Peripheral::SetProductID "SetProductID" | @ref Peripheral::ProductID "ProductID" + /// | **%Peripheral index** | `unsigned int` | @ref Peripheral::SetIndex "SetIndex" | @ref Peripheral::Index "Index" + /// + /// Further are following included: + /// - @ref Peripheral::Peripheral "Peripheral(PERIPHERAL_TYPE type = PERIPHERAL_TYPE_UNKNOWN, const std::string& strName = \"\")": Class constructor. + /// - @ref Peripheral::IsVidPidKnown "IsVidPidKnown()": To check VID and PID are known. + /// + + /// @addtogroup cpp_kodi_addon_peripheral_Defs_Peripheral_Peripheral + ///@{ + + /// @brief Constructor. + /// + /// @param[in] type [optional] Peripheral type, or @ref PERIPHERAL_TYPE_UNKNOWN + /// as default + /// @param[in] strName [optional] Name of related peripheral + Peripheral(PERIPHERAL_TYPE type = PERIPHERAL_TYPE_UNKNOWN, const std::string& strName = "") + : m_type(type), m_strName(strName) + { + } + + /// @brief Destructor. + virtual ~Peripheral(void) = default; + + /// @brief Get peripheral type. + /// + /// @return Type defined with @ref PERIPHERAL_TYPE + PERIPHERAL_TYPE Type(void) const { return m_type; } + + /// @brief Get peripheral name. + /// + /// @return Name string of peripheral + const std::string& Name(void) const { return m_strName; } + + /// @brief Get peripheral vendor id. + /// + /// @return Vendor id + uint16_t VendorID(void) const { return m_vendorId; } + + /// @brief Get peripheral product id. + /// + /// @return Product id + uint16_t ProductID(void) const { return m_productId; } + + /// @brief Get peripheral index identifier. + /// + /// @return Index number + unsigned int Index(void) const { return m_index; } + + /// @brief Check VID and PID are known. + /// + /// @return true if VID and PID are not 0 + /// + /// @note Derived property: VID and PID are `0x0000` if unknown + bool IsVidPidKnown(void) const { return m_vendorId != 0 || m_productId != 0; } + + /// @brief Set peripheral type. + /// + /// @param[in] type Type to set + void SetType(PERIPHERAL_TYPE type) { m_type = type; } + + /// @brief Set peripheral name. + /// + /// @param[in] strName Name to set + void SetName(const std::string& strName) { m_strName = strName; } + + /// @brief Set peripheral vendor id. + /// + /// @param[in] vendorId Type to set + void SetVendorID(uint16_t vendorId) { m_vendorId = vendorId; } + + /// @brief Set peripheral product identifier. + /// + /// @param[in] productId Type to set + void SetProductID(uint16_t productId) { m_productId = productId; } + + /// @brief Set peripheral index. + /// + /// @param[in] index Type to set + void SetIndex(unsigned int index) { m_index = index; } + + ///@} + + explicit Peripheral(const PERIPHERAL_INFO& info) + : m_type(info.type), + m_strName(info.name ? info.name : ""), + m_vendorId(info.vendor_id), + m_productId(info.product_id), + m_index(info.index) + { + } + + void ToStruct(PERIPHERAL_INFO& info) const + { + info.type = m_type; + info.name = new char[m_strName.size() + 1]; + info.vendor_id = m_vendorId; + info.product_id = m_productId; + info.index = m_index; + + std::strcpy(info.name, m_strName.c_str()); + } + + static void FreeStruct(PERIPHERAL_INFO& info) { PERIPHERAL_SAFE_DELETE_ARRAY(info.name); } + +private: + PERIPHERAL_TYPE m_type; + std::string m_strName; + uint16_t m_vendorId = 0; + uint16_t m_productId = 0; + unsigned int m_index = 0; +}; +///@} +//------------------------------------------------------------------------------ + +typedef PeripheralVector Peripherals; + +//============================================================================== +/// @defgroup cpp_kodi_addon_peripheral_Defs_Peripheral_PeripheralEvent class PeripheralEvent +/// @ingroup cpp_kodi_addon_peripheral_Defs_Peripheral +/// @brief **Wrapper class for %peripheral events**\n +/// To handle data of change events between add-on and Kodi. +/// +/// Used on @ref kodi::addon::CInstancePeripheral::GetEvents() and +/// @ref kodi::addon::CInstancePeripheral::SendEvent(). +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_peripheral_Defs_Peripheral_PeripheralEvent_Help +/// +///@{ +class PeripheralEvent +{ +public: + /// @defgroup cpp_kodi_addon_peripheral_Defs_Peripheral_PeripheralEvent_Help Value Help + /// @ingroup cpp_kodi_addon_peripheral_Defs_Peripheral_PeripheralEvent + /// ---------------------------------------------------------------------------- + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_peripheral_Defs_Peripheral_PeripheralEvent : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **%Peripheral event type** | @ref PERIPHERAL_EVENT_TYPE | @ref PeripheralEvent::SetType "SetType" | @ref PeripheralEvent::Type "Type" + /// | **%Peripheral index** | `unsigned int` | @ref PeripheralEvent::SetPeripheralIndex "SetPeripheralIndex" | @ref PeripheralEvent::PeripheralIndex "PeripheralIndex" + /// | **%Peripheral event driver index** | `unsigned int` | @ref PeripheralEvent::SetDriverIndex "SetDriverIndex" | @ref PeripheralEvent::DriverIndex "DriverIndex" + /// | **%Peripheral event button state** | @ref JOYSTICK_STATE_BUTTON | @ref PeripheralEvent::SetButtonState "SetButtonState" | @ref PeripheralEvent::ButtonState "ButtonState" + /// | **%Peripheral event hat state** | @ref JOYSTICK_STATE_HAT | @ref PeripheralEvent::SetHatState "SetHatState" | @ref PeripheralEvent::HatState "HatState" + /// | **%Peripheral event axis state** | @ref JOYSTICK_STATE_AXIS (`float`) | @ref PeripheralEvent::SetAxisState "SetAxisState" | @ref PeripheralEvent::AxisState "AxisState" + /// | **%Peripheral event motor state** | @ref JOYSTICK_STATE_MOTOR (`float`) | @ref PeripheralEvent::SetMotorState "SetMotorState" | @ref PeripheralEvent::MotorState "MotorState" + /// + /// Further are several class constructors with values included. + + /// @addtogroup cpp_kodi_addon_peripheral_Defs_Peripheral_PeripheralEvent + ///@{ + + /// @brief Constructor. + PeripheralEvent() = default; + + /// @brief Constructor. + /// + /// @param[in] peripheralIndex %Peripheral index + /// @param[in] buttonIndex Button index + /// @param[in] state Joystick state button + PeripheralEvent(unsigned int peripheralIndex, + unsigned int buttonIndex, + JOYSTICK_STATE_BUTTON state) + : m_type(PERIPHERAL_EVENT_TYPE_DRIVER_BUTTON), + m_peripheralIndex(peripheralIndex), + m_driverIndex(buttonIndex), + m_buttonState(state) + { + } + + /// @brief Constructor. + /// + /// @param[in] peripheralIndex %Peripheral index + /// @param[in] hatIndex Hat index + /// @param[in] state Joystick state hat + PeripheralEvent(unsigned int peripheralIndex, unsigned int hatIndex, JOYSTICK_STATE_HAT state) + : m_type(PERIPHERAL_EVENT_TYPE_DRIVER_HAT), + m_peripheralIndex(peripheralIndex), + m_driverIndex(hatIndex), + m_hatState(state) + { + } + + /// @brief Constructor. + /// + /// @param[in] peripheralIndex %Peripheral index + /// @param[in] axisIndex Axis index + /// @param[in] state Joystick state axis + PeripheralEvent(unsigned int peripheralIndex, unsigned int axisIndex, JOYSTICK_STATE_AXIS state) + : m_type(PERIPHERAL_EVENT_TYPE_DRIVER_AXIS), + m_peripheralIndex(peripheralIndex), + m_driverIndex(axisIndex), + m_axisState(state) + { + } + + /// @brief Get type of event. + /// + /// @return Type defined with @ref PERIPHERAL_EVENT_TYPE + PERIPHERAL_EVENT_TYPE Type(void) const { return m_type; } + + /// @brief Get peripheral index. + /// + /// @return %Peripheral index number + unsigned int PeripheralIndex(void) const { return m_peripheralIndex; } + + /// @brief Get driver index. + /// + /// @return Driver index number + unsigned int DriverIndex(void) const { return m_driverIndex; } + + /// @brief Get button state. + /// + /// @return Button state as @ref JOYSTICK_STATE_BUTTON + JOYSTICK_STATE_BUTTON ButtonState(void) const { return m_buttonState; } + + /// @brief Get hat state. + /// + /// @return Hat state + JOYSTICK_STATE_HAT HatState(void) const { return m_hatState; } + + /// @brief Get axis state. + /// + /// @return Axis state + JOYSTICK_STATE_AXIS AxisState(void) const { return m_axisState; } + + /// @brief Get motor state. + /// + /// @return Motor state + JOYSTICK_STATE_MOTOR MotorState(void) const { return m_motorState; } + + /// @brief Set type of event. + /// + /// @param[in] type Type defined with @ref PERIPHERAL_EVENT_TYPE + void SetType(PERIPHERAL_EVENT_TYPE type) { m_type = type; } + + /// @brief Set peripheral index. + /// + /// @param[in] index %Peripheral index number + void SetPeripheralIndex(unsigned int index) { m_peripheralIndex = index; } + + /// @brief Set driver index. + /// + /// @param[in] index Driver index number + void SetDriverIndex(unsigned int index) { m_driverIndex = index; } + + /// @brief Set button state. + /// + /// @param[in] state Button state as @ref JOYSTICK_STATE_BUTTON + void SetButtonState(JOYSTICK_STATE_BUTTON state) { m_buttonState = state; } + + /// @brief Set hat state. + /// + /// @param[in] state Hat state as @ref JOYSTICK_STATE_HAT (float) + void SetHatState(JOYSTICK_STATE_HAT state) { m_hatState = state; } + + /// @brief Set axis state. + /// + /// @param[in] state Axis state as @ref JOYSTICK_STATE_AXIS (float) + void SetAxisState(JOYSTICK_STATE_AXIS state) { m_axisState = state; } + + /// @brief Set motor state. + /// + /// @param[in] state Motor state as @ref JOYSTICK_STATE_MOTOR (float) + void SetMotorState(JOYSTICK_STATE_MOTOR state) { m_motorState = state; } + + ///@} + + explicit PeripheralEvent(const PERIPHERAL_EVENT& event) + : m_type(event.type), + m_peripheralIndex(event.peripheral_index), + m_driverIndex(event.driver_index), + m_buttonState(event.driver_button_state), + m_hatState(event.driver_hat_state), + m_axisState(event.driver_axis_state), + m_motorState(event.motor_state) + { + } + + void ToStruct(PERIPHERAL_EVENT& event) const + { + event.type = m_type; + event.peripheral_index = m_peripheralIndex; + event.driver_index = m_driverIndex; + event.driver_button_state = m_buttonState; + event.driver_hat_state = m_hatState; + event.driver_axis_state = m_axisState; + event.motor_state = m_motorState; + } + + static void FreeStruct(PERIPHERAL_EVENT& event) { (void)event; } + +private: + PERIPHERAL_EVENT_TYPE m_type = PERIPHERAL_EVENT_TYPE_NONE; + unsigned int m_peripheralIndex = 0; + unsigned int m_driverIndex = 0; + JOYSTICK_STATE_BUTTON m_buttonState = JOYSTICK_STATE_BUTTON_UNPRESSED; + JOYSTICK_STATE_HAT m_hatState = JOYSTICK_STATE_HAT_UNPRESSED; + JOYSTICK_STATE_AXIS m_axisState = 0.0f; + JOYSTICK_STATE_MOTOR m_motorState = 0.0f; +}; +///@} +//------------------------------------------------------------------------------ + +typedef PeripheralVector PeripheralEvents; + +//============================================================================== +/// @defgroup cpp_kodi_addon_peripheral_Defs_Joystick_Joystick class Joystick +/// @ingroup cpp_kodi_addon_peripheral_Defs_Joystick +/// @brief **Wrapper class providing additional joystick information**\n +/// This is a child class to expand another class with necessary joystick data. +/// +/// For data not provided by @ref cpp_kodi_addon_peripheral_Defs_Peripheral_Peripheral. +/// +/// Used on: +/// - @ref kodi::addon::CInstancePeripheral::GetJoystickInfo() +/// - @ref kodi::addon::CInstancePeripheral::GetFeatures(). +/// - @ref kodi::addon::CInstancePeripheral::MapFeatures(). +/// - @ref kodi::addon::CInstancePeripheral::GetIgnoredPrimitives(). +/// - @ref kodi::addon::CInstancePeripheral::SetIgnoredPrimitives(). +/// - @ref kodi::addon::CInstancePeripheral::SaveButtonMap(). +/// - @ref kodi::addon::CInstancePeripheral::RevertButtonMap(). +/// - @ref kodi::addon::CInstancePeripheral::ResetButtonMap(). +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_peripheral_Defs_Joystick_Joystick_Help +/// +///@{ +class Joystick : public Peripheral +{ +public: + /// @defgroup cpp_kodi_addon_peripheral_Defs_Joystick_Joystick_Help Value Help + /// @ingroup cpp_kodi_addon_peripheral_Defs_Joystick_Joystick + /// ---------------------------------------------------------------------------- + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_peripheral_Defs_Joystick_Joystick : + /// | Name | Type | Class | Set call | Get call + /// |------|------|-------|----------|---------- + /// | **%Joystick provider** | `const std::string&` | @ref Joystick | @ref Joystick::SetProvider "SetProvider" | @ref Joystick::Provider "Provider" + /// | **%Joystick requested port** | `int` | @ref Joystick | @ref Joystick::SetRequestedPort "SetRequestedPort" | @ref Joystick::RequestedPort "RequestedPort" + /// | **%Joystick button count** | `unsigned int` | @ref Joystick | @ref Joystick::SetButtonCount "SetButtonCount" | @ref Joystick::ButtonCount "ButtonCount" + /// | **%Joystick hat count** | `unsigned int` | @ref Joystick | @ref Joystick::SetHatCount "SetHatCount" | @ref Joystick::HatCount "HatCount" + /// | **%Joystick axis count** | `unsigned int` | @ref Joystick | @ref Joystick::SetAxisCount "SetAxisCount" | @ref Joystick::AxisCount "AxisCount" + /// | **%Joystick motor count** | `unsigned int` | @ref Joystick | @ref Joystick::SetMotorCount "SetMotorCount" | @ref Joystick::MotorCount "MotorCount" + /// | **%Joystick support power off** | `bool` | @ref Joystick | @ref Joystick::SetSupportsPowerOff "SetSupportsPowerOff" | @ref Joystick::SupportsPowerOff "SupportsPowerOff" + /// | **%Peripheral type** | @ref PERIPHERAL_TYPE | @ref Peripheral | @ref Peripheral::SetType "SetType" | @ref Peripheral::Type "Type" + /// | **%Peripheral name** | `const std::string&` | @ref Peripheral | @ref Peripheral::SetName "SetName" | @ref Peripheral::Name "Name" + /// | **%Peripheral vendor id** | `uint16_t` | @ref Peripheral | @ref Peripheral::SetVendorID "SetVendorID" | @ref Peripheral::VendorID "VendorID" + /// | **%Peripheral product id** | `uint16_t` | @ref Peripheral | @ref Peripheral::SetProductID "SetProductID" | @ref Peripheral::ProductID "ProductID" + /// | **%Peripheral index** | `unsigned int` | @ref Peripheral | @ref Peripheral::SetIndex "SetIndex" | @ref Peripheral::Index "Index" + /// + /// Further are following included: + /// - @ref Joystick::Joystick "Joystick(const std::string& provider = \"\", const std::string& strName = \"\")" + /// - @ref Joystick::operator= "Joystick& operator=(const Joystick& rhs)" + /// - @ref Peripheral::IsVidPidKnown "IsVidPidKnown()": To check VID and PID are known. + /// + + /// @addtogroup cpp_kodi_addon_peripheral_Defs_Joystick_Joystick + ///@{ + + /// @brief Constructor. + /// + /// @param[in] provider [optional] Provide name + /// @param[in] strName [optional] Name of related joystick + Joystick(const std::string& provider = "", const std::string& strName = "") + : Peripheral(PERIPHERAL_TYPE_JOYSTICK, strName), + m_provider(provider), + m_requestedPort(NO_PORT_REQUESTED) + { + } + + /// @brief Class copy constructor. + /// + /// @param[in] other Other class to copy on construct here + Joystick(const Joystick& other) { *this = other; } + + /// @brief Destructor. + /// + ~Joystick(void) override = default; + + /// @brief Copy data from another @ref Joystick class to here. + /// + /// @param[in] other Other class to copy here + Joystick& operator=(const Joystick& rhs) + { + if (this != &rhs) + { + Peripheral::operator=(rhs); + + m_provider = rhs.m_provider; + m_requestedPort = rhs.m_requestedPort; + m_buttonCount = rhs.m_buttonCount; + m_hatCount = rhs.m_hatCount; + m_axisCount = rhs.m_axisCount; + m_motorCount = rhs.m_motorCount; + m_supportsPowerOff = rhs.m_supportsPowerOff; + } + return *this; + } + + /// @brief Get provider name. + /// + /// @return Name of provider + const std::string& Provider(void) const { return m_provider; } + + /// @brief Get requested port number. + /// + /// @return Port + int RequestedPort(void) const { return m_requestedPort; } + + /// @brief Get button count. + /// + /// @return Button count + unsigned int ButtonCount(void) const { return m_buttonCount; } + + /// @brief Get hat count. + /// + /// @return Hat count + unsigned int HatCount(void) const { return m_hatCount; } + + /// @brief Get axis count. + /// + /// @return Axis count + unsigned int AxisCount(void) const { return m_axisCount; } + + /// @brief Get motor count. + /// + /// @return Motor count + unsigned int MotorCount(void) const { return m_motorCount; } + + /// @brief Get supports power off. + /// + /// @return True if power off is supported, false otherwise + bool SupportsPowerOff(void) const { return m_supportsPowerOff; } + + /// @brief Set provider name. + /// + /// @param[in] provider Name of provider + void SetProvider(const std::string& provider) { m_provider = provider; } + + /// @brief Get requested port number. + /// + /// @param[in] requestedPort Port + void SetRequestedPort(int requestedPort) { m_requestedPort = requestedPort; } + + /// @brief Get button count. + /// + /// @param[in] buttonCount Button count + void SetButtonCount(unsigned int buttonCount) { m_buttonCount = buttonCount; } + + /// @brief Get hat count. + /// + /// @param[in] hatCount Hat count + void SetHatCount(unsigned int hatCount) { m_hatCount = hatCount; } + + /// @brief Get axis count. + /// + /// @param[in] axisCount Axis count + void SetAxisCount(unsigned int axisCount) { m_axisCount = axisCount; } + + /// @brief Get motor count. + /// + /// @param[in] motorCount Motor count + void SetMotorCount(unsigned int motorCount) { m_motorCount = motorCount; } + + /// @brief Get supports power off. + /// + /// @param[in] supportsPowerOff True if power off is supported, false otherwise + void SetSupportsPowerOff(bool supportsPowerOff) { m_supportsPowerOff = supportsPowerOff; } + + ///@} + + explicit Joystick(const JOYSTICK_INFO& info) + : Peripheral(info.peripheral), + m_provider(info.provider ? info.provider : ""), + m_requestedPort(info.requested_port), + m_buttonCount(info.button_count), + m_hatCount(info.hat_count), + m_axisCount(info.axis_count), + m_motorCount(info.motor_count), + m_supportsPowerOff(info.supports_poweroff) + { + } + + void ToStruct(JOYSTICK_INFO& info) const + { + Peripheral::ToStruct(info.peripheral); + + info.provider = new char[m_provider.size() + 1]; + info.requested_port = m_requestedPort; + info.button_count = m_buttonCount; + info.hat_count = m_hatCount; + info.axis_count = m_axisCount; + info.motor_count = m_motorCount; + info.supports_poweroff = m_supportsPowerOff; + + std::strcpy(info.provider, m_provider.c_str()); + } + + static void FreeStruct(JOYSTICK_INFO& info) + { + Peripheral::FreeStruct(info.peripheral); + + PERIPHERAL_SAFE_DELETE_ARRAY(info.provider); + } + +private: + std::string m_provider; + int m_requestedPort; + unsigned int m_buttonCount = 0; + unsigned int m_hatCount = 0; + unsigned int m_axisCount = 0; + unsigned int m_motorCount = 0; + bool m_supportsPowerOff = false; +}; +///@} +//------------------------------------------------------------------------------ + +typedef PeripheralVector Joysticks; + +class JoystickFeature; + +//============================================================================== +/// @defgroup cpp_kodi_addon_peripheral_Defs_Joystick_DriverPrimitive class DriverPrimitive +/// @ingroup cpp_kodi_addon_peripheral_Defs_Joystick +/// @brief **Base class for joystick driver primitives** +/// +/// A driver primitive can be: +/// +/// 1. a button +/// 2. a hat direction +/// 3. a semiaxis (either the positive or negative half of an axis) +/// 4. a motor +/// 5. a keyboard key +/// 6. a mouse button +/// 7. a relative pointer direction +/// +/// The type determines the fields in use: +/// +/// Button: +/// - driver index +/// +/// Hat direction: +/// - driver index +/// - hat direction +/// +/// Semiaxis: +/// - driver index +/// - center +/// - semiaxis direction +/// - range +/// +/// Motor: +/// - driver index +/// +/// Key: +/// - key code +/// +/// Mouse button: +/// - driver index +/// +/// Relative pointer direction: +/// - relative pointer direction +/// +///@{ +struct DriverPrimitive +{ +protected: + /*! + * \brief Construct a driver primitive of the specified type + */ + DriverPrimitive(JOYSTICK_DRIVER_PRIMITIVE_TYPE type, unsigned int driverIndex) + : m_type(type), m_driverIndex(driverIndex) + { + } + +public: + /// @addtogroup cpp_kodi_addon_peripheral_Defs_Joystick_DriverPrimitive + ///@{ + + /// @brief Construct an invalid driver primitive. + DriverPrimitive(void) = default; + + /// @brief Construct a driver primitive representing a joystick button. + /// + /// @param[in] buttonIndex Index + /// @return Created class + static DriverPrimitive CreateButton(unsigned int buttonIndex) + { + return DriverPrimitive(JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON, buttonIndex); + } + + /// @brief Construct a driver primitive representing one of the four direction + /// arrows on a dpad. + /// + /// @param[in] hatIndex Hat index + /// @param[in] direction With @ref JOYSTICK_DRIVER_HAT_DIRECTION defined direction + DriverPrimitive(unsigned int hatIndex, JOYSTICK_DRIVER_HAT_DIRECTION direction) + : m_type(JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION), + m_driverIndex(hatIndex), + m_hatDirection(direction) + { + } + + /// @brief Construct a driver primitive representing the positive or negative + /// half of an axis. + /// + /// @param[in] axisIndex Axis index + /// @param[in] center Center + /// @param[in] direction With @ref JOYSTICK_DRIVER_HAT_DIRECTION defined direction + /// @param[in] range Range + DriverPrimitive(unsigned int axisIndex, + int center, + JOYSTICK_DRIVER_SEMIAXIS_DIRECTION direction, + unsigned int range) + : m_type(JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS), + m_driverIndex(axisIndex), + m_center(center), + m_semiAxisDirection(direction), + m_range(range) + { + } + + /// @brief Construct a driver primitive representing a motor. + /// + /// @param[in] motorIndex Motor index number + /// @return Constructed driver primitive representing a motor + static DriverPrimitive CreateMotor(unsigned int motorIndex) + { + return DriverPrimitive(JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR, motorIndex); + } + + /// @brief Construct a driver primitive representing a key on a keyboard. + /// + /// @param[in] keycode Keycode to use + DriverPrimitive(std::string keycode) + : m_type(JOYSTICK_DRIVER_PRIMITIVE_TYPE_KEY), m_keycode(std::move(keycode)) + { + } + + /// @brief Construct a driver primitive representing a mouse button. + /// + /// @param[in] buttonIndex Index + /// @return Constructed driver primitive representing a mouse button + static DriverPrimitive CreateMouseButton(JOYSTICK_DRIVER_MOUSE_INDEX buttonIndex) + { + return DriverPrimitive(JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOUSE_BUTTON, + static_cast(buttonIndex)); + } + + /// @brief Construct a driver primitive representing one of the four + /// direction in which a relative pointer can move + /// + /// @param[in] direction With @ref JOYSTICK_DRIVER_RELPOINTER_DIRECTION defined direction + DriverPrimitive(JOYSTICK_DRIVER_RELPOINTER_DIRECTION direction) + : m_type(JOYSTICK_DRIVER_PRIMITIVE_TYPE_RELPOINTER_DIRECTION), m_relPointerDirection(direction) + { + } + + /// @brief Get type of primitive. + /// + /// @return The with @ref JOYSTICK_DRIVER_PRIMITIVE_TYPE defined type + JOYSTICK_DRIVER_PRIMITIVE_TYPE Type(void) const { return m_type; } + + /// @brief Get driver index. + /// + /// @return Index number + unsigned int DriverIndex(void) const { return m_driverIndex; } + + /// @brief Get hat direction + /// + /// @return The with @ref JOYSTICK_DRIVER_HAT_DIRECTION defined direction + JOYSTICK_DRIVER_HAT_DIRECTION HatDirection(void) const { return m_hatDirection; } + + /// @brief Get center + /// + /// @return Center + int Center(void) const { return m_center; } + + /// @brief Get semi axis direction + /// + /// @return With @ref JOYSTICK_DRIVER_SEMIAXIS_DIRECTION defined direction + JOYSTICK_DRIVER_SEMIAXIS_DIRECTION SemiAxisDirection(void) const { return m_semiAxisDirection; } + + /// @brief Get range. + /// + /// @return Range + unsigned int Range(void) const { return m_range; } + + /// @brief Get key code as string. + /// + /// @return Key code + const std::string& Keycode(void) const { return m_keycode; } + + /// @brief Get mouse index + /// + /// @return With @ref JOYSTICK_DRIVER_MOUSE_INDEX defined mouse index + JOYSTICK_DRIVER_MOUSE_INDEX MouseIndex(void) const + { + return static_cast(m_driverIndex); + } + + /// @brief Get relative pointer direction. + /// + /// @return With @ref JOYSTICK_DRIVER_RELPOINTER_DIRECTION defined direction + JOYSTICK_DRIVER_RELPOINTER_DIRECTION RelPointerDirection(void) const + { + return m_relPointerDirection; + } + + /// @brief Compare this with another class of this type. + /// + /// @param[in] other Other class to compare + /// @return True if they are equal, false otherwise + bool operator==(const DriverPrimitive& other) const + { + if (m_type == other.m_type) + { + switch (m_type) + { + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON: + { + return m_driverIndex == other.m_driverIndex; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION: + { + return m_driverIndex == other.m_driverIndex && m_hatDirection == other.m_hatDirection; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS: + { + return m_driverIndex == other.m_driverIndex && m_center == other.m_center && + m_semiAxisDirection == other.m_semiAxisDirection && m_range == other.m_range; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_KEY: + { + return m_keycode == other.m_keycode; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR: + { + return m_driverIndex == other.m_driverIndex; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOUSE_BUTTON: + { + return m_driverIndex == other.m_driverIndex; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_RELPOINTER_DIRECTION: + { + return m_relPointerDirection == other.m_relPointerDirection; + } + default: + break; + } + } + return false; + } + + ///@} + + explicit DriverPrimitive(const JOYSTICK_DRIVER_PRIMITIVE& primitive) : m_type(primitive.type) + { + switch (m_type) + { + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON: + { + m_driverIndex = primitive.button.index; + break; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION: + { + m_driverIndex = primitive.hat.index; + m_hatDirection = primitive.hat.direction; + break; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS: + { + m_driverIndex = primitive.semiaxis.index; + m_center = primitive.semiaxis.center; + m_semiAxisDirection = primitive.semiaxis.direction; + m_range = primitive.semiaxis.range; + break; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR: + { + m_driverIndex = primitive.motor.index; + break; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_KEY: + { + m_keycode = primitive.key.keycode; + break; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOUSE_BUTTON: + { + m_driverIndex = primitive.mouse.button; + break; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_RELPOINTER_DIRECTION: + { + m_relPointerDirection = primitive.relpointer.direction; + break; + } + default: + break; + } + } + + void ToStruct(JOYSTICK_DRIVER_PRIMITIVE& driver_primitive) const + { + driver_primitive.type = m_type; + switch (m_type) + { + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON: + { + driver_primitive.button.index = m_driverIndex; + break; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION: + { + driver_primitive.hat.index = m_driverIndex; + driver_primitive.hat.direction = m_hatDirection; + break; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS: + { + driver_primitive.semiaxis.index = m_driverIndex; + driver_primitive.semiaxis.center = m_center; + driver_primitive.semiaxis.direction = m_semiAxisDirection; + driver_primitive.semiaxis.range = m_range; + break; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR: + { + driver_primitive.motor.index = m_driverIndex; + break; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_KEY: + { + const size_t size = sizeof(driver_primitive.key.keycode); + std::strncpy(driver_primitive.key.keycode, m_keycode.c_str(), size - 1); + driver_primitive.key.keycode[size - 1] = '\0'; + break; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOUSE_BUTTON: + { + driver_primitive.mouse.button = static_cast(m_driverIndex); + break; + } + case JOYSTICK_DRIVER_PRIMITIVE_TYPE_RELPOINTER_DIRECTION: + { + driver_primitive.relpointer.direction = m_relPointerDirection; + break; + } + default: + break; + } + } + + static void FreeStruct(JOYSTICK_DRIVER_PRIMITIVE& primitive) { (void)primitive; } + +private: + JOYSTICK_DRIVER_PRIMITIVE_TYPE m_type = JOYSTICK_DRIVER_PRIMITIVE_TYPE_UNKNOWN; + unsigned int m_driverIndex = 0; + JOYSTICK_DRIVER_HAT_DIRECTION m_hatDirection = JOYSTICK_DRIVER_HAT_UNKNOWN; + int m_center = 0; + JOYSTICK_DRIVER_SEMIAXIS_DIRECTION m_semiAxisDirection = JOYSTICK_DRIVER_SEMIAXIS_UNKNOWN; + unsigned int m_range = 1; + std::string m_keycode; + JOYSTICK_DRIVER_RELPOINTER_DIRECTION m_relPointerDirection = JOYSTICK_DRIVER_RELPOINTER_UNKNOWN; +}; +///@} +//------------------------------------------------------------------------------ + +typedef PeripheralVector DriverPrimitives; + +//============================================================================== +/// @defgroup cpp_kodi_addon_peripheral_Defs_Joystick_JoystickFeature class JoystickFeature +/// @ingroup cpp_kodi_addon_peripheral_Defs_Joystick +/// @brief **Base class for joystick feature primitives** +/// +/// Class for joystick features. A feature can be: +/// +/// 1. scalar *[1]* +/// 2. analog stick +/// 3. accelerometer +/// 4. motor +/// 5. relative pointer *[2]* +/// 6. absolute pointer +/// 7. wheel +/// 8. throttle +/// 9. keyboard key +/// +/// *[1]* All three driver primitives (buttons, hats and axes) have a state that +/// can be represented using a single scalar value. For this reason, +/// features that map to a single primitive are called "scalar features". +/// +/// *[2]* Relative pointers are similar to analog sticks, but they use +/// relative distances instead of positions. +/// +///@{ +class JoystickFeature +{ +public: + /// @addtogroup cpp_kodi_addon_peripheral_Defs_Joystick_JoystickFeature + ///@{ + + /// @brief Class constructor. + /// + /// @param[in] name [optional] Name of the feature + /// @param[in] type [optional] Type of the feature, @ref JOYSTICK_FEATURE_TYPE_UNKNOWN + /// as default + JoystickFeature(const std::string& name = "", + JOYSTICK_FEATURE_TYPE type = JOYSTICK_FEATURE_TYPE_UNKNOWN) + : m_name(name), m_type(type), m_primitives{} + { + } + + /// @brief Class copy constructor. + /// + /// @param[in] other Other class to copy on construct here + JoystickFeature(const JoystickFeature& other) { *this = other; } + + /// @brief Copy data from another @ref JoystickFeature class to here. + /// + /// @param[in] other Other class to copy here + JoystickFeature& operator=(const JoystickFeature& rhs) + { + if (this != &rhs) + { + m_name = rhs.m_name; + m_type = rhs.m_type; + m_primitives = rhs.m_primitives; + } + return *this; + } + + /// @brief Compare this with another class of this type. + /// + /// @param[in] other Other class to compare + /// @return True if they are equal, false otherwise + bool operator==(const JoystickFeature& other) const + { + return m_name == other.m_name && m_type == other.m_type && m_primitives == other.m_primitives; + } + + /// @brief Get name of feature. + /// + /// @return Name of feature + const std::string& Name(void) const { return m_name; } + + /// @brief Get name of feature. + /// + /// @return Type of feature defined with @ref JOYSTICK_FEATURE_TYPE + JOYSTICK_FEATURE_TYPE Type(void) const { return m_type; } + + /// @brief Check this feature is valid. + /// + /// @return True if valid (type != JOYSTICK_FEATURE_TYPE_UNKNOWN), false otherwise + bool IsValid() const { return m_type != JOYSTICK_FEATURE_TYPE_UNKNOWN; } + + /// @brief Set name of feature. + /// + /// @param[in] name Name of feature + void SetName(const std::string& name) { m_name = name; } + + /// @brief Set type of feature. + /// + /// @param[in] type Type of feature + void SetType(JOYSTICK_FEATURE_TYPE type) { m_type = type; } + + /// @brief Set type as invalid. + void SetInvalid(void) { m_type = JOYSTICK_FEATURE_TYPE_UNKNOWN; } + + /// @brief Get primitive of feature by wanted type. + /// + /// @param[in] which Type of feature, defined with @ref JOYSTICK_FEATURE_PRIMITIVE + /// @return Primitive of asked type + const DriverPrimitive& Primitive(JOYSTICK_FEATURE_PRIMITIVE which) const + { + return m_primitives[which]; + } + + /// @brief Set primitive for feature by wanted type. + /// + /// @param[in] which Type of feature, defined with @ref JOYSTICK_FEATURE_PRIMITIVE + /// @param[in] primitive The with @ref DriverPrimitive defined primitive to set + void SetPrimitive(JOYSTICK_FEATURE_PRIMITIVE which, const DriverPrimitive& primitive) + { + m_primitives[which] = primitive; + } + + /// @brief Get all primitives on this class. + /// + /// @return Array list of primitives + std::array& Primitives() { return m_primitives; } + + /// @brief Get all primitives on this class (as constant). + /// + /// @return Constant a´rray list of primitives + const std::array& Primitives() const + { + return m_primitives; + } + + ///@} + + explicit JoystickFeature(const JOYSTICK_FEATURE& feature) + : m_name(feature.name ? feature.name : ""), m_type(feature.type) + { + for (unsigned int i = 0; i < JOYSTICK_PRIMITIVE_MAX; i++) + m_primitives[i] = DriverPrimitive(feature.primitives[i]); + } + + void ToStruct(JOYSTICK_FEATURE& feature) const + { + feature.name = new char[m_name.length() + 1]; + feature.type = m_type; + for (unsigned int i = 0; i < JOYSTICK_PRIMITIVE_MAX; i++) + m_primitives[i].ToStruct(feature.primitives[i]); + + std::strcpy(feature.name, m_name.c_str()); + } + + static void FreeStruct(JOYSTICK_FEATURE& feature) { PERIPHERAL_SAFE_DELETE_ARRAY(feature.name); } + +private: + std::string m_name; + JOYSTICK_FEATURE_TYPE m_type; + std::array m_primitives; +}; +///@} +//------------------------------------------------------------------------------ + +typedef PeripheralVector JoystickFeatures; + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/CMakeLists.txt new file mode 100644 index 0000000..3443b1e --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/CMakeLists.txt @@ -0,0 +1,13 @@ +set(HEADERS ChannelGroups.h + Channels.h + EDL.h + EPG.h + General.h + MenuHook.h + Recordings.h + Stream.h + Timers.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_addon-instance_pvr) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/ChannelGroups.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/ChannelGroups.h new file mode 100644 index 0000000..17995bb --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/ChannelGroups.h @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/addon-instance/pvr.h" + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" Definitions group 3 - PVR channel group +#ifdef __cplusplus + +namespace kodi +{ +namespace addon +{ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup class PVRChannelGroup +/// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup +/// @brief **PVR add-on channel group**\n +/// To define a group for channels, this becomes be asked from +/// @ref kodi::addon::CInstancePVRClient::GetChannelGroups() and used on +/// @ref kodi::addon::CInstancePVRClient::GetChannelGroupMembers() to get his +/// content with @ref cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember "PVRChannelGroupMember". +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup_Help +/// +///@{ +class PVRChannelGroup : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVRChannelGroup() { memset(m_cStructure, 0, sizeof(PVR_CHANNEL_GROUP)); } + PVRChannelGroup(const PVRChannelGroup& channel) : CStructHdl(channel) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup : + /// | Name | Type | Set call | Get call | Usage + /// |------|------|----------|----------|----------- + /// | **Group name** | `std::string` | @ref PVRChannelGroup::SetGroupName "SetGroupName" | @ref PVRChannelGroup::GetGroupName "GetGroupName" | *required to set* + /// | **Is radio** | `bool` | @ref PVRChannelGroup::SetIsRadio "SetIsRadio" | @ref PVRChannelGroup::GetIsRadio "GetIsRadio" | *required to set* + /// | **Position** | `unsigned int` | @ref PVRChannelGroup::SetPosition "SetPosition" | @ref PVRChannelGroup::GetPosition "GetPosition" | *optional* + /// + + /// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup + ///@{ + + /// @brief **required**\n + /// Name of this channel group. + void SetGroupName(const std::string& groupName) + { + strncpy(m_cStructure->strGroupName, groupName.c_str(), sizeof(m_cStructure->strGroupName) - 1); + } + + /// @brief To get with @ref SetGroupName changed values. + std::string GetGroupName() const { return m_cStructure->strGroupName; } + + /// @brief **required**\n + /// **true** If this is a radio channel group, **false** otherwise. + void SetIsRadio(bool isRadio) { m_cStructure->bIsRadio = isRadio; } + + /// @brief To get with @ref SetIsRadio changed values. + bool GetIsRadio() const { return m_cStructure->bIsRadio; } + + /// @brief **optional**\n + /// Sort position of the group (`0` indicates that the backend doesn't + /// support sorting of groups). + void SetPosition(unsigned int position) { m_cStructure->iPosition = position; } + + /// @brief To get with @ref SetPosition changed values. + unsigned int GetPosition() const { return m_cStructure->iPosition; } + + ///@} + +private: + PVRChannelGroup(const PVR_CHANNEL_GROUP* channel) : CStructHdl(channel) {} + PVRChannelGroup(PVR_CHANNEL_GROUP* channel) : CStructHdl(channel) {} +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupsResultSet class PVRChannelGroupsResultSet +/// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroup +/// @brief **PVR add-on channel group member transfer class**\n +/// To transfer the content of @ref kodi::addon::CInstancePVRClient::GetChannelGroups(). +/// +///@{ +class PVRChannelGroupsResultSet +{ +public: + /*! \cond PRIVATE */ + PVRChannelGroupsResultSet() = delete; + PVRChannelGroupsResultSet(const AddonInstance_PVR* instance, ADDON_HANDLE handle) + : m_instance(instance), m_handle(handle) + { + } + /*! \endcond */ + + + /// @addtogroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupsResultSet + ///@{ + + /// @brief To add and give content from addon to Kodi on related call. + /// + /// @param[in] tag The to transferred data. + void Add(const kodi::addon::PVRChannelGroup& tag) + { + m_instance->toKodi->TransferChannelGroup(m_instance->toKodi->kodiInstance, m_handle, tag); + } + + ///@} + +private: + const AddonInstance_PVR* m_instance = nullptr; + const ADDON_HANDLE m_handle; +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember class PVRChannelGroupMember +/// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup +/// @brief **PVR add-on channel group member**\n +/// To define the content of @ref kodi::addon::CInstancePVRClient::GetChannelGroups() +/// given groups. +/// +/// This content becomes then requested with @ref kodi::addon::CInstancePVRClient::GetChannelGroupMembers(). +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember_Help +/// +///@{ +class PVRChannelGroupMember : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVRChannelGroupMember() { memset(m_cStructure, 0, sizeof(PVR_CHANNEL_GROUP_MEMBER)); } + PVRChannelGroupMember(const PVRChannelGroupMember& channel) : CStructHdl(channel) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember : + /// | Name | Type | Set call | Get call | Usage + /// |-------|-------|-----------|----------|----------- + /// | **Group name** | `std::string` | @ref PVRChannelGroupMember::SetGroupName "SetGroupName" | @ref PVRChannelGroupMember::GetGroupName "GetGroupName" | *required to set* + /// | **Channel unique id** | `unsigned int` | @ref PVRChannelGroupMember::SetChannelUniqueId "SetChannelUniqueId" | @ref PVRChannelGroupMember::GetChannelUniqueId "GetChannelUniqueId" | *required to set* + /// | **Channel Number** | `unsigned int` | @ref PVRChannelGroupMember::SetChannelNumber "SetChannelNumber" | @ref PVRChannelGroupMember::GetChannelNumber "GetChannelNumber" | *optional* + /// | **Sub channel number** | `unsigned int` | @ref PVRChannelGroupMember::SetSubChannelNumber "SetSubChannelNumber"| @ref PVRChannelGroupMember::GetSubChannelNumber "GetSubChannelNumber" | *optional* + /// | **Order** | `int` | @ref PVRChannel::SetOrder "SetOrder" | @ref PVRChannel::GetOrder "GetOrder" | *optional* + /// + + /// @addtogroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember + ///@{ + + /// @brief **required**\n + /// Name of the channel group to add the channel to. + void SetGroupName(const std::string& groupName) + { + strncpy(m_cStructure->strGroupName, groupName.c_str(), sizeof(m_cStructure->strGroupName) - 1); + } + + /// @brief To get with @ref SetGroupName changed values. + std::string GetGroupName() const { return m_cStructure->strGroupName; } + + /// @brief **required**\n + /// Unique id of the member. + void SetChannelUniqueId(unsigned int channelUniqueId) + { + m_cStructure->iChannelUniqueId = channelUniqueId; + } + + /// @brief To get with @ref SetChannelUniqueId changed values. + unsigned int GetChannelUniqueId() const { return m_cStructure->iChannelUniqueId; } + + /// @brief **optional**\n + /// Channel number within the group. + void SetChannelNumber(unsigned int channelNumber) + { + m_cStructure->iChannelNumber = channelNumber; + } + + /// @brief To get with @ref SetChannelNumber changed values. + unsigned int GetChannelNumber() const { return m_cStructure->iChannelNumber; } + + /// @brief **optional**\n + /// Sub channel number within the group (ATSC). + void SetSubChannelNumber(unsigned int subChannelNumber) + { + m_cStructure->iSubChannelNumber = subChannelNumber; + } + + /// @brief To get with @ref SetSubChannelNumber changed values. + unsigned int GetSubChannelNumber() const { return m_cStructure->iSubChannelNumber; } + + /// @brief **optional**\n + /// The value denoting the order of this channel in the 'All channels' group. + void SetOrder(bool order) { m_cStructure->iOrder = order; } + + /// @brief To get with @ref SetOrder changed values. + bool GetOrder() const { return m_cStructure->iOrder; } + + ///@} + +private: + PVRChannelGroupMember(const PVR_CHANNEL_GROUP_MEMBER* channel) : CStructHdl(channel) {} + PVRChannelGroupMember(PVR_CHANNEL_GROUP_MEMBER* channel) : CStructHdl(channel) {} +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMembersResultSet class PVRChannelGroupMembersResultSet +/// @ingroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMember +/// @brief **PVR add-on channel group member transfer class**\n +/// To transfer the content of @ref kodi::addon::CInstancePVRClient::GetChannelGroupMembers(). +/// +///@{ +class PVRChannelGroupMembersResultSet +{ +public: + /*! \cond PRIVATE */ + PVRChannelGroupMembersResultSet() = delete; + PVRChannelGroupMembersResultSet(const AddonInstance_PVR* instance, ADDON_HANDLE handle) + : m_instance(instance), m_handle(handle) + { + } + /*! \endcond */ + + /// @addtogroup cpp_kodi_addon_pvr_Defs_ChannelGroup_PVRChannelGroupMembersResultSet + ///@{ + + /// @brief To add and give content from addon to Kodi on related call. + /// + /// @param[in] tag The to transferred data. + void Add(const kodi::addon::PVRChannelGroupMember& tag) + { + m_instance->toKodi->TransferChannelGroupMember(m_instance->toKodi->kodiInstance, m_handle, tag); + } + + ///@} + +private: + const AddonInstance_PVR* m_instance = nullptr; + const ADDON_HANDLE m_handle; +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Channels.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Channels.h new file mode 100644 index 0000000..9c2f5d2 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Channels.h @@ -0,0 +1,518 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/addon-instance/pvr.h" + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" Definitions group 2 - PVR channel +#ifdef __cplusplus + +namespace kodi +{ +namespace addon +{ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannel class PVRChannel +/// @ingroup cpp_kodi_addon_pvr_Defs_Channel +/// @brief **Channel data structure**\n +/// Representation of a TV or radio channel. +/// +/// This is used to store all the necessary TV or radio channel data and can +/// either provide the necessary data from / to Kodi for the associated +/// functions or can also be used in the addon to store its data. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRChannel_Help +/// +///@{ +class PVRChannel : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVRChannel() { memset(m_cStructure, 0, sizeof(PVR_CHANNEL)); } + PVRChannel(const PVRChannel& channel) : CStructHdl(channel) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannel_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannel + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Channel_PVRChannel : + /// | Name | Type | Set call | Get call | Usage + /// |------|------|----------|----------|----------- + /// | **Unique id** | `unsigned int` | @ref PVRChannel::SetUniqueId "SetUniqueId" | @ref PVRChannel::GetUniqueId "GetUniqueId" | *required to set* + /// | **Is radio** | `bool` | @ref PVRChannel::SetIsRadio "SetIsRadio" | @ref PVRChannel::GetIsRadio "GetIsRadio" | *required to set* + /// | **Channel number** | `unsigned int` | @ref PVRChannel::SetChannelNumber "SetChannelNumber" | @ref PVRChannel::GetChannelNumber "GetChannelNumber" | *optional* + /// | **Sub channel number** | `unsigned int` | @ref PVRChannel::SetSubChannelNumber "SetSubChannelNumber" | @ref PVRChannel::GetSubChannelNumber "GetSubChannelNumber" | *optional* + /// | **Channel name** | `std::string` | @ref PVRChannel::SetChannelName "SetChannelName" | @ref PVRChannel::GetChannelName "GetChannelName" | *optional* + /// | **Mime type** | `std::string` | @ref PVRChannel::SetMimeType "SetMimeType" | @ref PVRChannel::GetMimeType "GetMimeType" | *optional* + /// | **Encryption system** | `unsigned int` | @ref PVRChannel::SetEncryptionSystem "SetEncryptionSystem" | @ref PVRChannel::GetEncryptionSystem "GetEncryptionSystem" | *optional* + /// | **Icon path** | `std::string` | @ref PVRChannel::SetIconPath "SetIconPath" | @ref PVRChannel::GetIconPath "GetIconPath" | *optional* + /// | **Is hidden** | `bool` | @ref PVRChannel::SetIsHidden "SetIsHidden" | @ref PVRChannel::GetIsHidden "GetIsHidden" | *optional* + /// | **Has archive** | `bool` | @ref PVRChannel::SetHasArchive "SetHasArchive" | @ref PVRChannel::GetHasArchive "GetHasArchive" | *optional* + /// | **Order** | `int` | @ref PVRChannel::SetOrder "SetOrder" | @ref PVRChannel::GetOrder "GetOrder" | *optional* + /// + + /// @addtogroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannel + ///@{ + + /// @brief **required**\n + /// Unique identifier for this channel. + void SetUniqueId(unsigned int uniqueId) { m_cStructure->iUniqueId = uniqueId; } + + /// @brief To get with @ref SetUniqueId changed values. + unsigned int GetUniqueId() const { return m_cStructure->iUniqueId; } + + /// @brief **required**\n + /// **true** if this is a radio channel, **false** if it's a TV channel. + void SetIsRadio(bool isRadio) { m_cStructure->bIsRadio = isRadio; } + + /// @brief To get with @ref SetIsRadio changed values. + bool GetIsRadio() const { return m_cStructure->bIsRadio; } + + /// @brief **optional**\n + /// Channel number of this channel on the backend. + void SetChannelNumber(unsigned int channelNumber) + { + m_cStructure->iChannelNumber = channelNumber; + } + + /// @brief To get with @ref SetChannelNumber changed values. + unsigned int GetChannelNumber() const { return m_cStructure->iChannelNumber; } + + /// @brief **optional**\n + /// Sub channel number of this channel on the backend (ATSC). + void SetSubChannelNumber(unsigned int subChannelNumber) + { + m_cStructure->iSubChannelNumber = subChannelNumber; + } + + /// @brief To get with @ref SetSubChannelNumber changed values. + unsigned int GetSubChannelNumber() const { return m_cStructure->iSubChannelNumber; } + + /// @brief **optional**\n + /// Channel name given to this channel. + void SetChannelName(const std::string& channelName) + { + strncpy(m_cStructure->strChannelName, channelName.c_str(), + sizeof(m_cStructure->strChannelName) - 1); + } + + /// @brief To get with @ref SetChannelName changed values. + std::string GetChannelName() const { return m_cStructure->strChannelName; } + + /// @brief **optional**\n + /// Input format mime type. + /// + /// Available types can be found in https://www.iana.org/assignments/media-types/media-types.xhtml + /// on "application" and "video" or leave empty if unknown. + /// + void SetMimeType(const std::string& inputFormat) + { + strncpy(m_cStructure->strMimeType, inputFormat.c_str(), sizeof(m_cStructure->strMimeType) - 1); + } + + /// @brief To get with @ref SetMimeType changed values. + std::string GetMimeType() const { return m_cStructure->strMimeType; } + + /// @brief **optional**\n + /// The encryption ID or CaID of this channel (Conditional access systems). + /// + /// Lists about available ID's: + /// - http://www.dvb.org/index.php?id=174 + /// - http://en.wikipedia.org/wiki/Conditional_access_system + /// + void SetEncryptionSystem(unsigned int encryptionSystem) + { + m_cStructure->iEncryptionSystem = encryptionSystem; + } + + /// @brief To get with @ref SetEncryptionSystem changed values. + unsigned int GetEncryptionSystem() const { return m_cStructure->iEncryptionSystem; } + + /// @brief **optional**\n + /// Path to the channel icon (if present). + void SetIconPath(const std::string& iconPath) + { + strncpy(m_cStructure->strIconPath, iconPath.c_str(), sizeof(m_cStructure->strIconPath) - 1); + } + + /// @brief To get with @ref SetIconPath changed values. + std::string GetIconPath() const { return m_cStructure->strIconPath; } + + /// @brief **optional**\n + /// **true** if this channel is marked as hidden. + void SetIsHidden(bool isHidden) { m_cStructure->bIsHidden = isHidden; } + + /// @brief To get with @ref GetIsRadio changed values. + bool GetIsHidden() const { return m_cStructure->bIsHidden; } + + /// @brief **optional**\n + /// **true** if this channel has a server-side back buffer. + void SetHasArchive(bool hasArchive) { m_cStructure->bHasArchive = hasArchive; } + + /// @brief To get with @ref GetIsRadio changed values. + bool GetHasArchive() const { return m_cStructure->bHasArchive; } + + /// @brief **optional**\n + /// The value denoting the order of this channel in the 'All channels' group. + void SetOrder(bool order) { m_cStructure->iOrder = order; } + + /// @brief To get with @ref SetOrder changed values. + bool GetOrder() const { return m_cStructure->iOrder; } + ///@} + +private: + PVRChannel(const PVR_CHANNEL* channel) : CStructHdl(channel) {} + PVRChannel(PVR_CHANNEL* channel) : CStructHdl(channel) {} +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannelsResultSet class PVRChannelsResultSet +/// @ingroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannel +/// @brief **PVR add-on channel transfer class**\n +/// To transfer the content of @ref kodi::addon::CInstancePVRClient::GetChannels(). +/// +///@{ +class PVRChannelsResultSet +{ +public: + /*! \cond PRIVATE */ + PVRChannelsResultSet() = delete; + PVRChannelsResultSet(const AddonInstance_PVR* instance, ADDON_HANDLE handle) + : m_instance(instance), m_handle(handle) + { + } + /*! \endcond */ + + /// @addtogroup cpp_kodi_addon_pvr_Defs_Channel_PVRChannelsResultSet + ///@{ + + /// @brief To add and give content from addon to Kodi on related call. + /// + /// @param[in] tag The to transferred data. + void Add(const kodi::addon::PVRChannel& tag) + { + m_instance->toKodi->TransferChannelEntry(m_instance->toKodi->kodiInstance, m_handle, tag); + } + + ///@} + +private: + const AddonInstance_PVR* m_instance = nullptr; + const ADDON_HANDLE m_handle; +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus class PVRSignalStatus +/// @ingroup cpp_kodi_addon_pvr_Defs_Channel +/// @brief **PVR Signal status information**\n +/// This class gives current status information from stream to Kodi. +/// +/// Used to get information for user by call of @ref kodi::addon::CInstancePVRClient::GetSignalStatus() +/// to see current quality and source. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus_Help +/// +///@{ +class PVRSignalStatus : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVRSignalStatus() = default; + PVRSignalStatus(const PVRSignalStatus& type) : CStructHdl(type) {} + /*! \endcond */ + + + /// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus : + /// | Name | Type | Set call | Get call | Usage + /// |------|------|----------|----------|----------- + /// | **Adapter name** | `std::string` | @ref PVRSignalStatus::SetAdapterName "SetAdapterName" | @ref PVRSignalStatus::GetAdapterName "GetAdapterName" | *optional* + /// | **Adapter status** | `std::string` | @ref PVRSignalStatus::SetAdapterStatus "SetAdapterStatus" | @ref PVRSignalStatus::GetAdapterStatus "GetAdapterStatus" | *optional* + /// | **Service name** | `std::string` | @ref PVRSignalStatus::SetServiceName "SetServiceName" | @ref PVRSignalStatus::GetServiceName "GetServiceName" | *optional* + /// | **Provider name** | `std::string` | @ref PVRSignalStatus::SetProviderName "SetProviderName" | @ref PVRSignalStatus::GetProviderName "GetProviderName" | *optional* + /// | **Mux name** | `std::string` | @ref PVRSignalStatus::SetMuxName "SetMuxName" | @ref PVRSignalStatus::GetMuxName "GetMuxName" | *optional* + /// | **Signal/noise ratio** | `int` | @ref PVRSignalStatus::SetSNR "SetSNR" | @ref PVRSignalStatus::GetSNR "GetSNR" | *optional* + /// | **Signal strength** | `int` | @ref PVRSignalStatus::SetSignal "SetSignal" | @ref PVRSignalStatus::GetSignal "GetSignal" | *optional* + /// | **Bit error rate** | `long` | @ref PVRSignalStatus::SetBER "SetBER" | @ref PVRSignalStatus::GetBER "GetBER" | *optional* + /// | **Uncorrected blocks** | `long` | @ref PVRSignalStatus::SetUNC "SetUNC" | @ref PVRSignalStatus::GetUNC "GetUNC" | *optional* + /// + + /// @addtogroup cpp_kodi_addon_pvr_Defs_Channel_PVRSignalStatus + ///@{ + + /// @brief **optional**\n + /// Name of the adapter that's being used. + void SetAdapterName(const std::string& adapterName) + { + strncpy(m_cStructure->strAdapterName, adapterName.c_str(), + sizeof(m_cStructure->strAdapterName) - 1); + } + + /// @brief To get with @ref SetAdapterName changed values. + std::string GetAdapterName() const { return m_cStructure->strAdapterName; } + + /// @brief **optional**\n + /// Status of the adapter that's being used. + void SetAdapterStatus(const std::string& adapterStatus) + { + strncpy(m_cStructure->strAdapterStatus, adapterStatus.c_str(), + sizeof(m_cStructure->strAdapterStatus) - 1); + } + + /// @brief To get with @ref SetAdapterStatus changed values. + std::string GetAdapterStatus() const { return m_cStructure->strAdapterStatus; } + + /// @brief **optional**\n + /// Name of the current service. + void SetServiceName(const std::string& serviceName) + { + strncpy(m_cStructure->strServiceName, serviceName.c_str(), + sizeof(m_cStructure->strServiceName) - 1); + } + + /// @brief To get with @ref SetServiceName changed values. + std::string GetServiceName() const { return m_cStructure->strServiceName; } + + /// @brief **optional**\n + /// Name of the current service's provider. + void SetProviderName(const std::string& providerName) + { + strncpy(m_cStructure->strProviderName, providerName.c_str(), + sizeof(m_cStructure->strProviderName) - 1); + } + + /// @brief To get with @ref SetProviderName changed values. + std::string GetProviderName() const { return m_cStructure->strProviderName; } + + /// @brief **optional**\n + /// Name of the current mux. + void SetMuxName(const std::string& muxName) + { + strncpy(m_cStructure->strMuxName, muxName.c_str(), sizeof(m_cStructure->strMuxName) - 1); + } + + /// @brief To get with @ref SetMuxName changed values. + std::string GetMuxName() const { return m_cStructure->strMuxName; } + + /// @brief **optional**\n + /// Signal/noise ratio. + /// + /// @note 100% is 0xFFFF 65535 + void SetSNR(int snr) { m_cStructure->iSNR = snr; } + + /// @brief To get with @ref SetSNR changed values. + int GetSNR() const { return m_cStructure->iSNR; } + + /// @brief **optional**\n + /// Signal strength. + /// + /// @note 100% is 0xFFFF 65535 + void SetSignal(int signal) { m_cStructure->iSignal = signal; } + + /// @brief To get with @ref SetSignal changed values. + int GetSignal() const { return m_cStructure->iSignal; } + + /// @brief **optional**\n + /// Bit error rate. + void SetBER(long ber) { m_cStructure->iBER = ber; } + + /// @brief To get with @ref SetBER changed values. + long GetBER() const { return m_cStructure->iBER; } + + /// @brief **optional**\n + /// Uncorrected blocks: + void SetUNC(long unc) { m_cStructure->iUNC = unc; } + + /// @brief To get with @ref SetBER changed values. + long GetUNC() const { return m_cStructure->iUNC; } + ///@} + +private: + PVRSignalStatus(const PVR_SIGNAL_STATUS* type) : CStructHdl(type) {} + PVRSignalStatus(PVR_SIGNAL_STATUS* type) : CStructHdl(type) {} +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo class PVRDescrambleInfo +/// @ingroup cpp_kodi_addon_pvr_Defs_Channel +/// @brief **Data structure for descrample info**\n +/// Information data to give via this to Kodi. +/// +/// As description see also here https://en.wikipedia.org/wiki/Conditional_access. +/// +/// Used on @ref kodi::addon::CInstancePVRClient::GetDescrambleInfo(). +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo_Help +/// +///@{ +class PVRDescrambleInfo : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVRDescrambleInfo() + { + m_cStructure->iPid = PVR_DESCRAMBLE_INFO_NOT_AVAILABLE; + m_cStructure->iCaid = PVR_DESCRAMBLE_INFO_NOT_AVAILABLE; + m_cStructure->iProvid = PVR_DESCRAMBLE_INFO_NOT_AVAILABLE; + m_cStructure->iEcmTime = PVR_DESCRAMBLE_INFO_NOT_AVAILABLE; + m_cStructure->iHops = PVR_DESCRAMBLE_INFO_NOT_AVAILABLE; + } + PVRDescrambleInfo(const PVRDescrambleInfo& type) : CStructHdl(type) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo : + /// | Name | Type | Set call | Get call | Usage + /// |------|------|----------|----------|----------- + /// | **Packet identifier** | `int` | @ref PVRDescrambleInfo::SetPID "SetPID" | @ref PVRDescrambleInfo::GetPID "GetPID" | *optional* + /// | **Conditional access identifier** | `int` | @ref PVRDescrambleInfo::SetCAID "SetCAID" | @ref PVRDescrambleInfo::GetCAID "GetCAID" | *optional* + /// | **Provider-ID** | `int` | @ref PVRDescrambleInfo::SetProviderID "SetProviderID" | @ref PVRDescrambleInfo::GetProviderID "GetProviderID" | *optional* + /// | **ECM time** | `int` | @ref PVRDescrambleInfo::SetECMTime "SetECMTime" | @ref PVRDescrambleInfo::GetECMTime "GetECMTime" | *optional* + /// | **Hops** | `int` | @ref PVRDescrambleInfo::SetHops "SetHops" | @ref PVRDescrambleInfo::GetHops "GetHops" | *optional* + /// | **Descramble card system** | `std::string` | @ref PVRDescrambleInfo::SetHops "SetHops" | @ref PVRDescrambleInfo::GetHops "GetHops" | *optional* + /// | **Reader** | `std::string` | @ref PVRDescrambleInfo::SetReader "SetReader" | @ref PVRDescrambleInfo::GetReader "GetReader" | *optional* + /// | **From** | `std::string` | @ref PVRDescrambleInfo::SetFrom "SetFrom" | @ref PVRDescrambleInfo::GetFrom "GetFrom" | *optional* + /// | **Protocol** | `std::string` | @ref PVRDescrambleInfo::SetProtocol "SetProtocol" | @ref PVRDescrambleInfo::GetProtocol "GetProtocol" | *optional* + /// + + /// @addtogroup cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo + ///@{ + + /// @brief **optional**\n + /// Packet identifier. + /// + /// Each table or elementary stream in a transport stream is identified by + /// a 13-bit packet identifier (PID). + /// + /// Is @ref PVR_DESCRAMBLE_INFO_NOT_AVAILABLE as default, if not available + void SetPID(int pid) { m_cStructure->iPid = pid; } + + /// @brief To get with @ref SetPID changed values + int GetPID() const { return m_cStructure->iPid; } + + /// @brief **optional**\n + /// Conditional access identifier. + /// + /// Conditional access (abbreviated CA) or conditional access system (abbreviated CAS) + /// is the protection of content by requiring certain criteria to be met before granting + /// access to the content. + /// + /// Available CA system ID's listed here https://www.dvbservices.com/identifiers/ca_system_id. + /// + /// @ref PVR_DESCRAMBLE_INFO_NOT_AVAILABLE if not available. + void SetCAID(int iCaid) { m_cStructure->iCaid = iCaid; } + + /// @brief To get with @ref SetCAID changed values. + int GetCAID() const { return m_cStructure->iCaid; } + + /// @brief **optional**\n + /// Provider-ID. + /// + /// Is @ref PVR_DESCRAMBLE_INFO_NOT_AVAILABLE as default, if not available. + void SetProviderID(int provid) { m_cStructure->iProvid = provid; } + + /// @brief To get with @ref SetProviderID changed values + int GetProviderID() const { return m_cStructure->iProvid; } + + /// @brief **optional**\n + /// ECM time. + /// + /// Is @ref PVR_DESCRAMBLE_INFO_NOT_AVAILABLE as default, if not available. + void SetECMTime(int ecmTime) { m_cStructure->iEcmTime = ecmTime; } + + /// @brief To get with @ref SetECMTime changed values. + int GetECMTime() const { return m_cStructure->iEcmTime; } + + /// @brief **optional**\n + /// Hops. + /// + /// Is @ref PVR_DESCRAMBLE_INFO_NOT_AVAILABLE as default, if not available. + void SetHops(int hops) { m_cStructure->iHops = hops; } + + /// @brief To get with @ref SetHops changed values. + int GetHops() const { return m_cStructure->iHops; } + + /// @brief **optional**\n + /// Empty string if not available. + void SetCardSystem(const std::string& cardSystem) + { + strncpy(m_cStructure->strCardSystem, cardSystem.c_str(), + sizeof(m_cStructure->strCardSystem) - 1); + } + + /// @brief To get with @ref SetCardSystem changed values. + std::string GetCardSystem() const { return m_cStructure->strCardSystem; } + + /// @brief **optional**\n + /// Empty string if not available. + void SetReader(const std::string& reader) + { + strncpy(m_cStructure->strReader, reader.c_str(), sizeof(m_cStructure->strReader) - 1); + } + + /// @brief To get with @ref SetReader changed values. + std::string GetReader() const { return m_cStructure->strReader; } + + /// @brief **optional**\n + /// Empty string if not available. + void SetFrom(const std::string& from) + { + strncpy(m_cStructure->strFrom, from.c_str(), sizeof(m_cStructure->strFrom) - 1); + } + + /// @brief To get with @ref SetFrom changed values. + std::string GetFrom() const { return m_cStructure->strFrom; } + + /// @brief **optional**\n + /// Empty string if not available. + void SetProtocol(const std::string& protocol) + { + strncpy(m_cStructure->strProtocol, protocol.c_str(), sizeof(m_cStructure->strProtocol) - 1); + } + + /// @brief To get with @ref SetProtocol changed values. + std::string GetProtocol() const { return m_cStructure->strProtocol; } + ///@} + +private: + PVRDescrambleInfo(const PVR_DESCRAMBLE_INFO* type) : CStructHdl(type) {} + PVRDescrambleInfo(PVR_DESCRAMBLE_INFO* type) : CStructHdl(type) {} +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/EDL.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/EDL.h new file mode 100644 index 0000000..34c7c41 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/EDL.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/addon-instance/pvr/pvr_edl.h" + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" Definitions group 8 - PVR Edit definition list (EDL) +#ifdef __cplusplus + +namespace kodi +{ +namespace addon +{ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry class PVREDLEntry +/// @ingroup cpp_kodi_addon_pvr_Defs_EDLEntry +/// @brief **Edit definition list (EDL) entry**\n +/// Time places and type of related fields. +/// +/// This used within @ref cpp_kodi_addon_pvr_EPGTag "EPG" and +/// @ref cpp_kodi_addon_pvr_Recordings "recordings". +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry_Help +/// +///@{ +class PVREDLEntry : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVREDLEntry() { memset(m_cStructure, 0, sizeof(PVR_EDL_ENTRY)); } + PVREDLEntry(const PVREDLEntry& type) : CStructHdl(type) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry : + /// | Name | Type | Set call | Get call | Usage + /// |------|------|----------|----------|----------- + /// | **Start time** | `int64_t` | @ref PVREDLEntry::SetStart "SetStart" | @ref PVREDLEntry::GetStart "GetStart" | *required to set* + /// | **End time** | `int64_t` | @ref PVREDLEntry::SetEnd "SetEnd" | @ref PVREDLEntry::GetEnd "GetEnd" | *required to set* + /// | **Type** | @ref PVR_EDL_TYPE | @ref PVREDLEntry::SetType "SetType" | @ref PVREDLEntry::GetType "GetType" | *required to set* + /// + + /// @addtogroup cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry + ///@{ + + /// @brief Start time in milliseconds. + void SetStart(int64_t start) { m_cStructure->start = start; } + + /// @brief To get with @ref SetStart() changed values. + int64_t GetStart() const { return m_cStructure->start; } + + /// @brief End time in milliseconds. + void SetEnd(int64_t end) { m_cStructure->end = end; } + + /// @brief To get with @ref SetEnd() changed values. + int64_t GetEnd() const { return m_cStructure->end; } + + /// @brief The with @ref PVR_EDL_TYPE used definition list type. + void SetType(PVR_EDL_TYPE type) { m_cStructure->type = type; } + + /// @brief To get with @ref SetType() changed values. + PVR_EDL_TYPE GetType() const { return m_cStructure->type; } + ///@} + +private: + PVREDLEntry(const PVR_EDL_ENTRY* type) : CStructHdl(type) {} + PVREDLEntry(PVR_EDL_ENTRY* type) : CStructHdl(type) {} +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/EPG.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/EPG.h new file mode 100644 index 0000000..e1fc04f --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/EPG.h @@ -0,0 +1,500 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/addon-instance/pvr.h" + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" Definitions group 4 - PVR EPG +#ifdef __cplusplus + +namespace kodi +{ +namespace addon +{ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTag class PVREPGTag +/// @ingroup cpp_kodi_addon_pvr_Defs_epg +/// @brief **PVR add-on EPG data tag**\n +/// Representation of an EPG event. +/// +/// Herewith all EPG related data are saved in one class whereby the data can +/// be exchanged with Kodi, or can also be used on the addon to save there. +/// +/// See @ref cpp_kodi_addon_pvr_EPGTag "EPG methods" about usage. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_epg_PVREPGTag_Help +/// +///@{ +class PVREPGTag : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVREPGTag() + { + memset(m_cStructure, 0, sizeof(EPG_TAG)); + m_cStructure->iSeriesNumber = EPG_TAG_INVALID_SERIES_EPISODE; + m_cStructure->iEpisodeNumber = EPG_TAG_INVALID_SERIES_EPISODE; + m_cStructure->iEpisodePartNumber = EPG_TAG_INVALID_SERIES_EPISODE; + } + PVREPGTag(const PVREPGTag& epg) : CStructHdl(epg) + { + m_title = epg.m_title; + m_plotOutline = epg.m_plotOutline; + m_plot = epg.m_plot; + m_originalTitle = epg.m_originalTitle; + m_cast = epg.m_cast; + m_director = epg.m_director; + m_writer = epg.m_writer; + m_IMDBNumber = epg.m_IMDBNumber; + m_iconPath = epg.m_iconPath; + m_genreDescription = epg.m_genreDescription; + m_episodeName = epg.m_episodeName; + m_seriesLink = epg.m_seriesLink; + m_firstAired = epg.m_firstAired; + } + /*! \endcond */ + + + /// @defgroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTag_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTag + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag : + /// | Name | Type | Set call | Get call | Usage + /// |------|------|----------|----------|--------- + /// | **Unique broadcast id** | `unsigned int` | @ref PVREPGTag::SetUniqueBroadcastId "SetUniqueBroadcastId" | @ref PVREPGTag::GetUniqueBroadcastId "GetUniqueBroadcastId" | *required to set* + /// | **Unique channel id** | `unsigned int` | @ref PVREPGTag::SetUniqueChannelId "SetUniqueChannelId" | @ref PVREPGTag::GetUniqueChannelId "GetUniqueChannelId" | *required to set* + /// | **Title** | `std::string` | @ref PVREPGTag::SetTitle "SetTitle" | @ref PVREPGTag::GetTitle "GetTitle" | *required to set* + /// | **Start time** | `time_t` | @ref PVREPGTag::SetStartTime "SetStartTime" | @ref PVREPGTag::GetStartTime "GetStartTime" | *required to set* + /// | **End time** | `time_t` | @ref PVREPGTag::SetEndTime "SetEndTime" | @ref PVREPGTag::GetEndTime "GetEndTime" | *required to set* + /// | **Plot outline** | `std::string` | @ref PVREPGTag::SetPlotOutline "SetPlotOutline" | @ref PVREPGTag::GetPlotOutline "GetPlotOutline" | *optional* + /// | **Plot** | `std::string` | @ref PVREPGTag::SetPlot "SetPlot" | @ref PVREPGTag::GetPlot "GetPlot" | *optional* + /// | **Original title** | `std::string` | @ref PVREPGTag::SetOriginalTitle "SetOriginalTitle" | @ref PVREPGTag::GetOriginalTitle "GetOriginalTitle" | *optional* + /// | **Cast** | `std::string` | @ref PVREPGTag::SetCast "SetCast" | @ref PVREPGTag::GetCast "GetCast" | *optional* + /// | **Director** | `std::string` | @ref PVREPGTag::SetDirector "SetDirector" | @ref PVREPGTag::GetDirector "GetDirector" | *optional* + /// | **Writer** | `std::string` | @ref PVREPGTag::SetWriter "SetWriter" | @ref PVREPGTag::GetWriter "GetWriter" | *optional* + /// | **Year** | `int` | @ref PVREPGTag::SetYear "SetYear" | @ref PVREPGTag::GetYear "GetYear" | *optional* + /// | **IMDB number** | `std::string` | @ref PVREPGTag::SetIMDBNumber "SetIMDBNumber" | @ref PVREPGTag::GetIMDBNumber "GetIMDBNumber" | *optional* + /// | **Icon path** | `std::string` | @ref PVREPGTag::SetIconPath "SetIconPath" | @ref PVREPGTag::GetIconPath "GetIconPath" | *optional* + /// | **Genre type** | `int` | @ref PVREPGTag::SetGenreType "SetGenreType" | @ref PVREPGTag::GetGenreType "GetGenreType" | *optional* + /// | **Genre sub type** | `int` | @ref PVREPGTag::SetGenreSubType "SetGenreSubType" | @ref PVREPGTag::GetGenreSubType "GetGenreSubType" | *optional* + /// | **Genre description** | `std::string` | @ref PVREPGTag::SetGenreDescription "SetGenreDescription" | @ref PVREPGTag::GetGenreDescription "GetGenreDescription" | *optional* + /// | **First aired** | `time_t` | @ref PVREPGTag::SetFirstAired "SetFirstAired" | @ref PVREPGTag::GetFirstAired "GetFirstAired" | *optional* + /// | **Parental rating** | `int` | @ref PVREPGTag::SetParentalRating "SetParentalRating" | @ref PVREPGTag::GetParentalRating "GetParentalRating" | *optional* + /// | **Star rating** | `int` | @ref PVREPGTag::SetStarRating "SetStarRating" | @ref PVREPGTag::GetStarRating "GetStarRating" | *optional* + /// | **Series number** | `int` | @ref PVREPGTag::SetSeriesNumber "SetSeriesNumber" | @ref PVREPGTag::GetSeriesNumber "GetSeriesNumber" | *optional* + /// | **Episode number** | `int` | @ref PVREPGTag::SetEpisodeNumber "SetEpisodeNumber" | @ref PVREPGTag::GetEpisodeNumber "GetEpisodeNumber" | *optional* + /// | **Episode part number** | `int` | @ref PVREPGTag::SetEpisodePartNumber "SetEpisodePartNumber" | @ref PVREPGTag::GetEpisodePartNumber "GetEpisodePartNumber" | *optional* + /// | **Episode name** | `std::string` | @ref PVREPGTag::SetEpisodeName "SetEpisodeName" | @ref PVREPGTag::GetEpisodeName "GetEpisodeName" | *optional* + /// | **Flags** | `unsigned int` | @ref PVREPGTag::SetFlags "SetFlags" | @ref PVREPGTag::GetFlags "GetFlags" | *optional* + /// | **Series link** | `std::string` | @ref PVREPGTag::SetSeriesLink "SetSeriesLink" | @ref PVREPGTag::GetSeriesLink "GetSeriesLink" | *optional* + /// + + /// @addtogroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTag + ///@{ + + /// @brief **required**\n + /// Identifier for this event. Event uids must be unique for a channel. Valid uids must be greater than @ref EPG_TAG_INVALID_UID. + void SetUniqueBroadcastId(unsigned int uniqueBroadcastId) + { + m_cStructure->iUniqueBroadcastId = uniqueBroadcastId; + } + + /// @brief To get with @ref SetUniqueBroadcastId changed values. + unsigned int GetUniqueBroadcastId() const { return m_cStructure->iUniqueBroadcastId; } + + /// @brief **required**\n + /// Unique identifier of the channel this event belongs to. + void SetUniqueChannelId(unsigned int uniqueChannelId) + { + m_cStructure->iUniqueChannelId = uniqueChannelId; + } + + /// @brief To get with @ref SetUniqueChannelId changed values + unsigned int GetUniqueChannelId() const { return m_cStructure->iUniqueChannelId; } + + /// @brief **required**\n + /// This event's title. + void SetTitle(const std::string& title) { m_title = title; } + + /// @brief To get with @ref SetTitle changed values. + std::string GetTitle() const { return m_title; } + + /// @brief **required**\n + /// Start time in UTC. + /// + /// Seconds elapsed since 00:00 hours, Jan 1, 1970 UTC. + void SetStartTime(time_t startTime) { m_cStructure->startTime = startTime; } + + /// @brief To get with @ref SetStartTime changed values. + time_t GetStartTime() const { return m_cStructure->startTime; } + + /// @brief **required**\n + /// End time in UTC. + /// + /// Seconds elapsed since 00:00 hours, Jan 1, 1970 UTC. + void SetEndTime(time_t endTime) { m_cStructure->endTime = endTime; } + + /// @brief To get with @ref SetEndTime changed values. + time_t GetEndTime() const { return m_cStructure->endTime; } + + /// @brief **optional**\n + /// Plot outline name. + void SetPlotOutline(const std::string& plotOutline) { m_plotOutline = plotOutline; } + + /// @brief To get with @ref SetPlotOutline changed values. + std::string GetPlotOutline() const { return m_plotOutline; } + + /// @brief **optional**\n + /// Plot name. + void SetPlot(const std::string& plot) { m_plot = plot; } + + /// @brief To get with @ref GetPlot changed values. + std::string GetPlot() const { return m_plot; } + + /// @brief **optional**\n + /// Original title. + void SetOriginalTitle(const std::string& originalTitle) { m_originalTitle = originalTitle; } + + /// @brief To get with @ref SetOriginalTitle changed values + std::string GetOriginalTitle() const { return m_originalTitle; } + + /// @brief **optional**\n + /// Cast name(s). + /// + /// @note Use @ref EPG_STRING_TOKEN_SEPARATOR to separate different persons. + void SetCast(const std::string& cast) { m_cast = cast; } + + /// @brief To get with @ref SetCast changed values + std::string GetCast() const { return m_cast; } + + /// @brief **optional**\n + /// Director name(s). + /// + /// @note Use @ref EPG_STRING_TOKEN_SEPARATOR to separate different persons. + void SetDirector(const std::string& director) { m_director = director; } + + /// @brief To get with @ref SetDirector changed values. + std::string GetDirector() const { return m_director; } + + /// @brief **optional**\n + /// Writer name(s). + /// + /// @note Use @ref EPG_STRING_TOKEN_SEPARATOR to separate different persons. + void SetWriter(const std::string& writer) { m_writer = writer; } + + /// @brief To get with @ref SetDirector changed values + std::string GetWriter() const { return m_writer; } + + /// @brief **optional**\n + /// Year. + void SetYear(int year) { m_cStructure->iYear = year; } + + /// @brief To get with @ref SetYear changed values. + int GetYear() const { return m_cStructure->iYear; } + + /// @brief **optional**\n + /// [IMDB](https://en.wikipedia.org/wiki/IMDb) identification number. + void SetIMDBNumber(const std::string& IMDBNumber) { m_IMDBNumber = IMDBNumber; } + + /// @brief To get with @ref SetIMDBNumber changed values. + std::string GetIMDBNumber() const { return m_IMDBNumber; } + + /// @brief **optional**\n + /// Icon path. + void SetIconPath(const std::string& iconPath) { m_iconPath = iconPath; } + + /// @brief To get with @ref SetIconPath changed values. + std::string GetIconPath() const { return m_iconPath; } + + /// @brief **optional**\n + /// Genre type. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails EPG_EVENT_CONTENTMASK + /// + /// Use @ref EPG_GENRE_USE_STRING if type becomes given by @ref SetGenreDescription. + /// + /// @note If confirmed that backend brings the types in [ETSI EN 300 468](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) + /// conform values, can be @ref EPG_EVENT_CONTENTMASK ignored and to set here + /// with backend value. + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Example 1:** + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVREPGTag tag; + /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MOVIEDRAMA); + /// ~~~~~~~~~~~~~ + /// + /// -------------------------------------------------------------------------- + /// + /// **Example 2** (in case of other, not ETSI EN 300 468 conform genre types): + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVREPGTag tag; + /// tag.SetGenreType(EPG_GENRE_USE_STRING); + /// tag.SetGenreDescription("My special genre name"); // Should use (if possible) kodi::GetLocalizedString(...) to have match user language. + /// ~~~~~~~~~~~~~ + /// + void SetGenreType(int genreType) { m_cStructure->iGenreType = genreType; } + + /// @brief To get with @ref SetGenreType changed values + int GetGenreType() const { return m_cStructure->iGenreType; } + + /// @brief **optional**\n + /// Genre sub type. + /// + /// @copydetails EPG_EVENT_CONTENTMASK + /// + /// Subtypes groups related to set by @ref SetGenreType: + /// | Main genre type | List with available sub genre types + /// |-----------------|----------------------------------------- + /// | @ref EPG_EVENT_CONTENTMASK_UNDEFINED | Nothing, should be 0 + /// | @ref EPG_EVENT_CONTENTMASK_MOVIEDRAMA | @ref EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA + /// | @ref EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS | @ref EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS + /// | @ref EPG_EVENT_CONTENTMASK_SHOW | @ref EPG_EVENT_CONTENTSUBMASK_SHOW + /// | @ref EPG_EVENT_CONTENTMASK_SPORTS | @ref EPG_EVENT_CONTENTSUBMASK_SPORTS + /// | @ref EPG_EVENT_CONTENTMASK_CHILDRENYOUTH | @ref EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH + /// | @ref EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE | @ref EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE + /// | @ref EPG_EVENT_CONTENTMASK_ARTSCULTURE | @ref EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE + /// | @ref EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS | @ref EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS + /// | @ref EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE | @ref EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE + /// | @ref EPG_EVENT_CONTENTMASK_LEISUREHOBBIES | @ref EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES + /// | @ref EPG_EVENT_CONTENTMASK_SPECIAL | @ref EPG_EVENT_CONTENTSUBMASK_SPECIAL + /// | @ref EPG_EVENT_CONTENTMASK_USERDEFINED | Can be defined by you + /// | @ref EPG_GENRE_USE_STRING | **Kodi's own value**, which declares that the type with @ref SetGenreDescription is given. + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVREPGTag tag; + /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE); + /// tag.SetGenreSubType(EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_JAZZ); + /// ~~~~~~~~~~~~~ + /// + void SetGenreSubType(int genreSubType) { m_cStructure->iGenreSubType = genreSubType; } + + /// @brief To get with @ref SetGenreSubType changed values. + int GetGenreSubType() const { return m_cStructure->iGenreSubType; } + + /// @brief **optional**\n genre. Will be used only when genreType == @ref EPG_GENRE_USE_STRING + /// or genreSubType == @ref EPG_GENRE_USE_STRING. + /// + /// Use @ref EPG_STRING_TOKEN_SEPARATOR to separate different genres. + /// + /// In case of other, not [ETSI EN 300 468](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) + /// conform genre types or something special. + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVREPGTag tag; + /// tag.SetGenreType(EPG_GENRE_USE_STRING); + /// tag.SetGenreDescription("Action" + EPG_STRING_TOKEN_SEPARATOR + "Thriller"); + /// ~~~~~~~~~~~~~ + /// + void SetGenreDescription(const std::string& genreDescription) + { + m_genreDescription = genreDescription; + } + + /// @brief To get with @ref SetGenreDescription changed values. + std::string GetGenreDescription() const { return m_genreDescription; } + + /// @brief **optional**\n + /// First aired in UTC. + void SetFirstAired(const std::string& firstAired) { m_firstAired = firstAired; } + + /// @brief To get with @ref SetFirstAired changed values. + std::string GetFirstAired() const { return m_firstAired; } + + /// @brief **optional**\n + /// Parental rating. + void SetParentalRating(int parentalRating) { m_cStructure->iParentalRating = parentalRating; } + + /// @brief To get with @ref SetParentalRatinge changed values. + int GetParentalRating() const { return m_cStructure->iParentalRating; } + + /// @brief **optional**\n + /// Star rating. + void SetStarRating(int starRating) { m_cStructure->iStarRating = starRating; } + + /// @brief To get with @ref SetStarRating changed values. + int GetStarRating() const { return m_cStructure->iStarRating; } + + /// @brief **optional**\n + /// Series number. + void SetSeriesNumber(int seriesNumber) { m_cStructure->iSeriesNumber = seriesNumber; } + + /// @brief To get with @ref SetSeriesNumber changed values. + int GetSeriesNumber() const { return m_cStructure->iSeriesNumber; } + + /// @brief **optional**\n + /// Episode number. + void SetEpisodeNumber(int episodeNumber) { m_cStructure->iEpisodeNumber = episodeNumber; } + + /// @brief To get with @ref SetEpisodeNumber changed values. + int GetEpisodeNumber() const { return m_cStructure->iEpisodeNumber; } + + /// @brief **optional**\n + /// Episode part number. + void SetEpisodePartNumber(int episodePartNumber) + { + m_cStructure->iEpisodePartNumber = episodePartNumber; + } + + /// @brief To get with @ref SetEpisodePartNumber changed values. + int GetEpisodePartNumber() const { return m_cStructure->iEpisodePartNumber; } + + /// @brief **optional**\n + /// Episode name. + void SetEpisodeName(const std::string& episodeName) { m_episodeName = episodeName; } + + /// @brief To get with @ref SetEpisodeName changed values. + std::string GetEpisodeName() const { return m_episodeName; } + + /// @brief **optional**\n + /// Bit field of independent flags associated with the EPG entry. + /// + /// See @ref cpp_kodi_addon_pvr_Defs_epg_EPG_TAG_FLAG for available bit flags. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_epg_EPG_TAG_FLAG + /// + void SetFlags(unsigned int flags) { m_cStructure->iFlags = flags; } + + /// @brief To get with @ref SetFlags changed values. + unsigned int GetFlags() const { return m_cStructure->iFlags; } + + /// @brief **optional**\n + /// Series link for this event. + void SetSeriesLink(const std::string& seriesLink) { m_seriesLink = seriesLink; } + + /// @brief To get with @ref SetSeriesLink changed values. + std::string GetSeriesLink() const { return m_seriesLink; } + + ///@} + + // Internal used, as this have own memory for strings and to translate them to "C" + EPG_TAG* GetTag() const + { + m_cStructure->strTitle = m_title.c_str(); + m_cStructure->strPlotOutline = m_plotOutline.c_str(); + m_cStructure->strPlot = m_plot.c_str(); + m_cStructure->strOriginalTitle = m_originalTitle.c_str(); + m_cStructure->strCast = m_cast.c_str(); + m_cStructure->strDirector = m_director.c_str(); + m_cStructure->strWriter = m_writer.c_str(); + m_cStructure->strIMDBNumber = m_IMDBNumber.c_str(); + m_cStructure->strIconPath = m_iconPath.c_str(); + m_cStructure->strGenreDescription = m_genreDescription.c_str(); + m_cStructure->strEpisodeName = m_episodeName.c_str(); + m_cStructure->strSeriesLink = m_seriesLink.c_str(); + m_cStructure->strFirstAired = m_firstAired.c_str(); + + return m_cStructure; + } + +private: + PVREPGTag(const EPG_TAG* epg) : CStructHdl(epg) { SetData(epg); } + PVREPGTag(EPG_TAG* epg) : CStructHdl(epg) { SetData(epg); } + + const PVREPGTag& operator=(const PVREPGTag& right); + const PVREPGTag& operator=(const EPG_TAG& right); + operator EPG_TAG*(); + + std::string m_title; + std::string m_plotOutline; + std::string m_plot; + std::string m_originalTitle; + std::string m_cast; + std::string m_director; + std::string m_writer; + std::string m_IMDBNumber; + std::string m_episodeName; + std::string m_iconPath; + std::string m_seriesLink; + std::string m_genreDescription; + std::string m_firstAired; + + void SetData(const EPG_TAG* tag) + { + m_title = tag->strTitle == nullptr ? "" : tag->strTitle; + m_plotOutline = tag->strPlotOutline == nullptr ? "" : tag->strPlotOutline; + m_plot = tag->strPlot == nullptr ? "" : tag->strPlot; + m_originalTitle = tag->strOriginalTitle == nullptr ? "" : tag->strOriginalTitle; + m_cast = tag->strCast == nullptr ? "" : tag->strCast; + m_director = tag->strDirector == nullptr ? "" : tag->strDirector; + m_writer = tag->strWriter == nullptr ? "" : tag->strWriter; + m_IMDBNumber = tag->strIMDBNumber == nullptr ? "" : tag->strIMDBNumber; + m_iconPath = tag->strIconPath == nullptr ? "" : tag->strIconPath; + m_genreDescription = tag->strGenreDescription == nullptr ? "" : tag->strGenreDescription; + m_episodeName = tag->strEpisodeName == nullptr ? "" : tag->strEpisodeName; + m_seriesLink = tag->strSeriesLink == nullptr ? "" : tag->strSeriesLink; + m_firstAired = tag->strFirstAired == nullptr ? "" : tag->strFirstAired; + } +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTagsResultSet class PVREPGTagsResultSet +/// @ingroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTag +/// @brief **PVR add-on EPG entry transfer class**\n +/// To transfer the content of @ref kodi::addon::CInstancePVRClient::GetEPGForChannel(). +/// +/// @note This becomes only be used on addon call above, not usable outside on +/// addon itself. +///@{ +class PVREPGTagsResultSet +{ +public: + /*! \cond PRIVATE */ + PVREPGTagsResultSet() = delete; + PVREPGTagsResultSet(const AddonInstance_PVR* instance, ADDON_HANDLE handle) + : m_instance(instance), m_handle(handle) + { + } + /*! \endcond */ + + /// @addtogroup cpp_kodi_addon_pvr_Defs_epg_PVREPGTagsResultSet + ///@{ + + /// @brief To add and give content from addon to Kodi on related call. + /// + /// @param[in] tag The to transferred data. + void Add(const kodi::addon::PVREPGTag& tag) + { + m_instance->toKodi->TransferEpgEntry(m_instance->toKodi->kodiInstance, m_handle, tag.GetTag()); + } + + ///@} + +private: + const AddonInstance_PVR* m_instance = nullptr; + const ADDON_HANDLE m_handle; +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/General.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/General.h new file mode 100644 index 0000000..c7977c2 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/General.h @@ -0,0 +1,511 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/addon-instance/pvr/pvr_general.h" + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" Definitions group 1 - General PVR +#ifdef __cplusplus + +namespace kodi +{ +namespace addon +{ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_PVRTypeIntValue class PVRTypeIntValue +/// @ingroup cpp_kodi_addon_pvr_Defs_General +/// @brief **PVR add-on type value**\n +/// Representation of a `` event related value. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help +/// +///@{ +class PVRTypeIntValue : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVRTypeIntValue(const PVRTypeIntValue& data) : CStructHdl(data) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_PVRTypeIntValue + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **Value** | `int` | @ref PVRTypeIntValue::SetValue "SetValue" | @ref PVRTypeIntValue::GetValue "GetValue" + /// | **Description** | `std::string` | @ref PVRTypeIntValue::SetDescription "SetDescription" | @ref PVRTypeIntValue::GetDescription "GetDescription" + /// + /// @remark Further can there be used his class constructor to set values. + + /// @addtogroup cpp_kodi_addon_pvr_Defs_PVRTypeIntValue + ///@{ + + /// @brief Default class constructor. + /// + /// @note Values must be set afterwards. + PVRTypeIntValue() = default; + + /// @brief Class constructor with integrated value set. + /// + /// @param[in] value Type identification value + /// @param[in] description Type description text + PVRTypeIntValue(int value, const std::string& description) + { + SetValue(value); + SetDescription(description); + } + + /// @brief To set with the identification value. + void SetValue(int value) { m_cStructure->iValue = value; } + + /// @brief To get with the identification value. + int GetValue() const { return m_cStructure->iValue; } + + /// @brief To set with the description text of the value. + void SetDescription(const std::string& description) + { + strncpy(m_cStructure->strDescription, description.c_str(), + sizeof(m_cStructure->strDescription) - 1); + } + + /// @brief To get with the description text of the value. + std::string GetDescription() const { return m_cStructure->strDescription; } + ///@} + +private: + PVRTypeIntValue(const PVR_ATTRIBUTE_INT_VALUE* data) : CStructHdl(data) {} + PVRTypeIntValue(PVR_ATTRIBUTE_INT_VALUE* data) : CStructHdl(data) {} +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_PVRCapabilities class PVRCapabilities +/// @ingroup cpp_kodi_addon_pvr_Defs_General +/// @brief **PVR add-on capabilities**\n +/// This class is needed to tell Kodi which options are supported on the addon. +/// +/// If a capability is set to **true**, then the corresponding methods from +/// @ref cpp_kodi_addon_pvr "kodi::addon::CInstancePVRClient" need to be +/// implemented. +/// +/// As default them all set to **false**. +/// +/// Used on @ref kodi::addon::CInstancePVRClient::GetCapabilities(). +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_PVRCapabilities_Help +/// +///@{ +class PVRCapabilities +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + explicit PVRCapabilities() = delete; + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_PVRCapabilities_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_PVRCapabilities + /// ---------------------------------------------------------------------------- + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_PVRCapabilities : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **Supports EPG** | `boolean` | @ref PVRCapabilities::SetSupportsEPG "SetSupportsEPG" | @ref PVRCapabilities::GetSupportsEPG "GetSupportsEPG" + /// | **Supports EPG EDL** | `boolean` | @ref PVRCapabilities::SetSupportsEPGEdl "SetSupportsEPGEdl" | @ref PVRCapabilities::GetSupportsEPGEdl "GetSupportsEPGEdl" + /// | **Supports TV** | `boolean` | @ref PVRCapabilities::SetSupportsTV "SetSupportsTV" | @ref PVRCapabilities::GetSupportsTV "GetSupportsTV" + /// | **Supports radio** | `boolean` | @ref PVRCapabilities::SetSupportsRadio "SetSupportsRadio" | @ref PVRCapabilities::GetSupportsRadio "GetSupportsRadio" + /// | **Supports recordings** | `boolean` | @ref PVRCapabilities::SetSupportsRecordings "SetSupportsRecordings" | @ref PVRCapabilities::GetSupportsRecordings "GetSupportsRecordings" + /// | **Supports recordings undelete** | `boolean` | @ref PVRCapabilities::SetSupportsRecordingsUndelete "SetSupportsRecordingsUndelete" | @ref PVRCapabilities::GetSupportsRecordingsUndelete "SetSupportsRecordingsUndelete" + /// | **Supports timers** | `boolean` | @ref PVRCapabilities::SetSupportsTimers "SetSupportsTimers" | @ref PVRCapabilities::GetSupportsTimers "GetSupportsTimers" + /// | **Supports channel groups** | `boolean` | @ref PVRCapabilities::SetSupportsChannelGroups "SetSupportsChannelGroups" | @ref PVRCapabilities::GetSupportsChannelGroups "GetSupportsChannelGroups" + /// | **Supports channel scan** | `boolean` | @ref PVRCapabilities::SetSupportsChannelScan "SetSupportsChannelScan" | @ref PVRCapabilities::GetSupportsChannelScan "GetSupportsChannelScan" + /// | **Supports channel settings** | `boolean` | @ref PVRCapabilities::SetSupportsChannelSettings "SetSupportsChannelSettings" | @ref PVRCapabilities::GetSupportsChannelSettings "GetSupportsChannelSettings" + /// | **Handles input stream** | `boolean` | @ref PVRCapabilities::SetHandlesInputStream "SetHandlesInputStream" | @ref PVRCapabilities::GetHandlesInputStream "GetHandlesInputStream" + /// | **Handles demuxing** | `boolean` | @ref PVRCapabilities::SetHandlesDemuxing "SetHandlesDemuxing" | @ref PVRCapabilities::GetHandlesDemuxing "GetHandlesDemuxing" + /// | **Supports recording play count** | `boolean` | @ref PVRCapabilities::SetSupportsRecordingPlayCount "SetSupportsRecordingPlayCount" | @ref PVRCapabilities::GetSupportsRecordingPlayCount "GetSupportsRecordingPlayCount" + /// | **Supports last played position** | `boolean` | @ref PVRCapabilities::SetSupportsLastPlayedPosition "SetSupportsLastPlayedPosition" | @ref PVRCapabilities::GetSupportsLastPlayedPosition "GetSupportsLastPlayedPosition" + /// | **Supports recording EDL** | `boolean` | @ref PVRCapabilities::SetSupportsRecordingEdl "SetSupportsRecordingEdl" | @ref PVRCapabilities::GetSupportsRecordingEdl "GetSupportsRecordingEdl" + /// | **Supports recordings rename** | `boolean` | @ref PVRCapabilities::SetSupportsRecordingsRename "SetSupportsRecordingsRename" | @ref PVRCapabilities::GetSupportsRecordingsRename "GetSupportsRecordingsRename" + /// | **Supports recordings lifetime change** | `boolean` | @ref PVRCapabilities::SetSupportsRecordingsLifetimeChange "SetSupportsRecordingsLifetimeChange" | @ref PVRCapabilities::GetSupportsRecordingsLifetimeChange "GetSupportsRecordingsLifetimeChange" + /// | **Supports descramble info** | `boolean` | @ref PVRCapabilities::SetSupportsDescrambleInfo "SetSupportsDescrambleInfo" | @ref PVRCapabilities::GetSupportsDescrambleInfo "GetSupportsDescrambleInfo" + /// | **Supports async EPG transfer** | `boolean` | @ref PVRCapabilities::SetSupportsAsyncEPGTransfer "SetSupportsAsyncEPGTransfer" | @ref PVRCapabilities::GetSupportsAsyncEPGTransfer "GetSupportsAsyncEPGTransfer" + /// | **Supports recording size** | `boolean` | @ref PVRCapabilities::SetSupportsRecordingSize "SetSupportsRecordingSize" | @ref PVRCapabilities::GetSupportsRecordingSize "GetSupportsRecordingSize" + /// | **Recordings lifetime values** | @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue "PVRTypeIntValue" | @ref PVRCapabilities::SetRecordingsLifetimeValues "SetRecordingsLifetimeValues" | @ref PVRCapabilities::GetRecordingsLifetimeValues "GetRecordingsLifetimeValues" + /// + /// @warning This class can not be used outside of @ref kodi::addon::CInstancePVRClient::GetCapabilities() + /// + + /// @addtogroup cpp_kodi_addon_pvr_Defs_PVRCapabilities + ///@{ + + /// @brief Set **true** if the add-on provides EPG information. + void SetSupportsEPG(bool supportsEPG) { m_capabilities->bSupportsEPG = supportsEPG; } + + /// @brief To get with @ref SetSupportsEPG changed values. + bool GetSupportsEPG() const { return m_capabilities->bSupportsEPG; } + + /// @brief Set **true** if the backend supports retrieving an edit decision + /// list for an EPG tag. + void SetSupportsEPGEdl(bool supportsEPGEdl) { m_capabilities->bSupportsEPGEdl = supportsEPGEdl; } + + /// @brief To get with @ref SetSupportsEPGEdl changed values. + bool GetSupportsEPGEdl() const { return m_capabilities->bSupportsEPGEdl; } + + /// @brief Set **true** if this add-on provides TV channels. + void SetSupportsTV(bool supportsTV) { m_capabilities->bSupportsTV = supportsTV; } + + /// @brief To get with @ref SetSupportsTV changed values. + bool GetSupportsTV() const { return m_capabilities->bSupportsTV; } + + /// @brief Set **true** if this add-on provides TV channels. + void SetSupportsRadio(bool supportsRadio) { m_capabilities->bSupportsRadio = supportsRadio; } + + /// @brief To get with @ref SetSupportsRadio changed values. + bool GetSupportsRadio() const { return m_capabilities->bSupportsRadio; } + + /// @brief **true** if this add-on supports playback of recordings stored on + /// the backend. + void SetSupportsRecordings(bool supportsRecordings) + { + m_capabilities->bSupportsRecordings = supportsRecordings; + } + + /// @brief To get with @ref SetSupportsRecordings changed values. + bool GetSupportsRecordings() const { return m_capabilities->bSupportsRecordings; } + + /// @brief Set **true** if this add-on supports undelete of recordings stored + /// on the backend. + void SetSupportsRecordingsUndelete(bool supportsRecordingsUndelete) + { + m_capabilities->bSupportsRecordingsUndelete = supportsRecordingsUndelete; + } + + /// @brief To get with @ref SetSupportsRecordings changed values. + bool GetSupportsRecordingsUndelete() const { return m_capabilities->bSupportsRecordingsUndelete; } + + /// @brief Set **true** if this add-on supports the creation and editing of + /// timers. + void SetSupportsTimers(bool supportsTimers) { m_capabilities->bSupportsTimers = supportsTimers; } + + /// @brief To get with @ref SetSupportsTimers changed values. + bool GetSupportsTimers() const { return m_capabilities->bSupportsTimers; } + + /// @brief Set **true** if this add-on supports channel groups. + /// + /// It use the following functions: + /// - @ref kodi::addon::CInstancePVRClient::GetChannelGroupsAmount() + /// - @ref kodi::addon::CInstancePVRClient::GetChannelGroups() + /// - @ref kodi::addon::CInstancePVRClient::GetChannelGroupMembers() + void SetSupportsChannelGroups(bool supportsChannelGroups) + { + m_capabilities->bSupportsChannelGroups = supportsChannelGroups; + } + + /// @brief To get with @ref SetSupportsChannelGroups changed values. + bool GetSupportsChannelGroups() const { return m_capabilities->bSupportsChannelGroups; } + + /// @brief Set **true** if this add-on support scanning for new channels on + /// the backend. + /// + /// It use the following function: + /// - @ref kodi::addon::CInstancePVRClient::OpenDialogChannelScan() + void SetSupportsChannelScan(bool supportsChannelScan) + { + m_capabilities->bSupportsChannelScan = supportsChannelScan; + } + + /// @brief To get with @ref SetSupportsChannelScan changed values. + bool GetSupportsChannelScan() const { return m_capabilities->bSupportsChannelScan; } + + /// @brief Set **true** if this add-on supports channel edit. + /// + /// It use the following functions: + /// - @ref kodi::addon::CInstancePVRClient::DeleteChannel() + /// - @ref kodi::addon::CInstancePVRClient::RenameChannel() + /// - @ref kodi::addon::CInstancePVRClient::OpenDialogChannelSettings() + /// - @ref kodi::addon::CInstancePVRClient::OpenDialogChannelAdd() + void SetSupportsChannelSettings(bool supportsChannelSettings) + { + m_capabilities->bSupportsChannelSettings = supportsChannelSettings; + } + + /// @brief To get with @ref SetSupportsChannelSettings changed values. + bool GetSupportsChannelSettings() const { return m_capabilities->bSupportsChannelSettings; } + + /// @brief Set **true** if this add-on provides an input stream. false if Kodi + /// handles the stream. + void SetHandlesInputStream(bool handlesInputStream) + { + m_capabilities->bHandlesInputStream = handlesInputStream; + } + + /// @brief To get with @ref SetHandlesInputStream changed values. + bool GetHandlesInputStream() const { return m_capabilities->bHandlesInputStream; } + + /// @brief Set **true** if this add-on demultiplexes packets. + void SetHandlesDemuxing(bool handlesDemuxing) + { + m_capabilities->bHandlesDemuxing = handlesDemuxing; + } + + /// @brief To get with @ref SetHandlesDemuxing changed values. + bool GetHandlesDemuxing() const { return m_capabilities->bHandlesDemuxing; } + + /// @brief Set **true** if the backend supports play count for recordings. + void SetSupportsRecordingPlayCount(bool supportsRecordingPlayCount) + { + m_capabilities->bSupportsRecordingPlayCount = supportsRecordingPlayCount; + } + + /// @brief To get with @ref SetSupportsRecordingPlayCount changed values. + bool GetSupportsRecordingPlayCount() const { return m_capabilities->bSupportsRecordingPlayCount; } + + /// @brief Set **true** if the backend supports store/retrieve of last played + /// position for recordings. + void SetSupportsLastPlayedPosition(bool supportsLastPlayedPosition) + { + m_capabilities->bSupportsLastPlayedPosition = supportsLastPlayedPosition; + } + + /// @brief To get with @ref SetSupportsLastPlayedPosition changed values. + bool GetSupportsLastPlayedPosition() const { return m_capabilities->bSupportsLastPlayedPosition; } + + /// @brief Set **true** if the backend supports retrieving an edit decision + /// list for recordings. + void SetSupportsRecordingEdl(bool supportsRecordingEdl) + { + m_capabilities->bSupportsRecordingEdl = supportsRecordingEdl; + } + + /// @brief To get with @ref SetSupportsRecordingEdl changed values. + bool GetSupportsRecordingEdl() const { return m_capabilities->bSupportsRecordingEdl; } + + /// @brief Set **true** if the backend supports renaming recordings. + void SetSupportsRecordingsRename(bool supportsRecordingsRename) + { + m_capabilities->bSupportsRecordingsRename = supportsRecordingsRename; + } + + /// @brief To get with @ref SetSupportsRecordingsRename changed values. + bool GetSupportsRecordingsRename() const { return m_capabilities->bSupportsRecordingsRename; } + + /// @brief Set **true** if the backend supports changing lifetime for + /// recordings. + void SetSupportsRecordingsLifetimeChange(bool supportsRecordingsLifetimeChange) + { + m_capabilities->bSupportsRecordingsLifetimeChange = supportsRecordingsLifetimeChange; + } + + /// @brief To get with @ref SetSupportsRecordingsLifetimeChange changed + /// values. + bool GetSupportsRecordingsLifetimeChange() const + { + return m_capabilities->bSupportsRecordingsLifetimeChange; + } + + /// @brief Set **true** if the backend supports descramble information for + /// playing channels. + void SetSupportsDescrambleInfo(bool supportsDescrambleInfo) + { + m_capabilities->bSupportsDescrambleInfo = supportsDescrambleInfo; + } + + /// @brief To get with @ref SetSupportsDescrambleInfo changed values. + bool GetSupportsDescrambleInfo() const { return m_capabilities->bSupportsDescrambleInfo; } + + /// @brief Set **true** if this addon-on supports asynchronous transfer of epg + /// events to Kodi using the callback function + /// @ref kodi::addon::CInstancePVRClient::EpgEventStateChange(). + void SetSupportsAsyncEPGTransfer(bool supportsAsyncEPGTransfer) + { + m_capabilities->bSupportsAsyncEPGTransfer = supportsAsyncEPGTransfer; + } + + /// @brief To get with @ref SetSupportsAsyncEPGTransfer changed values. + bool GetSupportsAsyncEPGTransfer() const { return m_capabilities->bSupportsAsyncEPGTransfer; } + + /// @brief Set **true** if this addon-on supports retrieving size of recordings. + void SetSupportsRecordingSize(bool supportsRecordingSize) + { + m_capabilities->bSupportsRecordingSize = supportsRecordingSize; + } + + /// @brief To get with @ref SetSupportsRecordingSize changed values. + bool GetSupportsRecordingSize() const { return m_capabilities->bSupportsRecordingSize; } + + /// @brief **optional**\n + /// Set array containing the possible values for @ref PVRRecording::SetLifetime(). + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help + void SetRecordingsLifetimeValues( + const std::vector& recordingsLifetimeValues) + { + m_capabilities->iRecordingsLifetimesSize = 0; + for (unsigned int i = 0; i < recordingsLifetimeValues.size() && + i < sizeof(m_capabilities->recordingsLifetimeValues); + ++i) + { + m_capabilities->recordingsLifetimeValues[i].iValue = + recordingsLifetimeValues[i].GetCStructure()->iValue; + strncpy(m_capabilities->recordingsLifetimeValues[i].strDescription, + recordingsLifetimeValues[i].GetCStructure()->strDescription, + sizeof(m_capabilities->recordingsLifetimeValues[i].strDescription) - 1); + ++m_capabilities->iRecordingsLifetimesSize; + } + } + + /// @brief To get with @ref SetRecordingsLifetimeValues changed values. + std::vector GetRecordingsLifetimeValues() const + { + std::vector recordingsLifetimeValues; + for (unsigned int i = 0; i < m_capabilities->iRecordingsLifetimesSize; ++i) + recordingsLifetimeValues.emplace_back( + m_capabilities->recordingsLifetimeValues[i].iValue, + m_capabilities->recordingsLifetimeValues[i].strDescription); + return recordingsLifetimeValues; + } + ///@} + +private: + PVRCapabilities(PVR_ADDON_CAPABILITIES* capabilities) : m_capabilities(capabilities) {} + + PVR_ADDON_CAPABILITIES* m_capabilities; +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_General_Inputstream_PVRStreamProperty class PVRStreamProperty +/// @ingroup cpp_kodi_addon_pvr_Defs_General_Inputstream +/// @brief **PVR stream property value handler**\n +/// To set for Kodi wanted stream properties. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_General_Inputstream_PVRStreamProperty_Help +/// +///--------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// ... +/// +/// PVR_ERROR CMyPVRInstance::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, +/// std::vector& properties) +/// { +/// ... +/// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM, "inputstream.adaptive"); +/// return PVR_ERROR_NO_ERROR; +/// } +/// +/// ... +/// ~~~~~~~~~~~~~ +/// +/// +/// **Example 2:** +/// ~~~~~~~~~~~~~{.cpp} +/// ... +/// +/// PVR_ERROR CMyPVRInstance::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, +/// std::vector& properties) +/// { +/// ... +/// kodi::addon::PVRStreamProperty property; +/// property.SetName(PVR_STREAM_PROPERTY_INPUTSTREAM); +/// property.SetValue("inputstream.adaptive"); +/// properties.emplace_back(property); +/// return PVR_ERROR_NO_ERROR; +/// } +/// +/// ... +/// ~~~~~~~~~~~~~ +/// +///@{ +class PVRStreamProperty : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVRStreamProperty(const PVRStreamProperty& data) : CStructHdl(data) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_General_Inputstream_PVRStreamProperty_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_General_Inputstream_PVRStreamProperty + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_General_Inputstream_PVRStreamProperty : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **Name** | `int` | @ref PVRStreamProperty::SetValue "SetName" | @ref PVRStreamProperty::GetName "GetName" + /// | **Value** | `std::string` | @ref PVRStreamProperty::SetValue "SetValue" | @ref PVRStreamProperty::GetValue "GetValue" + /// + /// @remark Further can there be used his class constructor to set values. + + /// @addtogroup cpp_kodi_addon_pvr_Defs_General_Inputstream_PVRStreamProperty + ///@{ + + /// @brief Default class constructor. + /// + /// @note Values must be set afterwards. + PVRStreamProperty() = default; + + /// @brief Class constructor with integrated value set. + /// + /// @param[in] name Type identification + /// @param[in] value Type used property value + PVRStreamProperty(const std::string& name, const std::string& value) + { + SetName(name); + SetValue(value); + } + + /// @brief To set with the identification name. + void SetName(const std::string& name) + { + strncpy(m_cStructure->strName, name.c_str(), sizeof(m_cStructure->strName) - 1); + } + + /// @brief To get with the identification name. + std::string GetName() const { return m_cStructure->strName; } + + /// @brief To set with the used property value. + void SetValue(const std::string& value) + { + strncpy(m_cStructure->strValue, value.c_str(), sizeof(m_cStructure->strValue) - 1); + } + + /// @brief To get with the used property value. + std::string GetValue() const { return m_cStructure->strValue; } + ///@} + +private: + PVRStreamProperty(const PVR_NAMED_VALUE* data) : CStructHdl(data) {} + PVRStreamProperty(PVR_NAMED_VALUE* data) : CStructHdl(data) {} +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/MenuHook.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/MenuHook.h new file mode 100644 index 0000000..053a4d5 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/MenuHook.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/addon-instance/pvr/pvr_menu_hook.h" + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" Definitions group 7 - Menu hook +#ifdef __cplusplus + +namespace kodi +{ +namespace addon +{ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook class PVRMenuhook +/// @ingroup cpp_kodi_addon_pvr_Defs_Menuhook +/// @brief **Context menu hook**\n +/// Menu hooks that are available in the context menus while playing a stream via this add-on. +/// And in the Live TV settings dialog. +/// +/// Possible menu's given to Kodi. +/// +/// This can be becomes used on this, if @ref kodi::addon::CInstancePVRClient::AddMenuHook() +/// was set to related type: +/// - @ref kodi::addon::CInstancePVRClient::CallSettingsMenuHook() +/// - @ref kodi::addon::CInstancePVRClient::CallChannelMenuHook() +/// - @ref kodi::addon::CInstancePVRClient::CallEPGMenuHook() +/// - @ref kodi::addon::CInstancePVRClient::CallRecordingMenuHook() +/// - @ref kodi::addon::CInstancePVRClient::CallTimerMenuHook() +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help +/// +///@{ +class PVRMenuhook : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /// @addtogroup cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook + /// @brief Optional class constructor with value set. + /// + /// @param[in] hookId This hook's identifier + /// @param[in] localizedStringId Localized string identifier + /// @param[in] category Category of menu hook, defined with @ref PVR_MENUHOOK_CAT + /// + /// + /// -------------------------------------------------------------------------- + /// + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// AddMenuHook(kodi::addon::PVRMenuhook(1, 30001, PVR_MENUHOOK_CHANNEL)); + /// ~~~~~~~~~~~~~ + /// + PVRMenuhook(unsigned int hookId, unsigned int localizedStringId, PVR_MENUHOOK_CAT category) + { + m_cStructure->iHookId = hookId; + m_cStructure->iLocalizedStringId = localizedStringId; + m_cStructure->category = category; + } + + /*! \cond PRIVATE */ + PVRMenuhook() + { + m_cStructure->iHookId = 0; + m_cStructure->iLocalizedStringId = 0; + m_cStructure->category = PVR_MENUHOOK_UNKNOWN; + } + PVRMenuhook(const PVRMenuhook& data) : CStructHdl(data) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook : + /// | Name | Type | Set call | Get call | Usage + /// |------|------|----------|----------|----------- + /// | **This hook's identifier** | `unsigned int` | @ref PVRMenuhook::SetHookId "SetHookId" | @ref PVRMenuhook::GetHookId "GetHookId" | *required to set* + /// | **Localized string Identifier** | `unsigned int` | @ref PVRMenuhook::SetLocalizedStringId "SetLocalizedStringId" | @ref PVRMenuhook::GetLocalizedStringId "GetLocalizedStringId" | *required to set* + /// | **Category of menu hook** | @ref PVR_MENUHOOK_CAT | @ref PVRMenuhook::SetCategory "SetCategory" | @ref PVRMenuhook::GetCategory "GetCategory" | *required to set* + + /// @addtogroup cpp_kodi_addon_pvr_Defs_Menuhook_PVRMenuhook + ///@{ + + /// @brief **required**\n + /// This hook's identifier. + void SetHookId(unsigned int hookId) { m_cStructure->iHookId = hookId; } + + /// @brief To get with @ref SetHookId() changed values. + unsigned int GetHookId() const { return m_cStructure->iHookId; } + + /// @brief **required**\n + /// The id of the label for this hook in @ref kodi::GetLocalizedString(). + void SetLocalizedStringId(unsigned int localizedStringId) + { + m_cStructure->iLocalizedStringId = localizedStringId; + } + + /// @brief To get with @ref SetLocalizedStringId() changed values. + unsigned int GetLocalizedStringId() const { return m_cStructure->iLocalizedStringId; } + + /// @brief **required**\n + /// Category of menu hook. + void SetCategory(PVR_MENUHOOK_CAT category) { m_cStructure->category = category; } + + /// @brief To get with @ref SetCategory() changed values. + PVR_MENUHOOK_CAT GetCategory() const { return m_cStructure->category; } + ///@} + +private: + PVRMenuhook(const PVR_MENUHOOK* data) : CStructHdl(data) {} + PVRMenuhook(PVR_MENUHOOK* data) : CStructHdl(data) {} +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Recordings.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Recordings.h new file mode 100644 index 0000000..24ecf11 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Recordings.h @@ -0,0 +1,520 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/addon-instance/pvr.h" + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" Definitions group 5 - PVR recordings +#ifdef __cplusplus + +namespace kodi +{ +namespace addon +{ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording class PVRRecording +/// @ingroup cpp_kodi_addon_pvr_Defs_Recording +/// @brief **Data structure with available recordings data**\n +/// With this, recordings related data are transferred between addon and Kodi +/// and can also be used by the addon itself. +/// +/// The related values here are automatically initiated to defaults and need +/// only be set if supported and used. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_Recording_PVRRecording_Help +/// +///@{ +class PVRRecording : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVRRecording() + { + m_cStructure->iSeriesNumber = PVR_RECORDING_INVALID_SERIES_EPISODE; + m_cStructure->iEpisodeNumber = PVR_RECORDING_INVALID_SERIES_EPISODE; + m_cStructure->recordingTime = 0; + m_cStructure->iDuration = PVR_RECORDING_VALUE_NOT_AVAILABLE; + m_cStructure->iPriority = PVR_RECORDING_VALUE_NOT_AVAILABLE; + m_cStructure->iLifetime = PVR_RECORDING_VALUE_NOT_AVAILABLE; + m_cStructure->iGenreType = PVR_RECORDING_VALUE_NOT_AVAILABLE; + m_cStructure->iGenreSubType = PVR_RECORDING_VALUE_NOT_AVAILABLE; + m_cStructure->iPlayCount = PVR_RECORDING_VALUE_NOT_AVAILABLE; + m_cStructure->iLastPlayedPosition = PVR_RECORDING_VALUE_NOT_AVAILABLE; + m_cStructure->bIsDeleted = false; + m_cStructure->iEpgEventId = 0; + m_cStructure->iChannelUid = PVR_RECORDING_VALUE_NOT_AVAILABLE; + m_cStructure->channelType = PVR_RECORDING_CHANNEL_TYPE_UNKNOWN; + m_cStructure->iFlags = 0; + m_cStructure->sizeInBytes = PVR_RECORDING_VALUE_NOT_AVAILABLE; + } + PVRRecording(const PVRRecording& recording) : CStructHdl(recording) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Recording_PVRRecording : + /// | Name | Type | Set call | Get call | Usage + /// |------|------|----------|----------|----------- + /// | **Recording id** | `std::string` | @ref PVRRecording::SetRecordingId "SetRecordingId" | @ref PVRRecording::GetRecordingId "GetRecordingId" | *required to set* + /// | **Title** | `std::string` | @ref PVRRecording::SetTitle "SetTitle" | @ref PVRRecording::GetTitle "GetTitle" | *required to set* + /// | **Episode name** | `std::string` | @ref PVRRecording::SetEpisodeName "SetEpisodeName" | @ref PVRRecording::GetEpisodeName "GetEpisodeName" | *optional* + /// | **Series number** | `int` | @ref PVRRecording::SetSeriesNumber "SetSeriesNumber" | @ref PVRRecording::GetSeriesNumber "GetSeriesNumber" | *optional* + /// | **Episode number** | `int` | @ref PVRRecording::SetEpisodeNumber "SetEpisodeNumber" | @ref PVRRecording::GetEpisodeNumber "GetEpisodeNumber" | *optional* + /// | **Year** | `int` | @ref PVRRecording::SetYear "SetYear" | @ref PVRRecording::GetYear "GetYear" | *optional* + /// | **Directory** | `std::string` | @ref PVRRecording::SetDirectory "SetDirectory" | @ref PVRRecording::GetDirectory "GetDirectory" | *optional* + /// | **Plot outline** | `std::string` | @ref PVRRecording::SetPlotOutline "SetPlotOutline" | @ref PVRRecording::GetPlotOutline "GetPlotOutline" | *optional* + /// | **Plot** | `std::string` | @ref PVRRecording::SetPlot "SetPlot" | @ref PVRRecording::GetPlot "GetPlot" | *optional* + /// | **Genre description** | `std::string` | @ref PVRRecording::SetGenreDescription "SetGenreDescription" | @ref PVRRecording::GetGenreDescription "GetGenreDescription" | *optional* + /// | **Channel name** | `std::string` | @ref PVRRecording::SetChannelName "SetChannelName" | @ref PVRRecording::GetChannelName "GetChannelName" | *optional* + /// | **Icon path** | `std::string` | @ref PVRRecording::SetIconPath "SetIconPath" | @ref PVRRecording::GetIconPath "GetIconPath" | *optional* + /// | **Thumbnail path** | `std::string` | @ref PVRRecording::SetThumbnailPath "SetThumbnailPath" | @ref PVRRecording::GetThumbnailPath "GetThumbnailPath" | *optional* + /// | **Fanart path** | `std::string` | @ref PVRRecording::SetFanartPath "SetFanartPath" | @ref PVRRecording::GetFanartPath "GetFanartPath" | *optional* + /// | **Recording time** | `time_t` | @ref PVRRecording::SetRecordingTime "SetRecordingTime" | @ref PVRRecording::GetRecordingTime "GetRecordingTime" | *optional* + /// | **Duration** | `int` | @ref PVRRecording::SetDuration "SetDuration" | @ref PVRRecording::GetDuration "GetDuration" | *optional* + /// | **Priority** | `int` | @ref PVRRecording::SetPriority "SetPriority" | @ref PVRRecording::GetPriority "GetPriority" | *optional* + /// | **Lifetime** | `int` | @ref PVRRecording::SetLifetime "SetLifetime" | @ref PVRRecording::GetLifetime "GetLifetime" | *optional* + /// | **Genre type** | `int` | @ref PVRRecording::SetGenreType "SetGenreType" | @ref PVRRecording::GetGenreType "GetGenreType" | *optional* + /// | **Genre sub type** | `int` | @ref PVRRecording::SetGenreSubType "SetGenreSubType" | @ref PVRRecording::GetGenreSubType "GetGenreSubType" | *optional* + /// | **Play count** | `int` | @ref PVRRecording::SetPlayCount "SetPlayCount" | @ref PVRRecording::GetPlayCount "GetPlayCount" | *optional* + /// | **Last played position** | `int` | @ref PVRRecording::SetLastPlayedPosition "SetLastPlayedPosition" | @ref PVRRecording::GetLastPlayedPosition "GetLastPlayedPosition" | *optional* + /// | **Is deleted** | `bool` | @ref PVRRecording::SetIsDeleted "SetIsDeleted" | @ref PVRRecording::GetIsDeleted "GetIsDeleted" | *optional* + /// | **EPG event id** | `unsigned int` | @ref PVRRecording::SetEPGEventId "SetEPGEventId" | @ref PVRRecording::GetEPGEventId "GetEPGEventId" | *optional* + /// | **Channel unique id** | `int` | @ref PVRRecording::SetChannelUid "SetChannelUid" | @ref PVRRecording::GetChannelUid "GetChannelUid" | *optional* + /// | **Channel type** | @ref PVR_RECORDING_CHANNEL_TYPE | @ref PVRRecording::SetChannelType "SetChannelType" | @ref PVRRecording::GetChannelType "GetChannelType" | *optional* + /// | **First aired** | `std::string` | @ref PVRRecording::SetFirstAired "SetFirstAired" | @ref PVRRecording::GetFirstAired "GetFirstAired" | *optional* + /// | **Flags** | `std::string` | @ref PVRRecording::SetFlags "SetFlags" | @ref PVRRecording::GetFlags "GetFlags" | *optional* + /// | **Size in bytes** | `std::string` | @ref PVRRecording::SetSizeInBytes "SetSizeInBytes" | @ref PVRRecording::GetSizeInBytes "GetSizeInBytes" | *optional* + + /// @addtogroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording + ///@{ + + /// @brief **required**\n + /// Unique identifier of the recording on the client. + void SetRecordingId(const std::string& recordingId) + { + strncpy(m_cStructure->strRecordingId, recordingId.c_str(), + sizeof(m_cStructure->strRecordingId) - 1); + } + + /// @brief To get with @ref SetRecordingId changed values. + std::string GetRecordingId() const { return m_cStructure->strRecordingId; } + + /// @brief **required**\n + /// The title of this recording. + void SetTitle(const std::string& title) + { + strncpy(m_cStructure->strTitle, title.c_str(), sizeof(m_cStructure->strTitle) - 1); + } + + /// @brief To get with @ref SetTitle changed values. + std::string GetTitle() const { return m_cStructure->strTitle; } + + /// @brief **optional**\n + /// Episode name (also known as subtitle). + void SetEpisodeName(const std::string& episodeName) + { + strncpy(m_cStructure->strEpisodeName, episodeName.c_str(), + sizeof(m_cStructure->strEpisodeName) - 1); + } + + /// @brief To get with @ref SetEpisodeName changed values. + std::string GetEpisodeName() const { return m_cStructure->strEpisodeName; } + + /// @brief **optional**\n + /// Series number (usually called season). + /// + /// Set to "0" for specials/pilot. For 'invalid' see @ref SetEpisodeNumber or set to -1. + void SetSeriesNumber(int seriesNumber) { m_cStructure->iSeriesNumber = seriesNumber; } + + /// @brief To get with @ref SetSeriesNumber changed values. + int GetSeriesNumber() const { return m_cStructure->iSeriesNumber; } + + /// @brief **optional**\n + /// Eepisode number within the "iSeriesNumber" season. + /// + /// For 'invalid' set to -1 or seriesNumber=episodeNumber=0 to show both are invalid. + void SetEpisodeNumber(int episodeNumber) { m_cStructure->iEpisodeNumber = episodeNumber; } + + /// @brief To get with @ref SetEpisodeNumber changed values. + int GetEpisodeNumber() const { return m_cStructure->iEpisodeNumber; } + + /// @brief **optional**\n + /// Year of first release (use to identify a specific movie re-make) / first + /// airing for TV shows. + /// + /// Set to '0' for invalid. + void SetYear(int year) { m_cStructure->iYear = year; } + + /// @brief To get with @ref SetYear changed values. + int GetYear() const { return m_cStructure->iYear; } + + /// @brief **optional**\n + /// + /// Directory of this recording on the client. + void SetDirectory(const std::string& directory) + { + strncpy(m_cStructure->strDirectory, directory.c_str(), sizeof(m_cStructure->strDirectory) - 1); + } + + /// @brief To get with @ref SetDirectory changed values. + std::string GetDirectory() const { return m_cStructure->strDirectory; } + + /// @brief **optional**\n + /// Plot outline name. + void SetPlotOutline(const std::string& plotOutline) + { + strncpy(m_cStructure->strPlotOutline, plotOutline.c_str(), + sizeof(m_cStructure->strPlotOutline) - 1); + } + + /// @brief To get with @ref SetPlotOutline changed values. + std::string GetPlotOutline() const { return m_cStructure->strPlotOutline; } + + /// @brief **optional**\n + /// Plot name. + void SetPlot(const std::string& plot) + { + strncpy(m_cStructure->strPlot, plot.c_str(), sizeof(m_cStructure->strPlot) - 1); + } + + /// @brief To get with @ref SetPlot changed values. + std::string GetPlot() const { return m_cStructure->strPlot; } + + /// @brief **optional**\n + /// Channel name. + void SetChannelName(const std::string& channelName) + { + strncpy(m_cStructure->strChannelName, channelName.c_str(), + sizeof(m_cStructure->strChannelName) - 1); + } + + /// @brief To get with @ref SetChannelName changed values. + std::string GetChannelName() const { return m_cStructure->strChannelName; } + + /// @brief **optional**\n + /// Channel logo (icon) path. + void SetIconPath(const std::string& iconPath) + { + strncpy(m_cStructure->strIconPath, iconPath.c_str(), sizeof(m_cStructure->strIconPath) - 1); + } + + /// @brief To get with @ref SetIconPath changed values. + std::string GetIconPath() const { return m_cStructure->strIconPath; } + + /// @brief **optional**\n + /// Thumbnail path. + void SetThumbnailPath(const std::string& thumbnailPath) + { + strncpy(m_cStructure->strThumbnailPath, thumbnailPath.c_str(), + sizeof(m_cStructure->strThumbnailPath) - 1); + } + + /// @brief To get with @ref SetThumbnailPath changed values. + std::string GetThumbnailPath() const { return m_cStructure->strThumbnailPath; } + + /// @brief **optional**\n + /// Fanart path. + void SetFanartPath(const std::string& fanartPath) + { + strncpy(m_cStructure->strFanartPath, fanartPath.c_str(), + sizeof(m_cStructure->strFanartPath) - 1); + } + + /// @brief To get with @ref SetFanartPath changed values. + std::string GetFanartPath() const { return m_cStructure->strFanartPath; } + + /// @brief **optional**\n + /// Start time of the recording. + void SetRecordingTime(time_t recordingTime) { m_cStructure->recordingTime = recordingTime; } + + /// @brief To get with @ref SetRecordingTime changed values. + time_t GetRecordingTime() const { return m_cStructure->recordingTime; } + + /// @brief **optional**\n + /// Duration of the recording in seconds. + void SetDuration(int duration) { m_cStructure->iDuration = duration; } + + /// @brief To get with @ref SetDuration changed values. + int GetDuration() const { return m_cStructure->iDuration; } + + /// @brief **optional**\n + /// Priority of this recording (from 0 - 100). + void SetPriority(int priority) { m_cStructure->iPriority = priority; } + + /// @brief To get with @ref SetPriority changed values. + int GetPriority() const { return m_cStructure->iPriority; } + + /// @brief **optional**\n + /// Life time in days of this recording. + void SetLifetime(int lifetime) { m_cStructure->iLifetime = lifetime; } + + /// @brief To get with @ref SetLifetime changed values. + int GetLifetime() const { return m_cStructure->iLifetime; } + + /// @brief **optional**\n + /// Genre type. + /// + /// Use @ref EPG_GENRE_USE_STRING if type becomes given by @ref SetGenreDescription. + /// + /// @note If confirmed that backend brings the types in [ETSI EN 300 468](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) + /// conform values, can be @ref EPG_EVENT_CONTENTMASK ignored and to set here + /// with backend value. + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Example 1:** + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVRRecording tag; + /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MOVIEDRAMA); + /// ~~~~~~~~~~~~~ + /// + /// -------------------------------------------------------------------------- + /// + /// **Example 2** (in case of other, not ETSI EN 300 468 conform genre types): + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVRRecording tag; + /// tag.SetGenreType(EPG_GENRE_USE_STRING); + /// tag.SetGenreDescription("My special genre name"); // Should use (if possible) kodi::GetLocalizedString(...) to have match user language. + /// ~~~~~~~~~~~~~ + /// + void SetGenreType(int genreType) { m_cStructure->iGenreType = genreType; } + + /// @brief To get with @ref SetGenreType changed values. + int GetGenreType() const { return m_cStructure->iGenreType; } + + /// @brief **optional**\n + /// Genre sub type. + /// + /// Subtypes groups related to set by @ref SetGenreType: + /// | Main genre type | List with available sub genre types + /// |-----------------|----------------------------------------- + /// | @ref EPG_EVENT_CONTENTMASK_UNDEFINED | Nothing, should be 0 + /// | @ref EPG_EVENT_CONTENTMASK_MOVIEDRAMA | @ref EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA + /// | @ref EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS | @ref EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS + /// | @ref EPG_EVENT_CONTENTMASK_SHOW | @ref EPG_EVENT_CONTENTSUBMASK_SHOW + /// | @ref EPG_EVENT_CONTENTMASK_SPORTS | @ref EPG_EVENT_CONTENTSUBMASK_SPORTS + /// | @ref EPG_EVENT_CONTENTMASK_CHILDRENYOUTH | @ref EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH + /// | @ref EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE | @ref EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE + /// | @ref EPG_EVENT_CONTENTMASK_ARTSCULTURE | @ref EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE + /// | @ref EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS | @ref EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS + /// | @ref EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE | @ref EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE + /// | @ref EPG_EVENT_CONTENTMASK_LEISUREHOBBIES | @ref EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES + /// | @ref EPG_EVENT_CONTENTMASK_SPECIAL | @ref EPG_EVENT_CONTENTSUBMASK_SPECIAL + /// | @ref EPG_EVENT_CONTENTMASK_USERDEFINED | Can be defined by you + /// | @ref EPG_GENRE_USE_STRING | **Kodi's own value**, which declares that the type with @ref SetGenreDescription is given. + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVRRecording tag; + /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE); + /// tag.SetGenreSubType(EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_JAZZ); + /// ~~~~~~~~~~~~~ + /// + void SetGenreSubType(int genreSubType) { m_cStructure->iGenreSubType = genreSubType; } + + /// @brief To get with @ref SetGenreSubType changed values. + int GetGenreSubType() const { return m_cStructure->iGenreSubType; } + + /// @brief **optional**\n + /// To set own genre description name. + /// + /// Will be used only when genreType == @ref EPG_GENRE_USE_STRING or + /// genreSubType == @ref EPG_GENRE_USE_STRING. + /// + /// Use @ref EPG_STRING_TOKEN_SEPARATOR to separate different genres. + /// + /// In case of other, not [ETSI EN 300 468](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) + /// conform genre types or something special. + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVRRecording tag; + /// tag.SetGenreType(EPG_GENRE_USE_STRING); + /// tag.SetGenreDescription("Action" + EPG_STRING_TOKEN_SEPARATOR + "Thriller"); + /// ~~~~~~~~~~~~~ + /// + void SetGenreDescription(const std::string& genreDescription) + { + strncpy(m_cStructure->strGenreDescription, genreDescription.c_str(), + sizeof(m_cStructure->strGenreDescription) - 1); + } + + /// @brief To get with @ref SetGenreDescription changed values. + std::string GetGenreDescription() const { return m_cStructure->strGenreDescription; } + + /// @brief **optional**\n + /// Play count of this recording on the client. + void SetPlayCount(int playCount) { m_cStructure->iPlayCount = playCount; } + + /// @brief To get with @ref SetPlayCount changed values. + int GetPlayCount() const { return m_cStructure->iPlayCount; } + + /// @brief **optional**\n + /// Last played position of this recording on the client. + void SetLastPlayedPosition(int lastPlayedPosition) + { + m_cStructure->iLastPlayedPosition = lastPlayedPosition; + } + + /// @brief To get with @ref SetLastPlayedPosition changed values. + int GetLastPlayedPosition() const { return m_cStructure->iLastPlayedPosition; } + + /// @brief **optional**\n + /// Shows this recording is deleted and can be undelete. + void SetIsDeleted(int isDeleted) { m_cStructure->bIsDeleted = isDeleted; } + + /// @brief To get with @ref SetIsDeleted changed values. + int GetIsDeleted() const { return m_cStructure->bIsDeleted; } + + /// @brief **optional**\n + /// EPG event id associated with this recording. Valid ids must be greater than @ref EPG_TAG_INVALID_UID. + void SetEPGEventId(unsigned int epgEventId) { m_cStructure->iEpgEventId = epgEventId; } + + /// @brief To get with @ref SetEPGEventId changed values. + unsigned int GetEPGEventId() const { return m_cStructure->iEpgEventId; } + + /// @brief **optional**\n + /// Unique identifier of the channel for this recording. @ref PVR_CHANNEL_INVALID_UID + /// denotes that channel uid is not available. + void SetChannelUid(int channelUid) { m_cStructure->iChannelUid = channelUid; } + + /// @brief To get with @ref SetChannelUid changed values + int GetChannelUid() const { return m_cStructure->iChannelUid; } + + /// @brief **optional**\n + /// Channel type. + /// + /// Set to @ref PVR_RECORDING_CHANNEL_TYPE_UNKNOWN if the type cannot be + /// determined. + /// + /// -------------------------------------------------------------------------- + /// + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVRRecording tag; + /// tag.SetChannelType(PVR_RECORDING_CHANNEL_TYPE_TV); + /// ~~~~~~~~~~~~~ + /// + void SetChannelType(PVR_RECORDING_CHANNEL_TYPE channelType) + { + m_cStructure->channelType = channelType; + } + + /// @brief To get with @ref SetChannelType changed values + PVR_RECORDING_CHANNEL_TYPE GetChannelType() const { return m_cStructure->channelType; } + + /// @brief **optional**\n + /// First aired date of this recording. + /// + /// Used only for display purposes. Specify in W3C date format "YYYY-MM-DD". + /// + /// -------------------------------------------------------------------------- + /// + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVRRecording tag; + /// tag.SetFirstAired(1982-10-22); + /// ~~~~~~~~~~~~~ + /// + void SetFirstAired(const std::string& firstAired) + { + strncpy(m_cStructure->strFirstAired, firstAired.c_str(), + sizeof(m_cStructure->strFirstAired) - 1); + } + + /// @brief To get with @ref SetFirstAired changed values + std::string GetFirstAired() const { return m_cStructure->strFirstAired; } + + /// @brief **optional**\n + /// Bit field of independent flags associated with the recording. + /// + /// See @ref cpp_kodi_addon_pvr_Defs_Recording_PVR_RECORDING_FLAG for + /// available bit flags. + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_Recording_PVR_RECORDING_FLAG + /// + void SetFlags(unsigned int flags) { m_cStructure->iFlags = flags; } + + /// @brief To get with @ref SetFlags changed values. + unsigned int GetFlags() const { return m_cStructure->iFlags; } + + /// @brief **optional**\n + /// Size of the recording in bytes. + void SetSizeInBytes(int64_t sizeInBytes) { m_cStructure->sizeInBytes = sizeInBytes; } + + /// @brief To get with @ref SetSizeInBytes changed values. + int64_t GetSizeInBytes() const { return m_cStructure->sizeInBytes; } + ///@} + +private: + PVRRecording(const PVR_RECORDING* recording) : CStructHdl(recording) {} + PVRRecording(PVR_RECORDING* recording) : CStructHdl(recording) {} +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecordingsResultSet class PVRRecordingsResultSet +/// @ingroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording +/// @brief **PVR add-on recording transfer class**\n +/// To transfer the content of @ref kodi::addon::CInstancePVRClient::GetRecordings(). +/// +/// @note This becomes only be used on addon call above, not usable outside on +/// addon itself. +///@{ +class PVRRecordingsResultSet +{ +public: + /*! \cond PRIVATE */ + PVRRecordingsResultSet() = delete; + PVRRecordingsResultSet(const AddonInstance_PVR* instance, ADDON_HANDLE handle) + : m_instance(instance), m_handle(handle) + { + } + /*! \endcond */ + + /// @addtogroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecordingsResultSet + ///@{ + + /// @brief To add and give content from addon to Kodi on related call. + /// + /// @param[in] tag The to transferred data. + void Add(const kodi::addon::PVRRecording& tag) + { + m_instance->toKodi->TransferRecordingEntry(m_instance->toKodi->kodiInstance, m_handle, tag); + } + + ///@} + +private: + const AddonInstance_PVR* m_instance = nullptr; + const ADDON_HANDLE m_handle; +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Stream.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Stream.h new file mode 100644 index 0000000..5613947 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Stream.h @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/addon-instance/pvr/pvr_stream.h" + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" Definitions group 9 - PVR stream definitions (NOTE: Becomes replaced +// in future by inputstream addon instance way) + +#ifdef __cplusplus + +namespace kodi +{ +namespace addon +{ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVRCodec class PVRCodec +/// @ingroup cpp_kodi_addon_pvr_Defs_Stream +/// @brief **PVR codec identifier**\n +/// Used to exchange the desired codec type between Kodi and addon. +/// +/// @ref kodi::addon::CInstancePVRClient::GetCodecByName is used to get this data. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_Stream_PVRCodec_Help +/// +///@{ +class PVRCodec : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVRCodec() + { + m_cStructure->codec_type = PVR_CODEC_TYPE_UNKNOWN; + m_cStructure->codec_id = PVR_INVALID_CODEC_ID; + } + PVRCodec(const PVRCodec& type) : CStructHdl(type) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVRCodec_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_Stream_PVRCodec + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Stream_PVRCodec : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **Codec type** | @ref PVR_CODEC_TYPE | @ref PVRCodec::SetCodecType "SetCodecType" | @ref PVRCodec::GetCodecType "GetCodecType" + /// | **Codec identifier** | `unsigned int` | @ref PVRCodec::SetCodecId "SetCodecId" | @ref PVRCodec::GetCodecId "GetCodecId" + /// + + /// @addtogroup cpp_kodi_addon_pvr_Defs_Stream_PVRCodec + ///@{ + + /// @brief Codec type. + void SetCodecType(PVR_CODEC_TYPE codecType) { m_cStructure->codec_type = codecType; } + + /// @brief To get with @ref SetCodecType() changed values. + PVR_CODEC_TYPE GetCodecType() const { return m_cStructure->codec_type; } + + /// @brief Codec id. + /// + /// Related codec identifier, normally match the ffmpeg id's. + void SetCodecId(unsigned int codecId) { m_cStructure->codec_id = codecId; } + + /// @brief To get with @ref SetCodecId() changed values. + unsigned int GetCodecId() const { return m_cStructure->codec_id; } + ///@} + +private: + PVRCodec(const PVR_CODEC& type) : CStructHdl(&type) {} + PVRCodec(const PVR_CODEC* type) : CStructHdl(type) {} + PVRCodec(PVR_CODEC* type) : CStructHdl(type) {} +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties class PVRStreamProperties +/// @ingroup cpp_kodi_addon_pvr_Defs_Stream +/// @brief **PVR stream properties**\n +/// All information about a respective stream is stored in this, so that Kodi +/// can process the data given by the addon after demux. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties_Help +/// +///@{ +class PVRStreamProperties + : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVRStreamProperties() { memset(m_cStructure, 0, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); } + PVRStreamProperties(const PVRStreamProperties& type) : CStructHdl(type) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties + /// ---------------------------------------------------------------------------- + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **PID** | `unsigned int` | @ref PVRStreamProperties::SetPID "SetPID" | @ref PVRStreamProperties::GetPID "GetPID" + /// | **Codec type** | @ref PVR_CODEC_TYPE | @ref PVRStreamProperties::SetCodecType "SetCodecType" | @ref PVRStreamProperties::GetCodecType "GetCodecType" + /// | **Codec identifier** | `unsigned int` | @ref PVRStreamProperties::SetCodecId "SetCodecId" | @ref PVRStreamProperties::GetCodecId "GetCodecId" + /// | **Language** | `std::string` | @ref PVRStreamProperties::SetLanguage "SetLanguage" | @ref PVRStreamProperties::GetLanguage "GetLanguage" + /// | **Subtitle info** | `int` | @ref PVRStreamProperties::SetSubtitleInfo "SetSubtitleInfo" | @ref PVRStreamProperties::GetSubtitleInfo "GetSubtitleInfo" + /// | **FPS scale** | `int` | @ref PVRStreamProperties::SetFPSScale "SetFPSScale" | @ref PVRStreamProperties::GetFPSScale "GetFPSScale" + /// | **FPS rate** | `int` | @ref PVRStreamProperties::SetFPSRate "SetFPSRate" | @ref PVRStreamProperties::GetFPSRate "GetFPSRate" + /// | **Height** | `int` | @ref PVRStreamProperties::SetHeight "SetHeight" | @ref PVRStreamProperties::GetHeight "GetHeight" + /// | **Width** | `int` | @ref PVRStreamProperties::SetWidth "SetWidth" | @ref PVRStreamProperties::GetWidth "GetWidth" + /// | **Aspect ratio** | `float` | @ref PVRStreamProperties::SetAspect "SetAspect" | @ref PVRStreamProperties::GetAspect "GetAspect" + /// | **Channels** | `int` | @ref PVRStreamProperties::SetChannels "SetChannels" | @ref PVRStreamProperties::GetChannels "GetChannels" + /// | **Samplerate** | `int` | @ref PVRStreamProperties::SetSampleRate "SetSampleRate" | @ref PVRStreamProperties::GetSampleRate "GetSampleRate" + /// | **Block align** | `int` | @ref PVRStreamProperties::SetBlockAlign "SetBlockAlign" | @ref PVRStreamProperties::GetBlockAlign "GetBlockAlign" + /// | **Bit rate** | `int` | @ref PVRStreamProperties::SetBitRate "SetBitRate" | @ref PVRStreamProperties::GetBitRate "GetBitRate" + /// | **Bits per sample** | `int` | @ref PVRStreamProperties::SetBitsPerSample "SetBitsPerSample" | @ref PVRStreamProperties::GetBitsPerSample "GetBitsPerSample" + /// + + /// @addtogroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties + ///@{ + + /// @brief PID. + void SetPID(unsigned int pid) { m_cStructure->iPID = pid; } + + /// @brief To get with @ref SetPID() changed values. + unsigned int GetPID() const { return m_cStructure->iPID; } + + /// @brief Codec type this stream. + void SetCodecType(PVR_CODEC_TYPE codecType) { m_cStructure->iCodecType = codecType; } + + /// @brief To get with @ref SetCodecType() changed values. + PVR_CODEC_TYPE GetCodecType() const { return m_cStructure->iCodecType; } + + /// @brief Codec id of this stream. + void SetCodecId(unsigned int codecId) { m_cStructure->iCodecId = codecId; } + + /// @brief To get with @ref SetCodecId() changed values. + unsigned int GetCodecId() const { return m_cStructure->iCodecId; } + + /// @brief 3 letter language id. + void SetLanguage(const std::string& language) + { + if (language.size() > 3) + { + kodi::Log(ADDON_LOG_ERROR, + "PVRStreamProperties::%s: Language string size '%li' higher as needed 3", __func__, + language.size()); + return; + } + m_cStructure->strLanguage[0] = language[0]; + m_cStructure->strLanguage[1] = language[1]; + m_cStructure->strLanguage[2] = language[2]; + m_cStructure->strLanguage[2] = 0; + } + + /// @brief To get with @ref SetLanguage() changed values. + std::string GetLanguage() const { return m_cStructure->strLanguage; } + + /// @brief Subtitle Info + void SetSubtitleInfo(int subtitleInfo) { m_cStructure->iSubtitleInfo = subtitleInfo; } + + /// @brief To get with @ref SetSubtitleInfo() changed values. + int GetSubtitleInfo() const { return m_cStructure->iSubtitleInfo; } + + /// @brief To set scale of 1000 and a rate of 29970 will result in 29.97 fps. + void SetFPSScale(int fpsScale) { m_cStructure->iFPSScale = fpsScale; } + + /// @brief To get with @ref SetFPSScale() changed values. + int GetFPSScale() const { return m_cStructure->iFPSScale; } + + /// @brief FPS rate + void SetFPSRate(int fpsRate) { m_cStructure->iFPSRate = fpsRate; } + + /// @brief To get with @ref SetFPSRate() changed values. + int GetFPSRate() const { return m_cStructure->iFPSRate; } + + /// @brief Height of the stream reported by the demuxer + void SetHeight(int height) { m_cStructure->iHeight = height; } + + /// @brief To get with @ref SetHeight() changed values. + int GetHeight() const { return m_cStructure->iHeight; } + + /// @brief Width of the stream reported by the demuxer. + void SetWidth(int width) { m_cStructure->iWidth = width; } + + /// @brief To get with @ref SetWidth() changed values. + int GetWidth() const { return m_cStructure->iWidth; } + + /// @brief Display aspect ratio of the stream. + void SetAspect(float aspect) { m_cStructure->fAspect = aspect; } + + /// @brief To get with @ref SetAspect() changed values. + float GetAspect() const { return m_cStructure->fAspect; } + + /// @brief Amount of channels. + void SetChannels(int channels) { m_cStructure->iChannels = channels; } + + /// @brief To get with @ref SetChannels() changed values. + int GetChannels() const { return m_cStructure->iChannels; } + + /// @brief Sample rate. + void SetSampleRate(int sampleRate) { m_cStructure->iSampleRate = sampleRate; } + + /// @brief To get with @ref SetSampleRate() changed values. + int GetSampleRate() const { return m_cStructure->iSampleRate; } + + /// @brief Block alignment + void SetBlockAlign(int blockAlign) { m_cStructure->iBlockAlign = blockAlign; } + + /// @brief To get with @ref SetBlockAlign() changed values. + int GetBlockAlign() const { return m_cStructure->iBlockAlign; } + + /// @brief Bit rate. + void SetBitRate(int bitRate) { m_cStructure->iBitRate = bitRate; } + + /// @brief To get with @ref SetBitRate() changed values. + int GetBitRate() const { return m_cStructure->iBitRate; } + + /// @brief Bits per sample. + void SetBitsPerSample(int bitsPerSample) { m_cStructure->iBitsPerSample = bitsPerSample; } + + /// @brief To get with @ref SetBitsPerSample() changed values. + int GetBitsPerSample() const { return m_cStructure->iBitsPerSample; } + ///@} + +private: + PVRStreamProperties(const PVR_STREAM_PROPERTIES::PVR_STREAM* type) : CStructHdl(type) {} + PVRStreamProperties(PVR_STREAM_PROPERTIES::PVR_STREAM* type) : CStructHdl(type) {} +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes class PVRStreamTimes +/// @ingroup cpp_kodi_addon_pvr_Defs_Stream +/// @brief **Times of playing stream (Live TV and recordings)**\n +/// This class is used to transfer the necessary data when +/// @ref kodi::addon::PVRStreamProperties::GetStreamTimes is called. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes_Help +/// +///@{ +class PVRStreamTimes : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVRStreamTimes() { memset(m_cStructure, 0, sizeof(PVR_STREAM_TIMES)); } + PVRStreamTimes(const PVRStreamTimes& type) : CStructHdl(type) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes + /// ---------------------------------------------------------------------------- + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes : + /// | Name | Type | Set call | Get call + /// |------|------|----------|---------- + /// | **Start time** | `time_t` | @ref PVRStreamTimes::SetStartTime "SetStartTime" | @ref PVRStreamTimes::GetStartTime "GetStartTime" + /// | **PTS start** | `int64_t` | @ref PVRStreamTimes::SetPTSStart "SetPTSStart" | @ref PVRStreamTimes::GetPTSStart "GetPTSStart" + /// | **PTS begin** | `int64_t` | @ref PVRStreamTimes::SetPTSBegin "SetPTSBegin" | @ref PVRStreamTimes::GetPTSBegin "GetPTSBegin" + /// | **PTS end** | `int64_t` | @ref PVRStreamTimes::SetPTSEnd "SetPTSEnd" | @ref PVRStreamTimes::GetPTSEnd "GetPTSEnd" + /// + + /// @addtogroup cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes + ///@{ + + /// @brief For recordings, this must be zero. For Live TV, this is a reference + /// time in units of time_t (UTC) from which time elapsed starts. Ideally start + /// of tv show, but can be any other value. + void SetStartTime(time_t startTime) { m_cStructure->startTime = startTime; } + + /// @brief To get with @ref SetStartTime() changed values. + time_t GetStartTime() const { return m_cStructure->startTime; } + + /// @brief The pts of startTime. + void SetPTSStart(int64_t ptsStart) { m_cStructure->ptsStart = ptsStart; } + + /// @brief To get with @ref SetPTSStart() changed values. + int64_t GetPTSStart() const { return m_cStructure->ptsStart; } + + /// @brief Earliest pts player can seek back. Value is in micro seconds, + /// relative to PTS start. For recordings, this must be zero. For Live TV, this + /// must be zero if not timeshifting and must point to begin of the timeshift + /// buffer, otherwise. + void SetPTSBegin(int64_t ptsBegin) { m_cStructure->ptsBegin = ptsBegin; } + + /// @brief To get with @ref SetPTSBegin() changed values. + int64_t GetPTSBegin() const { return m_cStructure->ptsBegin; } + + /// @brief Latest pts player can seek forward. Value is in micro seconds, + /// relative to PTS start. For recordings, this must be the total length. For + /// Live TV, this must be zero if not timeshifting and must point to end of + /// the timeshift buffer, otherwise. + void SetPTSEnd(int64_t ptsEnd) { m_cStructure->ptsEnd = ptsEnd; } + + /// @brief To get with @ref SetPTSEnd() changed values. + int64_t GetPTSEnd() const { return m_cStructure->ptsEnd; } + ///@} + +private: + PVRStreamTimes(const PVR_STREAM_TIMES* type) : CStructHdl(type) {} + PVRStreamTimes(PVR_STREAM_TIMES* type) : CStructHdl(type) {} +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Timers.h b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Timers.h new file mode 100644 index 0000000..6e05e55 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/addon-instance/pvr/Timers.h @@ -0,0 +1,896 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "General.h" +#include "../../AddonBase.h" +#include "../../c-api/addon-instance/pvr.h" + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C++" Definitions group 6 - PVR timers +#ifdef __cplusplus + +namespace kodi +{ +namespace addon +{ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimer class PVRTimer +/// @ingroup cpp_kodi_addon_pvr_Defs_Timer +/// @brief **PVR add-on timer type**\n +/// Representation of a timer event. +/// +/// The related values here are automatically initiated to defaults and need +/// only be set if supported and used. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_Timer_PVRTimer_Help +/// +///@{ +class PVRTimer : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVRTimer() + { + m_cStructure->iClientIndex = 0; + m_cStructure->state = PVR_TIMER_STATE_NEW; + m_cStructure->iTimerType = PVR_TIMER_TYPE_NONE; + m_cStructure->iParentClientIndex = 0; + m_cStructure->iClientChannelUid = PVR_TIMER_VALUE_NOT_AVAILABLE; + m_cStructure->startTime = 0; + m_cStructure->endTime = 0; + m_cStructure->bStartAnyTime = false; + m_cStructure->bEndAnyTime = false; + m_cStructure->bFullTextEpgSearch = false; + m_cStructure->iPriority = PVR_TIMER_VALUE_NOT_AVAILABLE; + m_cStructure->iLifetime = PVR_TIMER_VALUE_NOT_AVAILABLE; + m_cStructure->iMaxRecordings = PVR_TIMER_VALUE_NOT_AVAILABLE; + m_cStructure->iRecordingGroup = 0; + m_cStructure->firstDay = 0; + m_cStructure->iWeekdays = PVR_WEEKDAY_NONE; + m_cStructure->iPreventDuplicateEpisodes = 0; + m_cStructure->iEpgUid = 0; + m_cStructure->iMarginStart = 0; + m_cStructure->iMarginEnd = 0; + m_cStructure->iGenreType = PVR_TIMER_VALUE_NOT_AVAILABLE; + m_cStructure->iGenreSubType = PVR_TIMER_VALUE_NOT_AVAILABLE; + } + PVRTimer(const PVRTimer& data) : CStructHdl(data) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimer_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimer + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimer : + /// | Name | Type | Set call | Get call | Usage + /// |------|------|----------|----------|----------- + /// | **Client index** | `unsigned int` | @ref PVRTimer::SetClientIndex "SetClientIndex" | @ref PVRTimer::GetClientIndex "GetClientIndex" | *required to set* + /// | **State** | @ref PVR_TIMER_STATE | @ref PVRTimer::SetState "SetState" | @ref PVRTimer::GetState "GetState" | *required to set* + /// | **Type** | `unsigned int` | @ref PVRTimer::SetTimerType "SetTimerType" | @ref PVRTimer::GetTimerType "GetTimerType" | *required to set* + /// | **Title** | `std::string` | @ref PVRTimer::SetTitle "SetTitle" | @ref PVRTimer::GetTitle "GetTitle" | *required to set* + /// | **Parent client index** | `unsigned int` | @ref PVRTimer::SetParentClientIndex "SetParentClientIndex" | @ref PVRTimer::GetParentClientIndex "GetParentClientIndex" | *optional* + /// | **Client channel unique identifier** | `int` | @ref PVRTimer::SetClientChannelUid "SetClientChannelUid" | @ref PVRTimer::GetClientChannelUid "GetClientChannelUid" | *optional* + /// | **Start time** | `time_t` | @ref PVRTimer::SetStartTime "SetStartTime" | @ref PVRTimer::GetStartTime "GetStartTime" | *optional* + /// | **End time** | `time_t` | @ref PVRTimer::SetEndTime "SetEndTime" | @ref PVRTimer::GetEndTime "GetEndTime" | *optional* + /// | **Start any time** | `bool` | @ref PVRTimer::SetStartAnyTime "SetStartAnyTime" | @ref PVRTimer::GetStartAnyTime "GetStartAnyTime" | *optional* + /// | **End any time** | `bool` | @ref PVRTimer::SetEndAnyTime "SetEndAnyTime" | @ref PVRTimer::GetEndAnyTime "GetEndAnyTime" | *optional* + /// | **EPG search string** | `std::string` | @ref PVRTimer::SetEPGSearchString "SetEPGSearchString" | @ref PVRTimer::GetEPGSearchString "GetEPGSearchString" | *optional* + /// | **Full text EPG search** | `bool` | @ref PVRTimer::SetFullTextEpgSearch "SetFullTextEpgSearch" | @ref PVRTimer::GetFullTextEpgSearch "GetFullTextEpgSearch" | *optional* + /// | **Recording store directory** | `std::string` | @ref PVRTimer::SetDirectory "SetDirectory" | @ref PVRTimer::GetDirectory "GetDirectory" | *optional* + /// | **Timer priority** | `int` | @ref PVRTimer::SetPriority "SetPriority" | @ref PVRTimer::GetPriority "GetPriority" | *optional* + /// | **Timer lifetime** | `int` | @ref PVRTimer::SetLifetime "SetLifetime" | @ref PVRTimer::GetLifetime "GetLifetime" | *optional* + /// | **Max recordings** | `int` | @ref PVRTimer::SetMaxRecordings "SetMaxRecordings" | @ref PVRTimer::GetMaxRecordings "GetMaxRecordings" | *optional* + /// | **Recording group** | `unsigned int` | @ref PVRTimer::SetRecordingGroup "SetRecordingGroup" | @ref PVRTimer::GetRecordingGroup "GetRecordingGroup" | *optional* + /// | **First start day** | `time_t` | @ref PVRTimer::SetFirstDay "SetFirstDay" | @ref PVRTimer::GetFirstDay "GetFirstDay" | *optional* + /// | **Used timer weekdays** | `unsigned int` | @ref PVRTimer::SetWeekdays "SetWeekdays" | @ref PVRTimer::GetWeekdays "GetWeekdays" | *optional* + /// | **Prevent duplicate episodes** | `unsigned int` | @ref PVRTimer::SetPreventDuplicateEpisodes "SetPreventDuplicateEpisodes" | @ref PVRTimer::GetPreventDuplicateEpisodes "GetPreventDuplicateEpisodes" | *optional* + /// | **EPG unique identifier** | `unsigned int` | @ref PVRTimer::SetEPGUid "SetEPGUid" | @ref PVRTimer::GetEPGUid "GetEPGUid" | *optional* + /// | **Margin start** | `unsigned int` | @ref PVRTimer::SetMarginStart "SetMarginStart" | @ref PVRTimer::GetMarginStart "GetMarginStart" | *optional* + /// | **Margin end** | `unsigned int` | @ref PVRTimer::SetMarginEnd "SetMarginEnd" | @ref PVRTimer::GetMarginEnd "GetMarginEnd" | *optional* + /// | **Genre type** | `int` | @ref PVRTimer::SetGenreType "SetGenreType" | @ref PVRTimer::GetGenreType "GetGenreType" | *optional* + /// | **Genre sub type** | `int` | @ref PVRTimer::SetGenreSubType "SetGenreSubType" | @ref PVRTimer::GetGenreSubType "GetGenreSubType" | *optional* + /// | **Series link** | `std::string` | @ref PVRTimer::SetSeriesLink "SetSeriesLink" | @ref PVRTimer::GetSeriesLink "GetSeriesLink" | *optional* + + /// @addtogroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimer + ///@{ + + /// @brief **required**\n + /// The index of this timer given by the client. + /// + /// @ref PVR_TIMER_NO_CLIENT_INDEX indicates that the index was not yet set + /// by the client, for example for new timers created by Kodi and passed the + /// first time to the client. A valid index must be greater than + /// @ref PVR_TIMER_NO_CLIENT_INDEX. + /// + void SetClientIndex(unsigned int clientIndex) { m_cStructure->iClientIndex = clientIndex; } + + /// @brief To get with @ref SetClientIndex changed values. + unsigned int GetClientIndex() const { return m_cStructure->iClientIndex; } + + /// @brief **required**\n + /// The state of this timer. + /// + /// @note @ref PVR_TIMER_STATE_NEW is default. + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVRTimer tag; + /// tag.SetState(PVR_TIMER_STATE_RECORDING); + /// ~~~~~~~~~~~~~ + /// + void SetState(PVR_TIMER_STATE state) { m_cStructure->state = state; } + + /// @brief To get with @ref SetState changed values. + PVR_TIMER_STATE GetState() const { return m_cStructure->state; } + + /// @brief **required**\n + /// The type of this timer. + /// + /// It is private to the addon and can be freely defined by the addon. + /// The value must be greater than @ref PVR_TIMER_TYPE_NONE. + /// + /// Kodi does not interpret this value (except for checking for @ref PVR_TIMER_TYPE_NONE), + /// but will pass the right id to the addon with every @ref PVRTimer instance, + /// thus the addon easily can determine the timer type. + /// + /// @note @ref PVR_TIMER_TYPE_NONE is default. + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVRTimer tag; + /// tag.SetTimerType(123); + /// ~~~~~~~~~~~~~ + /// + void SetTimerType(unsigned int timerType) { m_cStructure->iTimerType = timerType; } + + /// @brief To get with @ref SetTimerType changed values. + unsigned int GetTimerType() const { return m_cStructure->iTimerType; } + + /// @brief **required**\n + /// A title for this timer. + void SetTitle(const std::string& title) + { + strncpy(m_cStructure->strTitle, title.c_str(), sizeof(m_cStructure->strTitle) - 1); + } + + /// @brief To get with @ref SetTitle changed values. + std::string GetTitle() const { return m_cStructure->strTitle; } + + /// @brief **optional**\n + /// For timers scheduled by a repeating timer. + /// + /// The index of the repeating timer that scheduled this timer (it's + /// @ref clientIndex value). Use @ref PVR_TIMER_NO_PARENT to indicate that + /// this timer was no scheduled by a repeating timer. + void SetParentClientIndex(unsigned int parentClientIndex) + { + m_cStructure->iParentClientIndex = parentClientIndex; + } + + /// @brief To get with @ref SetParentClientIndex changed values. + unsigned int GetParentClientIndex() const { return m_cStructure->iParentClientIndex; } + + /// @brief **optional**\n + /// Unique identifier of the channel to record on. + /// + /// @ref PVR_TIMER_ANY_CHANNEL will denote "any channel", not a specific one. + /// @ref PVR_CHANNEL_INVALID_UID denotes that channel uid is not available. + void SetClientChannelUid(int clientChannelUid) + { + m_cStructure->iClientChannelUid = clientChannelUid; + } + + /// @brief To get with @ref SetClientChannelUid changed values + int GetClientChannelUid() const { return m_cStructure->iClientChannelUid; } + + /// @brief **optional**\n + /// Start time of the recording in UTC. + /// + /// Instant timers that are sent to the add-on by Kodi will have this value + /// set to 0. + void SetStartTime(time_t startTime) { m_cStructure->startTime = startTime; } + + /// @brief To get with @ref SetStartTime changed values. + time_t GetStartTime() const { return m_cStructure->startTime; } + + /// @brief **optional**\n + /// End time of the recording in UTC. + void SetEndTime(time_t endTime) { m_cStructure->endTime = endTime; } + + /// @brief To get with @ref SetEndTime changed values. + time_t GetEndTime() const { return m_cStructure->endTime; } + + /// @brief **optional**\n + /// For EPG based (not Manual) timers indicates startTime does not apply. + /// + /// Default = false. + void SetStartAnyTime(bool startAnyTime) { m_cStructure->bStartAnyTime = startAnyTime; } + + /// @brief To get with @ref SetStartAnyTime changed values. + bool GetStartAnyTime() const { return m_cStructure->bStartAnyTime; } + + /// @brief **optional**\n + /// For EPG based (not Manual) timers indicates endTime does not apply. + /// + /// Default = false + void SetEndAnyTime(bool endAnyTime) { m_cStructure->bEndAnyTime = endAnyTime; } + + /// @brief To get with @ref SetEndAnyTime changed values. + bool GetEndAnyTime() const { return m_cStructure->bEndAnyTime; } + + /// @brief **optional**\n + /// A string used to search epg data for repeating epg-based timers. + /// + /// Format is backend-dependent, for example regexp. + void SetEPGSearchString(const std::string& epgSearchString) + { + strncpy(m_cStructure->strEpgSearchString, epgSearchString.c_str(), + sizeof(m_cStructure->strEpgSearchString) - 1); + } + + /// @brief To get with @ref SetEPGSearchString changed values + std::string GetEPGSearchString() const { return m_cStructure->strEpgSearchString; } + + /// @brief **optional**\n + /// Indicates, whether @ref SetEPGSearchString() is to match against the epg + /// episode title only or also against "other" epg data (backend-dependent). + void SetFullTextEpgSearch(bool fullTextEpgSearch) + { + m_cStructure->bFullTextEpgSearch = fullTextEpgSearch; + } + + /// @brief To get with @ref SetFullTextEpgSearch changed values. + bool GetFullTextEpgSearch() const { return m_cStructure->bFullTextEpgSearch; } + + /// @brief **optional**\n + /// The (relative) directory where the recording will be stored in. + void SetDirectory(const std::string& directory) + { + strncpy(m_cStructure->strDirectory, directory.c_str(), sizeof(m_cStructure->strDirectory) - 1); + } + + /// @brief To get with @ref SetDirectory changed values. + std::string GetDirectory() const { return m_cStructure->strDirectory; } + + /// @brief **optional**\n + /// The summary for this timer. + void SetSummary(const std::string& summary) + { + strncpy(m_cStructure->strSummary, summary.c_str(), sizeof(m_cStructure->strSummary) - 1); + } + + /// @brief To get with @ref SetDirectory changed values. + std::string GetSummary() const { return m_cStructure->strSummary; } + + /// @brief **optional**\n + /// The priority of this timer. + void SetPriority(int priority) { m_cStructure->iPriority = priority; } + + /// @brief To get with @ref SetPriority changed values. + int GetPriority() const { return m_cStructure->iPriority; } + + /// @brief **optional**\n + /// Lifetime of recordings created by this timer. + /// + /// Value > 0 days after which recordings will be deleted by the backend, < 0 + /// addon defined integer list reference, == 0 disabled. + void SetLifetime(int priority) { m_cStructure->iLifetime = priority; } + + /// @brief To get with @ref SetLifetime changed values. + int GetLifetime() const { return m_cStructure->iLifetime; } + + /// @brief **optional**\n + /// Maximum number of recordings this timer shall create. + /// + /// Value > 0 number of recordings, < 0 addon defined integer list reference, == 0 disabled. + void SetMaxRecordings(int maxRecordings) { m_cStructure->iMaxRecordings = maxRecordings; } + + /// @brief To get with @ref SetMaxRecordings changed values. + int GetMaxRecordings() const { return m_cStructure->iMaxRecordings; } + + /// @brief **optional**\n + /// Integer ref to addon/backend defined list of recording groups. + void SetRecordingGroup(unsigned int recordingGroup) + { + m_cStructure->iRecordingGroup = recordingGroup; + } + + /// @brief To get with @ref SetRecordingGroup changed values. + unsigned int GetRecordingGroup() const { return m_cStructure->iRecordingGroup; } + + /// @brief **optional**\n + /// The first day this timer is active, for repeating timers. + void SetFirstDay(time_t firstDay) { m_cStructure->firstDay = firstDay; } + + /// @brief To get with @ref SetFirstDay changed values. + time_t GetFirstDay() const { return m_cStructure->firstDay; } + + /// @brief **optional**\n + /// Week days, for repeating timers (see + /// @ref cpp_kodi_addon_pvr_Defs_Timer_PVR_WEEKDAY "PVR_WEEKDAY_*" constant values) + /// + /// @note @ref PVR_WEEKDAY_NONE is default. + /// + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// kodi::addon::PVRTimer tag; + /// tag.SetWeekdays(PVR_WEEKDAY_MONDAY | PVR_WEEKDAY_SATURDAY); + /// ... + /// ~~~~~~~~~~~~~ + void SetWeekdays(unsigned int weekdays) { m_cStructure->iWeekdays = weekdays; } + + /// @brief To get with @ref SetFirstDay changed values. + unsigned int GetWeekdays() const { return m_cStructure->iWeekdays; } + + /// @brief **optional**\n + /// Prevent duplicate episodes. + /// + /// Should 1 if backend should only record new episodes in case of a repeating + /// epg-based timer, 0 if all episodes shall be recorded (no duplicate detection). + /// + /// Actual algorithm for duplicate detection is defined by the backend. + /// Addons may define own values for different duplicate detection + /// algorithms, thus this is not just a bool. + void SetPreventDuplicateEpisodes(unsigned int preventDuplicateEpisodes) + { + m_cStructure->iPreventDuplicateEpisodes = preventDuplicateEpisodes; + } + + /// @brief To get with @ref SetPreventDuplicateEpisodes changed values. + unsigned int GetPreventDuplicateEpisodes() const + { + return m_cStructure->iPreventDuplicateEpisodes; + } + + /// @brief **optional**\n + /// EPG event id associated with this timer. Event ids must be unique for a + /// channel. + /// + /// Valid ids must be greater than @ref EPG_TAG_INVALID_UID. + void SetEPGUid(unsigned int epgUid) { m_cStructure->iEpgUid = epgUid; } + + /// @brief To get with @ref SetEPGUid changed values. + unsigned int GetEPGUid() const { return m_cStructure->iEpgUid; } + + /// @brief **optional**\n + /// If set, the backend starts the recording selected minutes before + /// @ref SetStartTime. + void SetMarginStart(unsigned int marginStart) { m_cStructure->iMarginStart = marginStart; } + + /// @brief To get with @ref SetMarginStart changed values. + unsigned int GetMarginStart() const { return m_cStructure->iMarginStart; } + + /// @brief **optional**\n + /// If set, the backend ends the recording selected minutes after + /// @ref SetEndTime. + void SetMarginEnd(unsigned int marginEnd) { m_cStructure->iMarginEnd = marginEnd; } + + /// @brief To get with @ref SetMarginEnd changed values. + unsigned int GetMarginEnd() const { return m_cStructure->iMarginEnd; } + + /// @brief **optional**\n + /// Genre type. + /// + /// @copydetails EPG_EVENT_CONTENTMASK + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// kodi::addon::PVRTimer tag; + /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MOVIEDRAMA); + /// ... + /// ~~~~~~~~~~~~~ + /// + /// @note If confirmed that backend brings the types in [ETSI EN 300 468](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) + /// conform values, can be @ref EPG_EVENT_CONTENTMASK ignored and to set here + /// with backend value. + /// + void SetGenreType(int genreType) { m_cStructure->iGenreType = genreType; } + + /// @brief To get with @ref SetGenreType changed values. + int GetGenreType() const { return m_cStructure->iGenreType; } + + /// @brief **optional**\n + /// Genre sub type. + /// + /// @copydetails EPG_EVENT_CONTENTMASK + /// + /// Subtypes groups related to set by @ref SetGenreType: + /// | Main genre type | List with available sub genre types + /// |-----------------|----------------------------------------- + /// | @ref EPG_EVENT_CONTENTMASK_UNDEFINED | Nothing, should be 0 + /// | @ref EPG_EVENT_CONTENTMASK_MOVIEDRAMA | @ref EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA + /// | @ref EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS | @ref EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS + /// | @ref EPG_EVENT_CONTENTMASK_SHOW | @ref EPG_EVENT_CONTENTSUBMASK_SHOW + /// | @ref EPG_EVENT_CONTENTMASK_SPORTS | @ref EPG_EVENT_CONTENTSUBMASK_SPORTS + /// | @ref EPG_EVENT_CONTENTMASK_CHILDRENYOUTH | @ref EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH + /// | @ref EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE | @ref EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE + /// | @ref EPG_EVENT_CONTENTMASK_ARTSCULTURE | @ref EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE + /// | @ref EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS | @ref EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS + /// | @ref EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE | @ref EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE + /// | @ref EPG_EVENT_CONTENTMASK_LEISUREHOBBIES | @ref EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES + /// | @ref EPG_EVENT_CONTENTMASK_SPECIAL | @ref EPG_EVENT_CONTENTSUBMASK_SPECIAL + /// | @ref EPG_EVENT_CONTENTMASK_USERDEFINED | Can be defined by you + /// + /// -------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// kodi::addon::PVRTimer tag; + /// tag.SetGenreType(EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE); + /// tag.SetGenreSubType(EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_JAZZ); + /// ... + /// ~~~~~~~~~~~~~ + /// + void SetGenreSubType(int genreSubType) { m_cStructure->iGenreSubType = genreSubType; } + + /// @brief To get with @ref SetGenreType changed values. + int GetGenreSubType() const { return m_cStructure->iGenreSubType; } + + /// @brief **optional**\n + /// Series link for this timer. + /// + /// If set for an epg-based timer rule, matching events will be found by + /// checking with here, instead of @ref SetTitle() (and @ref SetFullTextEpgSearch()). + void SetSeriesLink(const std::string& seriesLink) + { + strncpy(m_cStructure->strSeriesLink, seriesLink.c_str(), + sizeof(m_cStructure->strSeriesLink) - 1); + } + + /// @brief To get with @ref SetSeriesLink changed values. + std::string GetSeriesLink() const { return m_cStructure->strSeriesLink; } + ///@} + +private: + PVRTimer(const PVR_TIMER* data) : CStructHdl(data) {} + PVRTimer(PVR_TIMER* data) : CStructHdl(data) {} +}; + +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimersResultSet class PVRTimersResultSet +/// @ingroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimer +/// @brief **PVR add-on timer transfer class**\n +/// To transfer the content of @ref kodi::addon::CInstancePVRClient::GetTimers(). +/// +/// @note This becomes only be used on addon call above, not usable outside on +/// addon itself. +///@{ +class PVRTimersResultSet +{ +public: + /*! \cond PRIVATE */ + PVRTimersResultSet() = delete; + PVRTimersResultSet(const AddonInstance_PVR* instance, ADDON_HANDLE handle) + : m_instance(instance), m_handle(handle) + { + } + /*! \endcond */ + + /// @addtogroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimersResultSet + ///@{ + + /// @brief To add and give content from addon to Kodi on related call. + /// + /// @param[in] tag The to transferred data. + void Add(const kodi::addon::PVRTimer& tag) + { + m_instance->toKodi->TransferTimerEntry(m_instance->toKodi->kodiInstance, m_handle, tag); + } + + ///@} + +private: + const AddonInstance_PVR* m_instance = nullptr; + const ADDON_HANDLE m_handle; +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType class PVRTimerType +/// @ingroup cpp_kodi_addon_pvr_Defs_Timer +/// @brief **PVR add-on timer type**\n +/// To define the content of @ref kodi::addon::CInstancePVRClient::GetTimerTypes() +/// given groups. +/// +/// ---------------------------------------------------------------------------- +/// +/// @copydetails cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType_Help +/// +///@{ +class PVRTimerType : public CStructHdl +{ + friend class CInstancePVRClient; + +public: + /*! \cond PRIVATE */ + PVRTimerType() + { + memset(m_cStructure, 0, sizeof(PVR_TIMER_TYPE)); + m_cStructure->iPrioritiesDefault = -1; + m_cStructure->iLifetimesDefault = -1; + m_cStructure->iPreventDuplicateEpisodesDefault = -1; + m_cStructure->iRecordingGroupDefault = -1; + m_cStructure->iMaxRecordingsDefault = -1; + } + PVRTimerType(const PVRTimerType& type) : CStructHdl(type) {} + /*! \endcond */ + + /// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType_Help Value Help + /// @ingroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType + /// ---------------------------------------------------------------------------- + /// + /// The following table contains values that can be set with @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType : + /// | Name | Type | Set call | Get call | Usage + /// |------|------|----------|----------|----------- + /// | **Identifier** | `unsigned int` | @ref PVRTimerType::SetId "SetId" | @ref PVRTimerType::GetId "GetId" | *required to set* + /// | **Attributes** | `unsigned int` | @ref PVRTimerType::SetAttributes "SetAttributes" | @ref PVRTimerType::GetAttributes "GetAttributes" | *required to set* + /// | **Description** | `std::string` | @ref PVRTimerType::SetDescription "SetDescription" | @ref PVRTimerType::GetDescription "GetDescription" | *optional* + /// | | | | | | + /// | **Priority selection** | @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue "PVRTypeIntValue" | @ref PVRTimerType::SetPriorities "SetPriorities" | @ref PVRTimerType::GetPriorities "GetPriorities" | *optional* + /// | **Priority default selection** | `int`| @ref PVRTimerType::SetPrioritiesDefault "SetPrioritiesDefault" | @ref PVRTimerType::GetPrioritiesDefault "GetPrioritiesDefault" | *optional* + /// | | | | | | + /// | **Lifetime selection** | @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue "PVRTypeIntValue" | @ref PVRTimerType::SetLifetimes "SetLifetimes" | @ref PVRTimerType::GetLifetimes "GetLifetimes" | *optional* + /// | **Lifetime default selection** | `int`| @ref PVRTimerType::SetLifetimesDefault "SetLifetimesDefault" | @ref PVRTimerType::GetLifetimesDefault "GetLifetimesDefault" | *optional* + /// | | | | | | + /// | **Prevent duplicate episodes selection** | @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue "PVRTypeIntValue" | @ref PVRTimerType::SetPreventDuplicateEpisodes "SetPreventDuplicateEpisodes" | @ref PVRTimerType::GetPreventDuplicateEpisodes "GetPreventDuplicateEpisodes" | *optional* + /// | **Prevent duplicate episodes default** | `int`| @ref PVRTimerType::SetPreventDuplicateEpisodesDefault "SetPreventDuplicateEpisodesDefault" | @ref PVRTimerType::GetPreventDuplicateEpisodesDefault "GetPreventDuplicateEpisodesDefault" | *optional* + /// | | | | | | + /// | **Recording group selection**| @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue "PVRTypeIntValue" | @ref PVRTimerType::SetRecordingGroups "SetRecordingGroups" | @ref PVRTimerType::GetRecordingGroups "GetRecordingGroups" | *optional* + /// | **Recording group default** | `int`| @ref PVRTimerType::SetRecordingGroupDefault "SetRecordingGroupDefault" | @ref PVRTimerType::GetRecordingGroupDefault "GetRecordingGroupDefault" | *optional* + /// | | | | | | + /// | **Max recordings selection** | @ref cpp_kodi_addon_pvr_Defs_PVRTypeIntValue "PVRTypeIntValue" | @ref PVRTimerType::SetMaxRecordings "SetMaxRecordings" | @ref PVRTimerType::GetMaxRecordings "GetMaxRecordings" | *optional* + /// | **Max recordings default** | `int`| @ref PVRTimerType::SetMaxRecordingsDefault "SetMaxRecordingsDefault" | @ref PVRTimerType::GetMaxRecordingsDefault "GetMaxRecordingsDefault" | *optional* + /// + + /// @addtogroup cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType + ///@{ + + /// @brief **required**\n + /// This type's identifier. Ids must be > @ref PVR_TIMER_TYPE_NONE. + void SetId(unsigned int id) { m_cStructure->iId = id; } + + /// @brief To get with @ref SetAttributes changed values. + unsigned int GetId() const { return m_cStructure->iId; } + + /// @brief **required**\n + /// Defines the attributes for this type (@ref cpp_kodi_addon_pvr_Defs_Timer_PVR_TIMER_TYPE "PVR_TIMER_TYPE_*" constants). + /// + /// To defines the attributes for a type. These values are bit fields that can be + /// used together. + /// + ///-------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVRTimerType tag; + /// tag.SetAttributes(PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_IS_REPEATING); + /// ~~~~~~~~~~~~~ + /// + void SetAttributes(uint64_t attributes) { m_cStructure->iAttributes = attributes; } + + /// @brief To get with @ref SetAttributes changed values. + uint64_t GetAttributes() const { return m_cStructure->iAttributes; } + + /// @brief **optional**\n + /// A short localized string describing the purpose of the type. (e.g. + /// "Any time at this channel if title matches"). + /// + /// If left blank, Kodi will generate a description based on the attributes + /// REPEATING and MANUAL. (e.g. "Repeating EPG-based.") + void SetDescription(const std::string& description) + { + strncpy(m_cStructure->strDescription, description.c_str(), + sizeof(m_cStructure->strDescription) - 1); + } + + /// @brief To get with @ref SetDescription changed values. + std::string GetDescription() const { return m_cStructure->strDescription; } + + //---------------------------------------------------------------------------- + + /// @brief **optional**\n + /// Priority value definitions. + /// + /// Array containing the possible values for @ref PVRTimer::SetPriority(). + /// + /// @param[in] priorities List of priority values + /// @param[in] prioritiesDefault [opt] The default value in list, can also be + /// set by @ref SetPrioritiesDefault() + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help + void SetPriorities(const std::vector& priorities, int prioritiesDefault = -1) + { + m_cStructure->iPrioritiesSize = static_cast(priorities.size()); + for (unsigned int i = 0; + i < m_cStructure->iPrioritiesSize && i < sizeof(m_cStructure->priorities); ++i) + { + m_cStructure->priorities[i].iValue = priorities[i].GetCStructure()->iValue; + strncpy(m_cStructure->priorities[i].strDescription, + priorities[i].GetCStructure()->strDescription, + sizeof(m_cStructure->priorities[i].strDescription) - 1); + } + if (prioritiesDefault != -1) + m_cStructure->iPrioritiesDefault = prioritiesDefault; + } + + /// @brief To get with @ref SetPriorities changed values. + std::vector GetPriorities() const + { + std::vector ret; + for (unsigned int i = 0; i < m_cStructure->iPrioritiesSize; ++i) + ret.emplace_back(m_cStructure->priorities[i].iValue, + m_cStructure->priorities[i].strDescription); + return ret; + } + + /// @brief **optional**\n + /// The default value for @ref PVRTimer::SetPriority(). + /// + /// @note Must be filled if @ref SetPriorities contain values and not + /// defined there on second function value. + void SetPrioritiesDefault(int prioritiesDefault) + { + m_cStructure->iPrioritiesDefault = prioritiesDefault; + } + + /// @brief To get with @ref SetPrioritiesDefault changed values. + int GetPrioritiesDefault() const { return m_cStructure->iPrioritiesDefault; } + + //---------------------------------------------------------------------------- + + /// @brief **optional**\n + /// Lifetime value definitions. + /// + /// Array containing the possible values for @ref PVRTimer::SetLifetime(). + /// + /// @param[in] lifetimes List of lifetimes values + /// @param[in] lifetimesDefault [opt] The default value in list, can also be + /// set by @ref SetLifetimesDefault() + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help + void SetLifetimes(const std::vector& lifetimes, int lifetimesDefault = -1) + { + m_cStructure->iLifetimesSize = static_cast(lifetimes.size()); + for (unsigned int i = 0; + i < m_cStructure->iLifetimesSize && i < sizeof(m_cStructure->lifetimes); ++i) + { + m_cStructure->lifetimes[i].iValue = lifetimes[i].GetCStructure()->iValue; + strncpy(m_cStructure->lifetimes[i].strDescription, + lifetimes[i].GetCStructure()->strDescription, + sizeof(m_cStructure->lifetimes[i].strDescription) - 1); + } + if (lifetimesDefault != -1) + m_cStructure->iLifetimesDefault = lifetimesDefault; + } + + /// @brief To get with @ref SetLifetimes changed values. + std::vector GetLifetimes() const + { + std::vector ret; + for (unsigned int i = 0; i < m_cStructure->iLifetimesSize; ++i) + ret.emplace_back(m_cStructure->lifetimes[i].iValue, + m_cStructure->lifetimes[i].strDescription); + return ret; + } + + /// @brief **optional**\n + /// The default value for @ref SetLifetimes(). + /// + /// @note Must be filled if @ref SetLifetimes contain values and not + /// defined there on second function value. + void SetLifetimesDefault(int lifetimesDefault) + { + m_cStructure->iLifetimesDefault = lifetimesDefault; + } + + /// @brief To get with @ref SetLifetimesDefault changed values. + int GetLifetimesDefault() const { return m_cStructure->iLifetimesDefault; } + + //---------------------------------------------------------------------------- + + /// @brief **optional**\n + /// Prevent duplicate episodes value definitions. + /// + /// Array containing the possible values for @ref PVRTimer::SetPreventDuplicateEpisodes(). + /// + /// @note Must be filled if @ref PVRTimer::SetPreventDuplicateEpisodes() is not empty. + /// + /// @param[in] preventDuplicateEpisodes List of duplicate episodes values + /// @param[in] preventDuplicateEpisodesDefault [opt] The default value in list, can also be + /// set by @ref SetPreventDuplicateEpisodesDefault() + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help + void SetPreventDuplicateEpisodes( + const std::vector& preventDuplicateEpisodes, + int preventDuplicateEpisodesDefault = -1) + { + m_cStructure->iPreventDuplicateEpisodesSize = + static_cast(preventDuplicateEpisodes.size()); + for (unsigned int i = 0; i < m_cStructure->iPreventDuplicateEpisodesSize && + i < sizeof(m_cStructure->preventDuplicateEpisodes); + ++i) + { + m_cStructure->preventDuplicateEpisodes[i].iValue = + preventDuplicateEpisodes[i].GetCStructure()->iValue; + strncpy(m_cStructure->preventDuplicateEpisodes[i].strDescription, + preventDuplicateEpisodes[i].GetCStructure()->strDescription, + sizeof(m_cStructure->preventDuplicateEpisodes[i].strDescription) - 1); + } + if (preventDuplicateEpisodesDefault != -1) + m_cStructure->iPreventDuplicateEpisodesDefault = preventDuplicateEpisodesDefault; + } + + /// @brief To get with @ref SetPreventDuplicateEpisodes changed values. + std::vector GetPreventDuplicateEpisodes() const + { + std::vector ret; + for (unsigned int i = 0; i < m_cStructure->iPreventDuplicateEpisodesSize; ++i) + ret.emplace_back(m_cStructure->preventDuplicateEpisodes[i].iValue, + m_cStructure->preventDuplicateEpisodes[i].strDescription); + return ret; + } + + /// @brief **optional**\n + /// The default value for @ref PVRTimer::SetPreventDuplicateEpisodes(). + /// + /// @note Must be filled if @ref SetPreventDuplicateEpisodes contain values and not + /// defined there on second function value. + void SetPreventDuplicateEpisodesDefault(int preventDuplicateEpisodesDefault) + { + m_cStructure->iPreventDuplicateEpisodesDefault = preventDuplicateEpisodesDefault; + } + + /// @brief To get with @ref SetPreventDuplicateEpisodesDefault changed values. + int GetPreventDuplicateEpisodesDefault() const + { + return m_cStructure->iPreventDuplicateEpisodesDefault; + } + + //---------------------------------------------------------------------------- + + /// @brief **optional**\n + /// Array containing the possible values of @ref PVRTimer::SetRecordingGroup() + /// + /// @param[in] recordingGroup List of recording group values + /// @param[in] recordingGroupDefault [opt] The default value in list, can also be + /// set by @ref SetRecordingGroupDefault() + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help + void SetRecordingGroups(const std::vector& recordingGroup, + int recordingGroupDefault = -1) + { + m_cStructure->iRecordingGroupSize = static_cast(recordingGroup.size()); + for (unsigned int i = 0; + i < m_cStructure->iRecordingGroupSize && i < sizeof(m_cStructure->recordingGroup); ++i) + { + m_cStructure->recordingGroup[i].iValue = recordingGroup[i].GetCStructure()->iValue; + strncpy(m_cStructure->recordingGroup[i].strDescription, + recordingGroup[i].GetCStructure()->strDescription, + sizeof(m_cStructure->recordingGroup[i].strDescription) - 1); + } + if (recordingGroupDefault != -1) + m_cStructure->iRecordingGroupDefault = recordingGroupDefault; + } + + /// @brief To get with @ref SetRecordingGroups changed values + std::vector GetRecordingGroups() const + { + std::vector ret; + for (unsigned int i = 0; i < m_cStructure->iRecordingGroupSize; ++i) + ret.emplace_back(m_cStructure->recordingGroup[i].iValue, + m_cStructure->recordingGroup[i].strDescription); + return ret; + } + + /// @brief **optional**\n + /// The default value for @ref PVRTimer::SetRecordingGroup(). + /// + /// @note Must be filled if @ref SetRecordingGroups contain values and not + /// defined there on second function value. + void SetRecordingGroupDefault(int recordingGroupDefault) + { + m_cStructure->iRecordingGroupDefault = recordingGroupDefault; + } + + /// @brief To get with @ref SetRecordingGroupDefault changed values + int GetRecordingGroupDefault() const { return m_cStructure->iRecordingGroupDefault; } + + //---------------------------------------------------------------------------- + + /// @brief **optional**\n + /// Array containing the possible values of @ref PVRTimer::SetMaxRecordings(). + /// + /// @param[in] maxRecordings List of lifetimes values + /// @param[in] maxRecordingsDefault [opt] The default value in list, can also be + /// set by @ref SetMaxRecordingsDefault() + /// + /// -------------------------------------------------------------------------- + /// + /// @copydetails cpp_kodi_addon_pvr_Defs_PVRTypeIntValue_Help + void SetMaxRecordings(const std::vector& maxRecordings, + int maxRecordingsDefault = -1) + { + m_cStructure->iMaxRecordingsSize = static_cast(maxRecordings.size()); + for (unsigned int i = 0; + i < m_cStructure->iMaxRecordingsSize && i < sizeof(m_cStructure->maxRecordings); ++i) + { + m_cStructure->maxRecordings[i].iValue = maxRecordings[i].GetCStructure()->iValue; + strncpy(m_cStructure->maxRecordings[i].strDescription, + maxRecordings[i].GetCStructure()->strDescription, + sizeof(m_cStructure->maxRecordings[i].strDescription) - 1); + } + if (maxRecordingsDefault != -1) + m_cStructure->iMaxRecordingsDefault = maxRecordingsDefault; + } + + /// @brief To get with @ref SetMaxRecordings changed values + std::vector GetMaxRecordings() const + { + std::vector ret; + for (unsigned int i = 0; i < m_cStructure->iMaxRecordingsSize; ++i) + ret.emplace_back(m_cStructure->maxRecordings[i].iValue, + m_cStructure->maxRecordings[i].strDescription); + return ret; + } + + /// @brief **optional**\n + /// The default value for @ref SetMaxRecordings(). + /// + /// Can be set with here if on @ref SetMaxRecordings not given as second value. + void SetMaxRecordingsDefault(int maxRecordingsDefault) + { + m_cStructure->iMaxRecordingsDefault = maxRecordingsDefault; + } + + /// @brief To get with @ref SetMaxRecordingsDefault changed values + int GetMaxRecordingsDefault() const { return m_cStructure->iMaxRecordingsDefault; } + ///@} + +private: + PVRTimerType(const PVR_TIMER_TYPE* type) : CStructHdl(type) {} + PVRTimerType(PVR_TIMER_TYPE* type) : CStructHdl(type) {} +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace addon */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/CMakeLists.txt new file mode 100644 index 0000000..091e0fe --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/CMakeLists.txt @@ -0,0 +1,13 @@ +set(HEADERS addon_base.h + audio_engine.h + filesystem.h + general.h + network.h) + +if(CORE_SYSTEM_NAME STREQUAL android) + list(APPEND SOURCES platform/android/system.h) +endif() + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_c-api) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/CMakeLists.txt new file mode 100644 index 0000000..4edd034 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/CMakeLists.txt @@ -0,0 +1,13 @@ +set(HEADERS audio_decoder.h + audio_encoder.h + game.h + image_decoder.h + peripheral.h + pvr.h + screensaver.h + vfs.h + visualization.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_c-api_addon-instance) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/audio_decoder.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/audio_decoder.h new file mode 100644 index 0000000..8b75ddb --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/audio_decoder.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_AUDIO_DECODER_H +#define C_API_ADDONINSTANCE_AUDIO_DECODER_H + +#include "../addon_base.h" +#include "../audio_engine.h" + +#define AUDIO_DECODER_LYRICS_SIZE 65535 + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + // WARNING About size use malloc/new! + struct AUDIO_DECODER_INFO_TAG + { + char title[ADDON_STANDARD_STRING_LENGTH_SMALL]; + char artist[ADDON_STANDARD_STRING_LENGTH_SMALL]; + char album[ADDON_STANDARD_STRING_LENGTH_SMALL]; + char album_artist[ADDON_STANDARD_STRING_LENGTH_SMALL]; + char media_type[ADDON_STANDARD_STRING_LENGTH_SMALL]; + char genre[ADDON_STANDARD_STRING_LENGTH_SMALL]; + int duration; + int track; + int disc; + char disc_subtitle[ADDON_STANDARD_STRING_LENGTH_SMALL]; + int disc_total; + char release_date[ADDON_STANDARD_STRING_LENGTH_SMALL]; + char lyrics[AUDIO_DECODER_LYRICS_SIZE]; + int samplerate; + int channels; + int bitrate; + char comment[ADDON_STANDARD_STRING_LENGTH]; + }; + + typedef struct AddonProps_AudioDecoder + { + int dummy; + } AddonProps_AudioDecoder; + + typedef struct AddonToKodiFuncTable_AudioDecoder + { + KODI_HANDLE kodiInstance; + } AddonToKodiFuncTable_AudioDecoder; + + struct AddonInstance_AudioDecoder; + typedef struct KodiToAddonFuncTable_AudioDecoder + { + KODI_HANDLE addonInstance; + bool(__cdecl* init)(const struct AddonInstance_AudioDecoder* instance, + const char* file, + unsigned int filecache, + int* channels, + int* samplerate, + int* bitspersample, + int64_t* totaltime, + int* bitrate, + enum AudioEngineDataFormat* format, + const enum AudioEngineChannel** info); + int(__cdecl* read_pcm)(const struct AddonInstance_AudioDecoder* instance, + uint8_t* buffer, + int size, + int* actualsize); + int64_t(__cdecl* seek)(const struct AddonInstance_AudioDecoder* instance, int64_t time); + bool(__cdecl* read_tag)(const struct AddonInstance_AudioDecoder* instance, + const char* file, + struct AUDIO_DECODER_INFO_TAG* tag); + int(__cdecl* track_count)(const struct AddonInstance_AudioDecoder* instance, const char* file); + } KodiToAddonFuncTable_AudioDecoder; + + typedef struct AddonInstance_AudioDecoder + { + struct AddonProps_AudioDecoder* props; + struct AddonToKodiFuncTable_AudioDecoder* toKodi; + struct KodiToAddonFuncTable_AudioDecoder* toAddon; + } AddonInstance_AudioDecoder; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_AUDIO_DECODER_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/audio_encoder.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/audio_encoder.h new file mode 100644 index 0000000..6f24d1c --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/audio_encoder.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_AUDIO_ENCODER_H +#define C_API_ADDONINSTANCE_AUDIO_ENCODER_H + +#include "../addon_base.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonProps_AudioEncoder + { + int dummy; + } AddonProps_AudioEncoder; + + typedef struct AddonToKodiFuncTable_AudioEncoder + { + KODI_HANDLE kodiInstance; + int (*write)(KODI_HANDLE kodiInstance, const uint8_t* data, int len); + int64_t (*seek)(KODI_HANDLE kodiInstance, int64_t pos, int whence); + } AddonToKodiFuncTable_AudioEncoder; + + struct AddonInstance_AudioEncoder; + typedef struct KodiToAddonFuncTable_AudioEncoder + { + KODI_HANDLE addonInstance; + bool(__cdecl* start)(const struct AddonInstance_AudioEncoder* instance, + int in_channels, + int in_rate, + int in_bits, + const char* title, + const char* artist, + const char* albumartist, + const char* album, + const char* year, + const char* track, + const char* genre, + const char* comment, + int track_length); + int(__cdecl* encode)(const struct AddonInstance_AudioEncoder* instance, + int num_bytes_read, + const uint8_t* pbt_stream); + bool(__cdecl* finish)(const struct AddonInstance_AudioEncoder* instance); + } KodiToAddonFuncTable_AudioEncoder; + + typedef struct AddonInstance_AudioEncoder + { + struct AddonProps_AudioEncoder* props; + struct AddonToKodiFuncTable_AudioEncoder* toKodi; + struct KodiToAddonFuncTable_AudioEncoder* toAddon; + } AddonInstance_AudioEncoder; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_AUDIO_ENCODER_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/game.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/game.h new file mode 100644 index 0000000..c97fa5d --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/game.h @@ -0,0 +1,1212 @@ +/* + * Copyright (C) 2014-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_GAME_H +#define C_API_ADDONINSTANCE_GAME_H + +#include "../addon_base.h" + +#include /* size_t */ + +//============================================================================== +/// @ingroup cpp_kodi_addon_game_Defs +/// @brief **Port ID used when topology is unknown** +#define DEFAULT_PORT_ID "1" +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// @ingroup cpp_kodi_addon_game_Defs + /// @brief **Game add-on error codes** + /// + /// Used as return values on most Game related functions. + /// + typedef enum GAME_ERROR + { + /// @brief no error occurred + GAME_ERROR_NO_ERROR, + + /// @brief an unknown error occurred + GAME_ERROR_UNKNOWN, + + /// @brief the method that the frontend called is not implemented + GAME_ERROR_NOT_IMPLEMENTED, + + /// @brief the command was rejected by the game client + GAME_ERROR_REJECTED, + + /// @brief the parameters of the method that was called are invalid for this operation + GAME_ERROR_INVALID_PARAMETERS, + + /// @brief the command failed + GAME_ERROR_FAILED, + + /// @brief no game is loaded + GAME_ERROR_NOT_LOADED, + + /// @brief game requires restricted resources + GAME_ERROR_RESTRICTED, + } GAME_ERROR; + //---------------------------------------------------------------------------- + + //--==----==----==----==----==----==----==----==----==----==----==----==----==-- + /// @defgroup cpp_kodi_addon_game_Defs_AudioStream 1. Audio stream + /// @ingroup cpp_kodi_addon_game_Defs + /// @brief **The for Audio stream used data system** + /// + /// Used to give Addon currently used audio stream configuration on Kodi and + /// arrays to give related data to Kodi on callbacks. + /// + ///@{ + + //============================================================================ + /// @brief **Stream Format** + /// + /// From Kodi requested specified audio sample format. + /// + typedef enum GAME_PCM_FORMAT + { + GAME_PCM_FORMAT_UNKNOWN, + + /// @brief S16NE sample format + GAME_PCM_FORMAT_S16NE, + } GAME_PCM_FORMAT; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Audio channel** + /// + /// Channel identification flags. + /// + typedef enum GAME_AUDIO_CHANNEL + { + /// @brief Channel list terminator + GAME_CH_NULL, + + /// @brief Channel front left + GAME_CH_FL, + + /// @brief Channel front right + GAME_CH_FR, + + /// @brief Channel front center + GAME_CH_FC, + + /// @brief Channel Low Frequency Effects / Subwoofer + GAME_CH_LFE, + + /// @brief Channel back left + GAME_CH_BL, + + /// @brief Channel back right + GAME_CH_BR, + + /// @brief Channel front left over center + GAME_CH_FLOC, + + /// @brief Channel front right over center + GAME_CH_FROC, + + /// @brief Channel back center + GAME_CH_BC, + + /// @brief Channel surround/side left + GAME_CH_SL, + + /// @brief Channel surround/side right + GAME_CH_SR, + + /// @brief Channel top front left + GAME_CH_TFL, + + /// @brief Channel top front right + GAME_CH_TFR, + + /// @brief Channel top front center + GAME_CH_TFC, + + /// @brief Channel top center + GAME_CH_TC, + + /// @brief Channel top back left + GAME_CH_TBL, + + /// @brief Channel top back right + GAME_CH_TBR, + + /// @brief Channel top back center + GAME_CH_TBC, + + /// @brief Channel bacl left over center + GAME_CH_BLOC, + + /// @brief Channel back right over center + GAME_CH_BROC, + } GAME_AUDIO_CHANNEL; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Game audio stream properties** + /// + /// Used by Kodi to pass the currently required audio stream settings to the addon + /// + typedef struct game_stream_audio_properties + { + GAME_PCM_FORMAT format; + const GAME_AUDIO_CHANNEL* channel_map; + } ATTRIBUTE_PACKED game_stream_audio_properties; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Audio stream packet** + /// + /// This packet contains audio stream data passed to Kodi. + /// + typedef struct game_stream_audio_packet + { + /// @brief Pointer for audio stream data given to Kodi + const uint8_t* data; + + /// @brief Size of data array + size_t size; + } ATTRIBUTE_PACKED game_stream_audio_packet; + //---------------------------------------------------------------------------- + + ///@} + + //--==----==----==----==----==----==----==----==----==----==----==----==----==-- + /// @defgroup cpp_kodi_addon_game_Defs_VideoStream 2. Video stream + /// @ingroup cpp_kodi_addon_game_Defs + /// @brief **The for Video stream used data system** + /// + /// Used to give Addon currently used video stream configuration on Kodi and + /// arrays to give related data to Kodi on callbacks. + /// + ///@{ + + //============================================================================ + /// @brief **Pixel format** + /// + /// From Kodi requested specified video RGB color model format. + /// + typedef enum GAME_PIXEL_FORMAT + { + GAME_PIXEL_FORMAT_UNKNOWN, + + /// @brief 0RGB8888 Format + GAME_PIXEL_FORMAT_0RGB8888, + + /// @brief RGB565 Format + GAME_PIXEL_FORMAT_RGB565, + + /// @brief 0RGB1555 Format + GAME_PIXEL_FORMAT_0RGB1555, + } GAME_PIXEL_FORMAT; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Video rotation position** + /// + /// To define position how video becomes shown. + /// + typedef enum GAME_VIDEO_ROTATION + { + /// @brief 0° and Without rotation + GAME_VIDEO_ROTATION_0, + + /// @brief rotate 90° counterclockwise + GAME_VIDEO_ROTATION_90_CCW, + + /// @brief rotate 180° counterclockwise + GAME_VIDEO_ROTATION_180_CCW, + + /// @brief rotate 270° counterclockwise + GAME_VIDEO_ROTATION_270_CCW, + } GAME_VIDEO_ROTATION; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Game video stream properties** + /// + /// Used by Kodi to pass the currently required video stream settings to the addon + /// + typedef struct game_stream_video_properties + { + /// @brief The to used pixel format + GAME_PIXEL_FORMAT format; + + /// @brief The nominal used width + unsigned int nominal_width; + + /// @brief The nominal used height + unsigned int nominal_height; + + /// @brief The maximal used width + unsigned int max_width; + + /// @brief The maximal used height + unsigned int max_height; + + /// @brief On video stream used aspect ration + /// + /// @note If aspect_ratio is <= 0.0, an aspect ratio of nominal_width / nominal_height is assumed + float aspect_ratio; + } ATTRIBUTE_PACKED game_stream_video_properties; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Video stream packet** + /// + /// This packet contains video stream data passed to Kodi. + /// + typedef struct game_stream_video_packet + { + /// @brief Video height + unsigned int width; + + /// @brief Video width + unsigned int height; + + /// @brief Width @ref GAME_VIDEO_ROTATION defined rotation angle. + GAME_VIDEO_ROTATION rotation; + + /// @brief Pointer for video stream data given to Kodi + const uint8_t* data; + + /// @brief Size of data array + size_t size; + } ATTRIBUTE_PACKED game_stream_video_packet; + //---------------------------------------------------------------------------- + + ///@} + + //--==----==----==----==----==----==----==----==----==----==----==----==----==-- + /// @defgroup cpp_kodi_addon_game_Defs_HardwareFramebuffer 3. Hardware framebuffer stream + /// @ingroup cpp_kodi_addon_game_Defs + /// @brief **Hardware framebuffer stream data** + /// + ///@{ + + //============================================================================ + /// @brief **Hardware framebuffer type** + /// + typedef enum GAME_HW_CONTEXT_TYPE + { + /// @brief None context + GAME_HW_CONTEXT_NONE, + + /// @brief OpenGL 2.x. Driver can choose to use latest compatibility context + GAME_HW_CONTEXT_OPENGL, + + /// @brief OpenGL ES 2.0 + GAME_HW_CONTEXT_OPENGLES2, + + /// @brief Modern desktop core GL context. Use major/minor fields to set GL version + GAME_HW_CONTEXT_OPENGL_CORE, + + /// @brief OpenGL ES 3.0 + GAME_HW_CONTEXT_OPENGLES3, + + /// @brief OpenGL ES 3.1+. Set major/minor fields. + GAME_HW_CONTEXT_OPENGLES_VERSION, + + /// @brief Vulkan + GAME_HW_CONTEXT_VULKAN + } GAME_HW_CONTEXT_TYPE; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Hardware framebuffer properties** + /// + typedef struct game_stream_hw_framebuffer_properties + { + /// @brief The API to use. + /// + GAME_HW_CONTEXT_TYPE context_type; + + /// @brief Set if render buffers should have depth component attached. + /// + /// @todo: Obsolete + /// + bool depth; + + /// @brief Set if stencil buffers should be attached. + /// + /// If depth and stencil are true, a packed 24/8 buffer will be added. + /// Only attaching stencil is invalid and will be ignored. + /// + /// @todo: Obsolete. + /// + bool stencil; + + /// @brief Use conventional bottom-left origin convention. + /// + /// If false, standard top-left origin semantics are used. + /// + /// @todo: Move to GL specific interface + /// + bool bottom_left_origin; + + /// @brief Major version number for core GL context or GLES 3.1+. + unsigned int version_major; + + /// @brief Minor version number for core GL context or GLES 3.1+. + unsigned int version_minor; + + /// @brief If this is true, the frontend will go very far to avoid resetting context + /// in scenarios like toggling fullscreen, etc. + /// + /// @todo: Obsolete? Maybe frontend should just always assume this... + /// + /// The reset callback might still be called in extreme situations such as if + /// the context is lost beyond recovery. + /// + /// For optimal stability, set this to false, and allow context to be reset at + /// any time. + /// + bool cache_context; + + /// @brief Creates a debug context. + bool debug_context; + } ATTRIBUTE_PACKED game_stream_hw_framebuffer_properties; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Hardware framebuffer buffer** + /// + typedef struct game_stream_hw_framebuffer_buffer + { + /// @brief + uintptr_t framebuffer; + } ATTRIBUTE_PACKED game_stream_hw_framebuffer_buffer; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Hardware framebuffer packet** + /// + typedef struct game_stream_hw_framebuffer_packet + { + /// @brief + uintptr_t framebuffer; + } ATTRIBUTE_PACKED game_stream_hw_framebuffer_packet; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Hardware framebuffer process function address** + /// + typedef void (*game_proc_address_t)(void); + //---------------------------------------------------------------------------- + + ///@} + + //--==----==----==----==----==----==----==----==----==----==----==----==----==-- + /// @defgroup cpp_kodi_addon_game_Defs_SoftwareFramebuffer 4. Software framebuffer stream + /// @ingroup cpp_kodi_addon_game_Defs + /// @brief **Software framebuffer stream data** + /// + ///@{ + + //============================================================================ + /// @brief **Game video stream properties** + /// + /// Used by Kodi to pass the currently required video stream settings to the addon + /// + typedef game_stream_video_properties game_stream_sw_framebuffer_properties; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Hardware framebuffer type** + /// + typedef struct game_stream_sw_framebuffer_buffer + { + GAME_PIXEL_FORMAT format; + uint8_t* data; + size_t size; + } ATTRIBUTE_PACKED game_stream_sw_framebuffer_buffer; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Video stream packet** + /// + /// This packet contains video stream data passed to Kodi. + /// + typedef game_stream_video_packet game_stream_sw_framebuffer_packet; + //---------------------------------------------------------------------------- + + ///@} + + //--==----==----==----==----==----==----==----==----==----==----==----==----==-- + /// @defgroup cpp_kodi_addon_game_Defs_StreamTypes 5. Stream types + /// @ingroup cpp_kodi_addon_game_Defs + /// @brief **Stream types data** + /// + ///@{ + + //============================================================================ + /// @brief **Game stream types** + /// + typedef enum GAME_STREAM_TYPE + { + /// @brief Unknown + GAME_STREAM_UNKNOWN, + + /// @brief Audio stream + GAME_STREAM_AUDIO, + + /// @brief Video stream + GAME_STREAM_VIDEO, + + /// @brief Hardware framebuffer + GAME_STREAM_HW_FRAMEBUFFER, + + /// @brief Software framebuffer + GAME_STREAM_SW_FRAMEBUFFER, + } GAME_STREAM_TYPE; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Immutable stream metadata** + /// + /// This metadata is provided when the stream is opened. If any stream + /// properties change, a new stream must be opened. + /// + typedef struct game_stream_properties + { + /// @brief + GAME_STREAM_TYPE type; + union + { + /// @brief + game_stream_audio_properties audio; + + /// @brief + game_stream_video_properties video; + + /// @brief + game_stream_hw_framebuffer_properties hw_framebuffer; + + /// @brief + game_stream_sw_framebuffer_properties sw_framebuffer; + }; + } ATTRIBUTE_PACKED game_stream_properties; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Stream buffers for hardware rendering and zero-copy support** + /// + typedef struct game_stream_buffer + { + /// @brief + GAME_STREAM_TYPE type; + union + { + /// @brief + game_stream_hw_framebuffer_buffer hw_framebuffer; + + /// @brief + game_stream_sw_framebuffer_buffer sw_framebuffer; + }; + } ATTRIBUTE_PACKED game_stream_buffer; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Stream packet and ephemeral metadata** + /// + /// This packet contains stream data and accompanying metadata. The metadata + /// is ephemeral, meaning it only applies to the current packet and can change + /// from packet to packet in the same stream. + /// + typedef struct game_stream_packet + { + /// @brief + GAME_STREAM_TYPE type; + union + { + /// @brief + game_stream_audio_packet audio; + + /// @brief + game_stream_video_packet video; + + /// @brief + game_stream_hw_framebuffer_packet hw_framebuffer; + + /// @brief + game_stream_sw_framebuffer_packet sw_framebuffer; + }; + } ATTRIBUTE_PACKED game_stream_packet; + //---------------------------------------------------------------------------- + + ///@} + + //--==----==----==----==----==----==----==----==----==----==----==----==----==-- + /// @defgroup cpp_kodi_addon_game_Defs_GameTypes 6. Game types + /// @ingroup cpp_kodi_addon_game_Defs + /// @brief **Game types data** + /// + ///@{ + + //============================================================================ + /// @brief **Game reguin definition** + /// + /// Returned from game_get_region() + typedef enum GAME_REGION + { + /// @brief Game region unknown + GAME_REGION_UNKNOWN, + + /// @brief Game region NTSC + GAME_REGION_NTSC, + + /// @brief Game region PAL + GAME_REGION_PAL, + } GAME_REGION; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Special game types passed into game_load_game_special().** + /// + /// @remark Only used when multiple ROMs are required. + /// + typedef enum SPECIAL_GAME_TYPE + { + /// @brief Game Type BSX + SPECIAL_GAME_TYPE_BSX, + + /// @brief Game Type BSX slotted + SPECIAL_GAME_TYPE_BSX_SLOTTED, + + /// @brief Game Type sufami turbo + SPECIAL_GAME_TYPE_SUFAMI_TURBO, + + /// @brief Game Type super game boy + SPECIAL_GAME_TYPE_SUPER_GAME_BOY, + } SPECIAL_GAME_TYPE; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **Game Memory** + /// + typedef enum GAME_MEMORY + { + /// @brief Passed to game_get_memory_data/size(). If the memory type doesn't apply + /// to the implementation NULL/0 can be returned. + GAME_MEMORY_MASK = 0xff, + + /// @brief Regular save ram. + /// + /// This ram is usually found on a game cartridge, backed + /// up by a battery. If save game data is too complex for a single memory + /// buffer, the SYSTEM_DIRECTORY environment callback can be used. + GAME_MEMORY_SAVE_RAM = 0, + + /// @brief Some games have a built-in clock to keep track of time. + /// + /// This memory is usually just a couple of bytes to keep track of time. + GAME_MEMORY_RTC = 1, + + /// @brief System ram lets a frontend peek into a game systems main RAM + GAME_MEMORY_SYSTEM_RAM = 2, + + /// @brief Video ram lets a frontend peek into a game systems video RAM (VRAM) + GAME_MEMORY_VIDEO_RAM = 3, + + /// @brief Special memory type + GAME_MEMORY_SNES_BSX_RAM = ((1 << 8) | GAME_MEMORY_SAVE_RAM), + + /// @brief Special memory type + GAME_MEMORY_SNES_BSX_PRAM = ((2 << 8) | GAME_MEMORY_SAVE_RAM), + + /// @brief Special memory type + GAME_MEMORY_SNES_SUFAMI_TURBO_A_RAM = ((3 << 8) | GAME_MEMORY_SAVE_RAM), + + /// @brief Special memory type + GAME_MEMORY_SNES_SUFAMI_TURBO_B_RAM = ((4 << 8) | GAME_MEMORY_SAVE_RAM), + + /// @brief Special memory type + GAME_MEMORY_SNES_GAME_BOY_RAM = ((5 << 8) | GAME_MEMORY_SAVE_RAM), + + /// @brief Special memory type + GAME_MEMORY_SNES_GAME_BOY_RTC = ((6 << 8) | GAME_MEMORY_RTC), + } GAME_MEMORY; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief **ID values for SIMD CPU features** + typedef enum GAME_SIMD + { + /// @brief SIMD CPU SSE + GAME_SIMD_SSE = (1 << 0), + + /// @brief SIMD CPU SSE2 + GAME_SIMD_SSE2 = (1 << 1), + + /// @brief SIMD CPU VMX + GAME_SIMD_VMX = (1 << 2), + + /// @brief SIMD CPU VMX128 + GAME_SIMD_VMX128 = (1 << 3), + + /// @brief SIMD CPU AVX + GAME_SIMD_AVX = (1 << 4), + + /// @brief SIMD CPU NEON + GAME_SIMD_NEON = (1 << 5), + + /// @brief SIMD CPU SSE3 + GAME_SIMD_SSE3 = (1 << 6), + + /// @brief SIMD CPU SSSE3 + GAME_SIMD_SSSE3 = (1 << 7), + + /// @brief SIMD CPU MMX + GAME_SIMD_MMX = (1 << 8), + + /// @brief SIMD CPU MMXEXT + GAME_SIMD_MMXEXT = (1 << 9), + + /// @brief SIMD CPU SSE4 + GAME_SIMD_SSE4 = (1 << 10), + + /// @brief SIMD CPU SSE42 + GAME_SIMD_SSE42 = (1 << 11), + + /// @brief SIMD CPU AVX2 + GAME_SIMD_AVX2 = (1 << 12), + + /// @brief SIMD CPU VFPU + GAME_SIMD_VFPU = (1 << 13), + } GAME_SIMD; + //---------------------------------------------------------------------------- + + ///@} + + //--==----==----==----==----==----==----==----==----==----==----==----==----==-- + /// @defgroup cpp_kodi_addon_game_Defs_InputTypes 7. Input types + /// @ingroup cpp_kodi_addon_game_Defs + /// @brief **Input types** + /// + ///@{ + + //============================================================================ + /// @brief + typedef enum GAME_INPUT_EVENT_SOURCE + { + /// @brief + GAME_INPUT_EVENT_DIGITAL_BUTTON, + + /// @brief + GAME_INPUT_EVENT_ANALOG_BUTTON, + + /// @brief + GAME_INPUT_EVENT_AXIS, + + /// @brief + GAME_INPUT_EVENT_ANALOG_STICK, + + /// @brief + GAME_INPUT_EVENT_ACCELEROMETER, + + /// @brief + GAME_INPUT_EVENT_KEY, + + /// @brief + GAME_INPUT_EVENT_RELATIVE_POINTER, + + /// @brief + GAME_INPUT_EVENT_ABSOLUTE_POINTER, + + /// @brief + GAME_INPUT_EVENT_MOTOR, + } GAME_INPUT_EVENT_SOURCE; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief + typedef enum GAME_KEY_MOD + { + /// @brief + GAME_KEY_MOD_NONE = 0x0000, + + /// @brief + GAME_KEY_MOD_SHIFT = 0x0001, + + /// @brief + GAME_KEY_MOD_CTRL = 0x0002, + + /// @brief + GAME_KEY_MOD_ALT = 0x0004, + + /// @brief + GAME_KEY_MOD_META = 0x0008, + + /// @brief + GAME_KEY_MOD_SUPER = 0x0010, + + /// @brief + GAME_KEY_MOD_NUMLOCK = 0x0100, + + /// @brief + GAME_KEY_MOD_CAPSLOCK = 0x0200, + + /// @brief + GAME_KEY_MOD_SCROLLOCK = 0x0400, + } GAME_KEY_MOD; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Type of port on the virtual game console + typedef enum GAME_PORT_TYPE + { + /// @brief Game port unknown + GAME_PORT_UNKNOWN, + + /// @brief Game port Keyboard + GAME_PORT_KEYBOARD, + + /// @brief Game port mouse + GAME_PORT_MOUSE, + + /// @brief Game port controller + GAME_PORT_CONTROLLER, + } GAME_PORT_TYPE; + //---------------------------------------------------------------------------- + + /*! @cond PRIVATE */ + /*! + * @brief "C" Game add-on controller layout. + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref AddonGameControllerLayout for description of values. + */ + typedef struct game_controller_layout + { + char* controller_id; + bool provides_input; // False for multitaps + char** digital_buttons; + unsigned int digital_button_count; + char** analog_buttons; + unsigned int analog_button_count; + char** analog_sticks; + unsigned int analog_stick_count; + char** accelerometers; + unsigned int accelerometer_count; + char** keys; + unsigned int key_count; + char** rel_pointers; + unsigned int rel_pointer_count; + char** abs_pointers; + unsigned int abs_pointer_count; + char** motors; + unsigned int motor_count; + } ATTRIBUTE_PACKED game_controller_layout; + /*! @endcond */ + + struct game_input_port; + + //============================================================================ + /// @brief Device that can provide input + typedef struct game_input_device + { + /// @brief ID used in the Kodi controller API + const char* controller_id; + + /// @brief + const char* port_address; + + /// @brief + struct game_input_port* available_ports; + + /// @brief + unsigned int port_count; + } ATTRIBUTE_PACKED game_input_device; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Port that can provide input + /// + /// Ports can accept multiple devices and devices can have multiple ports, so + /// the topology of possible configurations is a tree structure of alternating + /// port and device nodes. + /// + typedef struct game_input_port + { + /// @brief + GAME_PORT_TYPE type; + + /// @brief Required for GAME_PORT_CONTROLLER type + const char* port_id; + + /// @brief + game_input_device* accepted_devices; + + /// @brief + unsigned int device_count; + } ATTRIBUTE_PACKED game_input_port; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief The input topology is the possible ways to connect input devices + /// + /// This represents the logical topology, which is the possible connections that + /// the game client's logic can handle. It is strictly a subset of the physical + /// topology. Loops are not allowed. + /// + typedef struct game_input_topology + { + /// @brief The list of ports on the virtual game console + game_input_port* ports; + + /// @brief The number of ports + unsigned int port_count; + + /// @brief A limit on the number of input-providing devices, or -1 for no limit + int player_limit; + } ATTRIBUTE_PACKED game_input_topology; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief + typedef struct game_digital_button_event + { + /// @brief + bool pressed; + } ATTRIBUTE_PACKED game_digital_button_event; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief + typedef struct game_analog_button_event + { + /// @brief + float magnitude; + } ATTRIBUTE_PACKED game_analog_button_event; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief + typedef struct game_axis_event + { + /// @brief + float position; + } ATTRIBUTE_PACKED game_axis_event; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief + typedef struct game_analog_stick_event + { + /// @brief + float x; + + /// @brief + float y; + } ATTRIBUTE_PACKED game_analog_stick_event; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief + typedef struct game_accelerometer_event + { + /// @brief + float x; + + /// @brief + float y; + + /// @brief + float z; + } ATTRIBUTE_PACKED game_accelerometer_event; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief + typedef struct game_key_event + { + /// @brief + bool pressed; + + /// @brief If the keypress generates a printing character + /// + /// The unicode value contains the character generated. If the key is a + /// non-printing character, e.g. a function or arrow key, the unicode value + /// is zero. + uint32_t unicode; + + /// @brief + GAME_KEY_MOD modifiers; + } ATTRIBUTE_PACKED game_key_event; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief + typedef struct game_rel_pointer_event + { + /// @brief + int x; + + /// @brief + int y; + } ATTRIBUTE_PACKED game_rel_pointer_event; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief + typedef struct game_abs_pointer_event + { + /// @brief + bool pressed; + + /// @brief + float x; + + /// @brief + float y; + } ATTRIBUTE_PACKED game_abs_pointer_event; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief + typedef struct game_motor_event + { + /// @brief + float magnitude; + } ATTRIBUTE_PACKED game_motor_event; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief + typedef struct game_input_event + { + /// @brief + GAME_INPUT_EVENT_SOURCE type; + + /// @brief + const char* controller_id; + + /// @brief + GAME_PORT_TYPE port_type; + + /// @brief + const char* port_address; + + /// @brief + const char* feature_name; + union + { + /// @brief + struct game_digital_button_event digital_button; + + /// @brief + struct game_analog_button_event analog_button; + + /// @brief + struct game_axis_event axis; + + /// @brief + struct game_analog_stick_event analog_stick; + + /// @brief + struct game_accelerometer_event accelerometer; + + /// @brief + struct game_key_event key; + + /// @brief + struct game_rel_pointer_event rel_pointer; + + /// @brief + struct game_abs_pointer_event abs_pointer; + + /// @brief + struct game_motor_event motor; + }; + } ATTRIBUTE_PACKED game_input_event; + //---------------------------------------------------------------------------- + + ///@} + + //--==----==----==----==----==----==----==----==----==----==----==----==----==-- + /// @defgroup cpp_kodi_addon_game_Defs_EnvironmentTypes 8. Environment types + /// @ingroup cpp_kodi_addon_game_Defs + /// @brief **Environment types** + /// + ///@{ + + //============================================================================ + /// @brief Game system timing + /// + struct game_system_timing + { + /// @brief FPS of video content. + double fps; + + /// @brief Sampling rate of audio. + double sample_rate; + }; + //---------------------------------------------------------------------------- + + ///@} + + + //--==----==----==----==----==----==----==----==----==----==----==----==----==-- + + /*! + * @brief Game properties + * + * Not to be used outside this header. + */ + typedef struct AddonProps_Game + { + /*! + * The path of the game client being loaded. + */ + const char* game_client_dll_path; + + /*! + * Paths to proxy DLLs used to load the game client. + */ + const char** proxy_dll_paths; + + /*! + * Number of proxy DLL paths provided. + */ + unsigned int proxy_dll_count; + + /*! + * The "system" directories of the frontend. These directories can be used to + * store system-specific ROMs such as BIOSes, configuration data, etc. + */ + const char** resource_directories; + + /*! + * Number of resource directories provided + */ + unsigned int resource_directory_count; + + /*! + * The writable directory of the frontend. This directory can be used to store + * SRAM, memory cards, high scores, etc, if the game client cannot use the + * regular memory interface, GetMemoryData(). + */ + const char* profile_directory; + + /*! + * The value of the property from addon.xml + */ + bool supports_vfs; + + /*! + * The extensions in the property from addon.xml + */ + const char** extensions; + + /*! + * Number of extensions provided + */ + unsigned int extension_count; + } AddonProps_Game; + + typedef void* KODI_GAME_STREAM_HANDLE; + + /*! Structure to transfer the methods from kodi_game_dll.h to Kodi */ + + struct AddonInstance_Game; + + /*! + * @brief Game callbacks + * + * Not to be used outside this header. + */ + typedef struct AddonToKodiFuncTable_Game + { + KODI_HANDLE kodiInstance; + + void (*CloseGame)(KODI_HANDLE kodiInstance); + KODI_GAME_STREAM_HANDLE (*OpenStream)(KODI_HANDLE, const struct game_stream_properties*); + bool (*GetStreamBuffer)(KODI_HANDLE, + KODI_GAME_STREAM_HANDLE, + unsigned int, + unsigned int, + struct game_stream_buffer*); + void (*AddStreamData)(KODI_HANDLE, KODI_GAME_STREAM_HANDLE, const struct game_stream_packet*); + void (*ReleaseStreamBuffer)(KODI_HANDLE, KODI_GAME_STREAM_HANDLE, struct game_stream_buffer*); + void (*CloseStream)(KODI_HANDLE, KODI_GAME_STREAM_HANDLE); + game_proc_address_t (*HwGetProcAddress)(KODI_HANDLE kodiInstance, const char* symbol); + bool (*InputEvent)(KODI_HANDLE kodiInstance, const struct game_input_event* event); + } AddonToKodiFuncTable_Game; + + /*! + * @brief Game function hooks + * + * Not to be used outside this header. + */ + typedef struct KodiToAddonFuncTable_Game + { + KODI_HANDLE addonInstance; + + GAME_ERROR(__cdecl* LoadGame)(const struct AddonInstance_Game*, const char*); + GAME_ERROR(__cdecl* LoadGameSpecial) + (const struct AddonInstance_Game*, enum SPECIAL_GAME_TYPE, const char**, size_t); + GAME_ERROR(__cdecl* LoadStandalone)(const struct AddonInstance_Game*); + GAME_ERROR(__cdecl* UnloadGame)(const struct AddonInstance_Game*); + GAME_ERROR(__cdecl* GetGameTiming) + (const struct AddonInstance_Game*, struct game_system_timing*); + GAME_REGION(__cdecl* GetRegion)(const struct AddonInstance_Game*); + bool(__cdecl* RequiresGameLoop)(const struct AddonInstance_Game*); + GAME_ERROR(__cdecl* RunFrame)(const struct AddonInstance_Game*); + GAME_ERROR(__cdecl* Reset)(const struct AddonInstance_Game*); + GAME_ERROR(__cdecl* HwContextReset)(const struct AddonInstance_Game*); + GAME_ERROR(__cdecl* HwContextDestroy)(const struct AddonInstance_Game*); + bool(__cdecl* HasFeature)(const struct AddonInstance_Game*, const char*, const char*); + game_input_topology*(__cdecl* GetTopology)(const struct AddonInstance_Game*); + void(__cdecl* FreeTopology)(const struct AddonInstance_Game*, struct game_input_topology*); + void(__cdecl* SetControllerLayouts)(const struct AddonInstance_Game*, + const struct game_controller_layout*, + unsigned int); + bool(__cdecl* EnableKeyboard)(const struct AddonInstance_Game*, bool, const char*); + bool(__cdecl* EnableMouse)(const struct AddonInstance_Game*, bool, const char*); + bool(__cdecl* ConnectController)(const struct AddonInstance_Game*, + bool, + const char*, + const char*); + bool(__cdecl* InputEvent)(const struct AddonInstance_Game*, const struct game_input_event*); + size_t(__cdecl* SerializeSize)(const struct AddonInstance_Game*); + GAME_ERROR(__cdecl* Serialize)(const struct AddonInstance_Game*, uint8_t*, size_t); + GAME_ERROR(__cdecl* Deserialize)(const struct AddonInstance_Game*, const uint8_t*, size_t); + GAME_ERROR(__cdecl* CheatReset)(const struct AddonInstance_Game*); + GAME_ERROR(__cdecl* GetMemory) + (const struct AddonInstance_Game*, enum GAME_MEMORY, uint8_t**, size_t*); + GAME_ERROR(__cdecl* SetCheat) + (const struct AddonInstance_Game*, unsigned int, bool, const char*); + } KodiToAddonFuncTable_Game; + + /*! + * @brief Game instance + * + * Not to be used outside this header. + */ + typedef struct AddonInstance_Game + { + struct AddonProps_Game* props; + struct AddonToKodiFuncTable_Game* toKodi; + struct KodiToAddonFuncTable_Game* toAddon; + } AddonInstance_Game; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_GAME_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/image_decoder.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/image_decoder.h new file mode 100644 index 0000000..6455b38 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/image_decoder.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_IMAGE_DECODER_H +#define C_API_ADDONINSTANCE_IMAGE_DECODER_H + +#include "../addon_base.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// @ingroup cpp_kodi_addon_imagedecoder_Defs + /// @brief **Image format types**\n + /// Used to define wanted target format where image decoder should give to + /// Kodi. + /// + typedef enum ImageFormat + { + /// @brief A 32-bit ARGB pixel format, with alpha, that uses 8 bits per + /// channel, ARGBARGB... + ADDON_IMG_FMT_A8R8G8B8 = 1, + + /// @brief A 8, alpha only, 8bpp, AAA... + ADDON_IMG_FMT_A8 = 2, + + /// @brief RGBA 8:8:8:8, with alpha, 32bpp, RGBARGBA... + ADDON_IMG_FMT_RGBA8 = 3, + + /// @brief RGB 8:8:8, with alpha, 24bpp, RGBRGB... + ADDON_IMG_FMT_RGB8 = 4 + } ImageFormat; + //---------------------------------------------------------------------------- + + typedef struct AddonProps_ImageDecoder + { + const char* mimetype; + } AddonProps_ImageDecoder; + + typedef struct AddonToKodiFuncTable_ImageDecoder + { + KODI_HANDLE kodi_instance; + } AddonToKodiFuncTable_ImageDecoder; + + struct AddonInstance_ImageDecoder; + typedef struct KodiToAddonFuncTable_ImageDecoder + { + KODI_HANDLE addonInstance; + bool(__cdecl* load_image_from_memory)(const struct AddonInstance_ImageDecoder* instance, + unsigned char* buffer, + unsigned int buf_size, + unsigned int* width, + unsigned int* height); + + bool(__cdecl* decode)(const struct AddonInstance_ImageDecoder* instance, + unsigned char* pixels, + unsigned int width, + unsigned int height, + unsigned int pitch, + enum ImageFormat format); + } KodiToAddonFuncTable_ImageDecoder; + + typedef struct AddonInstance_ImageDecoder + { + struct AddonProps_ImageDecoder* props; + struct AddonToKodiFuncTable_ImageDecoder* toKodi; + struct KodiToAddonFuncTable_ImageDecoder* toAddon; + } AddonInstance_ImageDecoder; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_IMAGE_DECODER_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/peripheral.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/peripheral.h new file mode 100644 index 0000000..393f34a --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/peripheral.h @@ -0,0 +1,709 @@ +/* + * Copyright (C) 2014-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_PERIPHERAL_H +#define C_API_ADDONINSTANCE_PERIPHERAL_H + +#include "../addon_base.h" + +/* indicates a joystick has no preference for port number */ +#define NO_PORT_REQUESTED (-1) + +/* joystick's driver button/hat/axis index is unknown */ +#define DRIVER_INDEX_UNKNOWN (-1) + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_Defs_General_PERIPHERAL_ERROR enum PERIPHERAL_ERROR + /// @ingroup cpp_kodi_addon_peripheral_Defs_General + /// @brief **Peripheral add-on error codes**\n + /// Used as return values on most peripheral related functions. + /// + /// In this way, a peripheral instance signals errors in its processing and, + /// under certain conditions, allows Kodi to make corrections. + /// + ///@{ + typedef enum PERIPHERAL_ERROR + { + /// @brief __0__ : No error occurred + PERIPHERAL_NO_ERROR = 0, + + /// @brief __-1__ : An unknown error occurred + PERIPHERAL_ERROR_UNKNOWN = -1, + + /// @brief __-2__ : The command failed + PERIPHERAL_ERROR_FAILED = -2, + + /// @brief __-3__ : The parameters of the method are invalid for this operation + PERIPHERAL_ERROR_INVALID_PARAMETERS = -3, + + /// @brief __-4__ : The method that the frontend called is not implemented + PERIPHERAL_ERROR_NOT_IMPLEMENTED = -4, + + /// @brief __-5__ : No peripherals are connected + PERIPHERAL_ERROR_NOT_CONNECTED = -5, + + /// @brief __-6__ : Peripherals are connected, but command was interrupted + PERIPHERAL_ERROR_CONNECTION_FAILED = -6, + } PERIPHERAL_ERROR; + ///@} + //---------------------------------------------------------------------------- + + // @name Peripheral types + //{ + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_Defs_Peripheral_PERIPHERAL_TYPE enum PERIPHERAL_TYPE + /// @ingroup cpp_kodi_addon_peripheral_Defs_Peripheral + /// @brief **Peripheral types**\n + /// Types used to identify wanted peripheral. + ///@{ + typedef enum PERIPHERAL_TYPE + { + /// @brief Type declared as unknown. + PERIPHERAL_TYPE_UNKNOWN, + + /// @brief Type declared as joystick. + PERIPHERAL_TYPE_JOYSTICK, + + /// @brief Type declared as keyboard. + PERIPHERAL_TYPE_KEYBOARD, + } PERIPHERAL_TYPE; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief Information shared between peripherals + */ + typedef struct PERIPHERAL_INFO + { + PERIPHERAL_TYPE type; /*!< type of peripheral */ + char* name; /*!< name of peripheral */ + uint16_t vendor_id; /*!< vendor ID of peripheral, 0x0000 if unknown */ + uint16_t product_id; /*!< product ID of peripheral, 0x0000 if unknown */ + unsigned int index; /*!< the order in which the add-on identified this peripheral */ + } ATTRIBUTE_PACKED PERIPHERAL_INFO; + + /*! + * @brief Peripheral add-on capabilities. + */ + typedef struct PERIPHERAL_CAPABILITIES + { + bool provides_joysticks; /*!< true if the add-on provides joysticks */ + bool provides_joystick_rumble; + bool provides_joystick_power_off; + bool provides_buttonmaps; /*!< true if the add-on provides button maps */ + } ATTRIBUTE_PACKED PERIPHERAL_CAPABILITIES; + + //} + + // @name Event types + //{ + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_Defs_Event_PERIPHERAL_EVENT_TYPE enum PERIPHERAL_EVENT_TYPE + /// @ingroup cpp_kodi_addon_peripheral_Defs_Event + /// @brief **Event types**\n + /// Types of events that can be sent and received. + ///@{ + typedef enum PERIPHERAL_EVENT_TYPE + { + /// @brief unknown event + PERIPHERAL_EVENT_TYPE_NONE, + + /// @brief state changed for joystick driver button + PERIPHERAL_EVENT_TYPE_DRIVER_BUTTON, + + /// @brief state changed for joystick driver hat + PERIPHERAL_EVENT_TYPE_DRIVER_HAT, + + /// @brief state changed for joystick driver axis + PERIPHERAL_EVENT_TYPE_DRIVER_AXIS, + + /// @brief set the state for joystick rumble motor + PERIPHERAL_EVENT_TYPE_SET_MOTOR, + } PERIPHERAL_EVENT_TYPE; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_Defs_Event_JOYSTICK_STATE_BUTTON enum JOYSTICK_STATE_BUTTON + /// @ingroup cpp_kodi_addon_peripheral_Defs_Event + /// @brief **State button**\n + /// States a button can have + ///@{ + typedef enum JOYSTICK_STATE_BUTTON + { + /// @brief button is released + JOYSTICK_STATE_BUTTON_UNPRESSED = 0x0, + + /// @brief button is pressed + JOYSTICK_STATE_BUTTON_PRESSED = 0x1, + } JOYSTICK_STATE_BUTTON; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_Defs_Event_JOYSTICK_STATE_HAT enum JOYSTICK_STATE_HAT + /// @ingroup cpp_kodi_addon_peripheral_Defs_Event + /// @brief **State hat**\n + /// States a D-pad (also called a hat) can have + ///@{ + typedef enum JOYSTICK_STATE_HAT + { + /// @brief no directions are pressed + JOYSTICK_STATE_HAT_UNPRESSED = 0x0, + + /// @brief only left is pressed + JOYSTICK_STATE_HAT_LEFT = 0x1, + + /// @brief only right is pressed + JOYSTICK_STATE_HAT_RIGHT = 0x2, + + /// @brief only up is pressed + JOYSTICK_STATE_HAT_UP = 0x4, + + /// @brief only down is pressed + JOYSTICK_STATE_HAT_DOWN = 0x8, + + /// @brief left and up is pressed + JOYSTICK_STATE_HAT_LEFT_UP = JOYSTICK_STATE_HAT_LEFT | JOYSTICK_STATE_HAT_UP, + + /// @brief left and down is pressed + JOYSTICK_STATE_HAT_LEFT_DOWN = JOYSTICK_STATE_HAT_LEFT | JOYSTICK_STATE_HAT_DOWN, + + /// @brief right and up is pressed + JOYSTICK_STATE_HAT_RIGHT_UP = JOYSTICK_STATE_HAT_RIGHT | JOYSTICK_STATE_HAT_UP, + + /// @brief right and down is pressed + JOYSTICK_STATE_HAT_RIGHT_DOWN = JOYSTICK_STATE_HAT_RIGHT | JOYSTICK_STATE_HAT_DOWN, + } JOYSTICK_STATE_HAT; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_peripheral_Defs_Event + /// @brief Axis value in the closed interval [-1.0, 1.0] + /// + /// The axis state uses the XInput coordinate system: + /// - Negative values signify down or to the left + /// - Positive values signify up or to the right + /// + typedef float JOYSTICK_STATE_AXIS; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_peripheral_Defs_Event + /// @brief Motor value in the closed interval [0.0, 1.0] + typedef float JOYSTICK_STATE_MOTOR; + //---------------------------------------------------------------------------- + + /*! + * @brief Event information + */ + typedef struct PERIPHERAL_EVENT + { + /*! @brief Index of the peripheral handling/receiving the event */ + unsigned int peripheral_index; + + /*! @brief Type of the event used to determine which enum field to access below */ + PERIPHERAL_EVENT_TYPE type; + + /*! @brief The index of the event source */ + unsigned int driver_index; + + JOYSTICK_STATE_BUTTON driver_button_state; + JOYSTICK_STATE_HAT driver_hat_state; + JOYSTICK_STATE_AXIS driver_axis_state; + JOYSTICK_STATE_MOTOR motor_state; + } ATTRIBUTE_PACKED PERIPHERAL_EVENT; + + //} + + // @name Joystick types + //{ + + /*! + * @brief Info specific to joystick peripherals + */ + typedef struct JOYSTICK_INFO + { + PERIPHERAL_INFO peripheral; /*!< @brief peripheral info for this joystick */ + char* provider; /*!< @brief name of the driver or interface providing the joystick */ + int requested_port; /*!< @brief requested port number (such as for 360 controllers), or NO_PORT_REQUESTED */ + unsigned int button_count; /*!< @brief number of buttons reported by the driver */ + unsigned int hat_count; /*!< @brief number of hats reported by the driver */ + unsigned int axis_count; /*!< @brief number of axes reported by the driver */ + unsigned int motor_count; /*!< @brief number of motors reported by the driver */ + bool supports_poweroff; /*!< @brief whether the joystick supports being powered off */ + } ATTRIBUTE_PACKED JOYSTICK_INFO; + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_Defs_Joystick_JOYSTICK_DRIVER_PRIMITIVE_TYPE enum JOYSTICK_DRIVER_PRIMITIVE_TYPE + /// @ingroup cpp_kodi_addon_peripheral_Defs_Joystick + /// @brief **Driver primitive type**\n + /// Driver input primitives + /// + /// Mapping lower-level driver values to higher-level controller features is + /// non-injective; two triggers can share a single axis. + /// + /// To handle this, driver values are subdivided into "primitives" that map + /// injectively to higher-level features. + /// + ///@{ + typedef enum JOYSTICK_DRIVER_PRIMITIVE_TYPE + { + /// @brief Driver input primitive type unknown + JOYSTICK_DRIVER_PRIMITIVE_TYPE_UNKNOWN, + + /// @brief Driver input primitive type button + JOYSTICK_DRIVER_PRIMITIVE_TYPE_BUTTON, + + /// @brief Driver input primitive type hat direction + JOYSTICK_DRIVER_PRIMITIVE_TYPE_HAT_DIRECTION, + + /// @brief Driver input primitive type semiaxis + JOYSTICK_DRIVER_PRIMITIVE_TYPE_SEMIAXIS, + + /// @brief Driver input primitive type motor + JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOTOR, + + /// @brief Driver input primitive type key + JOYSTICK_DRIVER_PRIMITIVE_TYPE_KEY, + + /// @brief Driver input primitive type mouse button + JOYSTICK_DRIVER_PRIMITIVE_TYPE_MOUSE_BUTTON, + + /// @brief Driver input primitive type relative pointer direction + JOYSTICK_DRIVER_PRIMITIVE_TYPE_RELPOINTER_DIRECTION, + } JOYSTICK_DRIVER_PRIMITIVE_TYPE; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief Button primitive + */ + typedef struct JOYSTICK_DRIVER_BUTTON + { + int index; + } ATTRIBUTE_PACKED JOYSTICK_DRIVER_BUTTON; + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_Defs_Joystick_JOYSTICK_DRIVER_HAT_DIRECTION enum JOYSTICK_DRIVER_HAT_DIRECTION + /// @ingroup cpp_kodi_addon_peripheral_Defs_Joystick + /// @brief **Driver direction**\n + /// Hat direction. + ///@{ + typedef enum JOYSTICK_DRIVER_HAT_DIRECTION + { + /// @brief Driver hat unknown + JOYSTICK_DRIVER_HAT_UNKNOWN, + + /// @brief Driver hat left + JOYSTICK_DRIVER_HAT_LEFT, + + /// @brief Driver hat right + JOYSTICK_DRIVER_HAT_RIGHT, + + /// @brief Driver hat up + JOYSTICK_DRIVER_HAT_UP, + + /// @brief Driver hat down + JOYSTICK_DRIVER_HAT_DOWN, + } JOYSTICK_DRIVER_HAT_DIRECTION; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief Hat direction primitive + */ + typedef struct JOYSTICK_DRIVER_HAT + { + int index; + JOYSTICK_DRIVER_HAT_DIRECTION direction; + } ATTRIBUTE_PACKED JOYSTICK_DRIVER_HAT; + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_Defs_Joystick_JOYSTICK_DRIVER_SEMIAXIS_DIRECTION enum JOYSTICK_DRIVER_SEMIAXIS_DIRECTION + /// @ingroup cpp_kodi_addon_peripheral_Defs_Joystick + /// @brief **Driver direction**\n + /// Semiaxis direction. + ///@{ + typedef enum JOYSTICK_DRIVER_SEMIAXIS_DIRECTION + { + /// @brief negative half of the axis + JOYSTICK_DRIVER_SEMIAXIS_NEGATIVE = -1, + + /// @brief unknown direction + JOYSTICK_DRIVER_SEMIAXIS_UNKNOWN = 0, + + /// @brief positive half of the axis + JOYSTICK_DRIVER_SEMIAXIS_POSITIVE = 1, + } JOYSTICK_DRIVER_SEMIAXIS_DIRECTION; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief Semiaxis primitive + */ + typedef struct JOYSTICK_DRIVER_SEMIAXIS + { + int index; + int center; + JOYSTICK_DRIVER_SEMIAXIS_DIRECTION direction; + unsigned int range; + } ATTRIBUTE_PACKED JOYSTICK_DRIVER_SEMIAXIS; + + /*! + * @brief Motor primitive + */ + typedef struct JOYSTICK_DRIVER_MOTOR + { + int index; + } ATTRIBUTE_PACKED JOYSTICK_DRIVER_MOTOR; + + /*! + * @brief Keyboard key primitive + */ + typedef struct JOYSTICK_DRIVER_KEY + { + char keycode[16]; + } ATTRIBUTE_PACKED JOYSTICK_DRIVER_KEY; + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_Defs_Joystick_JOYSTICK_DRIVER_MOUSE_INDEX enum JOYSTICK_DRIVER_MOUSE_INDEX + /// @ingroup cpp_kodi_addon_peripheral_Defs_Joystick + /// @brief **Buttons**\n + /// Mouse buttons. + ///@{ + typedef enum JOYSTICK_DRIVER_MOUSE_INDEX + { + /// @brief Mouse index unknown + JOYSTICK_DRIVER_MOUSE_INDEX_UNKNOWN, + + /// @brief Mouse index left + JOYSTICK_DRIVER_MOUSE_INDEX_LEFT, + + /// @brief Mouse index right + JOYSTICK_DRIVER_MOUSE_INDEX_RIGHT, + + /// @brief Mouse index middle + JOYSTICK_DRIVER_MOUSE_INDEX_MIDDLE, + + /// @brief Mouse index button 4 + JOYSTICK_DRIVER_MOUSE_INDEX_BUTTON4, + + /// @brief Mouse index button 5 + JOYSTICK_DRIVER_MOUSE_INDEX_BUTTON5, + + /// @brief Mouse index wheel up + JOYSTICK_DRIVER_MOUSE_INDEX_WHEEL_UP, + + /// @brief Mouse index wheel down + JOYSTICK_DRIVER_MOUSE_INDEX_WHEEL_DOWN, + + /// @brief Mouse index horizontal wheel left + JOYSTICK_DRIVER_MOUSE_INDEX_HORIZ_WHEEL_LEFT, + + /// @brief Mouse index horizontal wheel right + JOYSTICK_DRIVER_MOUSE_INDEX_HORIZ_WHEEL_RIGHT, + } JOYSTICK_DRIVER_MOUSE_INDEX; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief Mouse button primitive + */ + typedef struct JOYSTICK_DRIVER_MOUSE_BUTTON + { + JOYSTICK_DRIVER_MOUSE_INDEX button; + } ATTRIBUTE_PACKED JOYSTICK_DRIVER_MOUSE_BUTTON; + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_Defs_Joystick_JOYSTICK_DRIVER_RELPOINTER_DIRECTION enum JOYSTICK_DRIVER_RELPOINTER_DIRECTION + /// @ingroup cpp_kodi_addon_peripheral_Defs_Joystick + /// @brief **Pointer direction**\n + /// Relative pointer direction + ///@{ + typedef enum JOYSTICK_DRIVER_RELPOINTER_DIRECTION + { + /// @brief Relative pointer direction unknown + JOYSTICK_DRIVER_RELPOINTER_UNKNOWN, + + /// @brief Relative pointer direction left + JOYSTICK_DRIVER_RELPOINTER_LEFT, + + /// @brief Relative pointer direction right + JOYSTICK_DRIVER_RELPOINTER_RIGHT, + + /// @brief Relative pointer direction up + JOYSTICK_DRIVER_RELPOINTER_UP, + + /// @brief Relative pointer direction down + JOYSTICK_DRIVER_RELPOINTER_DOWN, + } JOYSTICK_DRIVER_RELPOINTER_DIRECTION; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief Relative pointer direction primitive + */ + typedef struct JOYSTICK_DRIVER_RELPOINTER + { + JOYSTICK_DRIVER_RELPOINTER_DIRECTION direction; + } ATTRIBUTE_PACKED JOYSTICK_DRIVER_RELPOINTER; + + /*! + * @brief Driver primitive struct + */ + typedef struct JOYSTICK_DRIVER_PRIMITIVE + { + JOYSTICK_DRIVER_PRIMITIVE_TYPE type; + union + { + struct JOYSTICK_DRIVER_BUTTON button; + struct JOYSTICK_DRIVER_HAT hat; + struct JOYSTICK_DRIVER_SEMIAXIS semiaxis; + struct JOYSTICK_DRIVER_MOTOR motor; + struct JOYSTICK_DRIVER_KEY key; + struct JOYSTICK_DRIVER_MOUSE_BUTTON mouse; + struct JOYSTICK_DRIVER_RELPOINTER relpointer; + }; + } ATTRIBUTE_PACKED JOYSTICK_DRIVER_PRIMITIVE; + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_Defs_Joystick_JOYSTICK_FEATURE_TYPE enum JOYSTICK_FEATURE_TYPE + /// @ingroup cpp_kodi_addon_peripheral_Defs_Joystick + /// @brief **Feature type**\n + /// Controller feature. + /// + /// Controller features are an abstraction over driver values. Each feature + /// maps to one or more driver primitives. + /// + ///@{ + typedef enum JOYSTICK_FEATURE_TYPE + { + /// @brief Unknown type + JOYSTICK_FEATURE_TYPE_UNKNOWN, + + /// @brief Type scalar + JOYSTICK_FEATURE_TYPE_SCALAR, + + /// @brief Type analog stick + JOYSTICK_FEATURE_TYPE_ANALOG_STICK, + + /// @brief Type accelerometer + JOYSTICK_FEATURE_TYPE_ACCELEROMETER, + + /// @brief Type motor + JOYSTICK_FEATURE_TYPE_MOTOR, + + /// @brief Type relative pointer + JOYSTICK_FEATURE_TYPE_RELPOINTER, + + /// @brief Type absolut pointer + JOYSTICK_FEATURE_TYPE_ABSPOINTER, + + /// @brief Type wheel + JOYSTICK_FEATURE_TYPE_WHEEL, + + /// @brief Type throttle + JOYSTICK_FEATURE_TYPE_THROTTLE, + + /// @brief Type key + JOYSTICK_FEATURE_TYPE_KEY, + } JOYSTICK_FEATURE_TYPE; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_peripheral_Defs_Joystick_JOYSTICK_FEATURE_PRIMITIVE enum JOYSTICK_FEATURE_PRIMITIVE + /// @ingroup cpp_kodi_addon_peripheral_Defs_Joystick + /// @brief **Feature primitives**\n + /// Indices used to access a feature's driver primitives. + /// + ///@{ + typedef enum JOYSTICK_FEATURE_PRIMITIVE + { + /// @brief Scalar feature (a button, hat direction or semiaxis) + JOYSTICK_SCALAR_PRIMITIVE = 0, + + /// @brief Analog stick up + JOYSTICK_ANALOG_STICK_UP = 0, + /// @brief Analog stick down + JOYSTICK_ANALOG_STICK_DOWN = 1, + /// @brief Analog stick right + JOYSTICK_ANALOG_STICK_RIGHT = 2, + /// @brief Analog stick left + JOYSTICK_ANALOG_STICK_LEFT = 3, + + /// @brief Accelerometer X + JOYSTICK_ACCELEROMETER_POSITIVE_X = 0, + /// @brief Accelerometer Y + JOYSTICK_ACCELEROMETER_POSITIVE_Y = 1, + /// @brief Accelerometer Z + JOYSTICK_ACCELEROMETER_POSITIVE_Z = 2, + + /// @brief Motor + JOYSTICK_MOTOR_PRIMITIVE = 0, + + /// @brief Wheel left + JOYSTICK_WHEEL_LEFT = 0, + /// @brief Wheel right + JOYSTICK_WHEEL_RIGHT = 1, + + /// @brief Throttle up + JOYSTICK_THROTTLE_UP = 0, + /// @brief Throttle down + JOYSTICK_THROTTLE_DOWN = 1, + + /// @brief Key + JOYSTICK_KEY_PRIMITIVE = 0, + + /// @brief Mouse button + JOYSTICK_MOUSE_BUTTON = 0, + + /// @brief Relative pointer direction up + JOYSTICK_RELPOINTER_UP = 0, + /// @brief Relative pointer direction down + JOYSTICK_RELPOINTER_DOWN = 1, + /// @brief Relative pointer direction right + JOYSTICK_RELPOINTER_RIGHT = 2, + /// @brief Relative pointer direction left + JOYSTICK_RELPOINTER_LEFT = 3, + + /// @brief Maximum number of primitives + JOYSTICK_PRIMITIVE_MAX = 4, + } JOYSTICK_FEATURE_PRIMITIVE; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief Mapping between higher-level controller feature and its driver primitives + */ + typedef struct JOYSTICK_FEATURE + { + char* name; + JOYSTICK_FEATURE_TYPE type; + struct JOYSTICK_DRIVER_PRIMITIVE primitives[JOYSTICK_PRIMITIVE_MAX]; + } ATTRIBUTE_PACKED JOYSTICK_FEATURE; + //} + + typedef struct AddonProps_Peripheral + { + const char* user_path; /*!< @brief path to the user profile */ + const char* addon_path; /*!< @brief path to this add-on */ + } ATTRIBUTE_PACKED AddonProps_Peripheral; + + struct AddonInstance_Peripheral; + + typedef struct AddonToKodiFuncTable_Peripheral + { + KODI_HANDLE kodiInstance; + void (*trigger_scan)(void* kodiInstance); + void (*refresh_button_maps)(void* kodiInstance, + const char* device_name, + const char* controller_id); + unsigned int (*feature_count)(void* kodiInstance, + const char* controller_id, + JOYSTICK_FEATURE_TYPE type); + JOYSTICK_FEATURE_TYPE(*feature_type) + (void* kodiInstance, const char* controller_id, const char* feature_name); + } AddonToKodiFuncTable_Peripheral; + + //! @todo Mouse, light gun, multitouch + + typedef struct KodiToAddonFuncTable_Peripheral + { + KODI_HANDLE addonInstance; + + void(__cdecl* get_capabilities)(const struct AddonInstance_Peripheral* addonInstance, + struct PERIPHERAL_CAPABILITIES* capabilities); + PERIPHERAL_ERROR(__cdecl* perform_device_scan) + (const struct AddonInstance_Peripheral* addonInstance, + unsigned int* peripheral_count, + struct PERIPHERAL_INFO** scan_results); + void(__cdecl* free_scan_results)(const struct AddonInstance_Peripheral* addonInstance, + unsigned int peripheral_count, + struct PERIPHERAL_INFO* scan_results); + PERIPHERAL_ERROR(__cdecl* get_events) + (const struct AddonInstance_Peripheral* addonInstance, + unsigned int* event_count, + struct PERIPHERAL_EVENT** events); + void(__cdecl* free_events)(const struct AddonInstance_Peripheral* addonInstance, + unsigned int event_count, + struct PERIPHERAL_EVENT* events); + bool(__cdecl* send_event)(const struct AddonInstance_Peripheral* addonInstance, + const struct PERIPHERAL_EVENT* event); + + /// @name Joystick operations + ///{ + PERIPHERAL_ERROR(__cdecl* get_joystick_info) + (const struct AddonInstance_Peripheral* addonInstance, + unsigned int index, + struct JOYSTICK_INFO* info); + void(__cdecl* free_joystick_info)(const struct AddonInstance_Peripheral* addonInstance, + struct JOYSTICK_INFO* info); + PERIPHERAL_ERROR(__cdecl* get_features) + (const struct AddonInstance_Peripheral* addonInstance, + const struct JOYSTICK_INFO* joystick, + const char* controller_id, + unsigned int* feature_count, + struct JOYSTICK_FEATURE** features); + void(__cdecl* free_features)(const struct AddonInstance_Peripheral* addonInstance, + unsigned int feature_count, + struct JOYSTICK_FEATURE* features); + PERIPHERAL_ERROR(__cdecl* map_features) + (const struct AddonInstance_Peripheral* addonInstance, + const struct JOYSTICK_INFO* joystick, + const char* controller_id, + unsigned int feature_count, + const struct JOYSTICK_FEATURE* features); + PERIPHERAL_ERROR(__cdecl* get_ignored_primitives) + (const struct AddonInstance_Peripheral* addonInstance, + const struct JOYSTICK_INFO* joystick, + unsigned int* feature_count, + struct JOYSTICK_DRIVER_PRIMITIVE** primitives); + void(__cdecl* free_primitives)(const struct AddonInstance_Peripheral* addonInstance, + unsigned int, + struct JOYSTICK_DRIVER_PRIMITIVE* primitives); + PERIPHERAL_ERROR(__cdecl* set_ignored_primitives) + (const struct AddonInstance_Peripheral* addonInstance, + const struct JOYSTICK_INFO* joystick, + unsigned int primitive_count, + const struct JOYSTICK_DRIVER_PRIMITIVE* primitives); + void(__cdecl* save_button_map)(const struct AddonInstance_Peripheral* addonInstance, + const struct JOYSTICK_INFO* joystick); + void(__cdecl* revert_button_map)(const struct AddonInstance_Peripheral* addonInstance, + const struct JOYSTICK_INFO* joystick); + void(__cdecl* reset_button_map)(const struct AddonInstance_Peripheral* addonInstance, + const struct JOYSTICK_INFO* joystick, + const char* controller_id); + void(__cdecl* power_off_joystick)(const struct AddonInstance_Peripheral* addonInstance, + unsigned int index); + ///} + } KodiToAddonFuncTable_Peripheral; + + typedef struct AddonInstance_Peripheral + { + struct AddonProps_Peripheral* props; + struct AddonToKodiFuncTable_Peripheral* toKodi; + struct KodiToAddonFuncTable_Peripheral* toAddon; + } AddonInstance_Peripheral; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_PERIPHERAL_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr.h new file mode 100644 index 0000000..a50ea2b --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr.h @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_PVR_H +#define C_API_ADDONINSTANCE_PVR_H + +#include "../../AddonBase.h" +#include "pvr/pvr_channel_groups.h" +#include "pvr/pvr_channels.h" +#include "pvr/pvr_defines.h" +#include "pvr/pvr_edl.h" +#include "pvr/pvr_epg.h" +#include "pvr/pvr_general.h" +#include "pvr/pvr_menu_hook.h" +#include "pvr/pvr_recordings.h" +#include "pvr/pvr_stream.h" +#include "pvr/pvr_timers.h" + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C" main interface function tables between Kodi and addon +// +// Values related to all parts and not used direct on addon, are to define here. +// +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + /*! + * @internal + * @brief PVR "C" basis API interface + * + * This field contains things that are exchanged between Kodi and Addon + * and is the basis of the PVR-side "C" API. + * + * @warning Care should be taken when making changes in this fields!\n + * Changes can destroy API in addons that have already been created. If a + * necessary change or new feature is added, the version of the PVR + * at @ref ADDON_INSTANCE_VERSION_PVR_MIN must be increased too.\n + * \n + * Conditional changes can be made in some places, without min PVR version + * increase. The add-on should then use CreateInstanceEx and add partial tests + * for this in the C++ header. + * + * Have by add of new parts a look about **Doxygen** `\\ingroup`, so that + * added parts included in documentation. + * + * If you add addon side related documentation, where his dev need know, + * use `///`. For parts only for Kodi make it like here. + * + * @endinternal + */ + + struct AddonInstance_PVR; + + /*! + * @brief Structure to define typical standard values + */ + typedef struct AddonProperties_PVR + { + const char* strUserPath; + const char* strClientPath; + int iEpgMaxDays; + } AddonProperties_PVR; + + /*! + * @brief Structure to transfer the methods from Kodi to addon + */ + typedef struct AddonToKodiFuncTable_PVR + { + // Pointer inside Kodi where used from him to find his class + KODI_HANDLE kodiInstance; + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // General callback functions + void (*AddMenuHook)(void* kodiInstance, const struct PVR_MENUHOOK* hook); + void (*RecordingNotification)(void* kodiInstance, + const char* name, + const char* fileName, + bool on); + void (*ConnectionStateChange)(void* kodiInstance, + const char* strConnectionString, + enum PVR_CONNECTION_STATE newState, + const char* strMessage); + void (*EpgEventStateChange)(void* kodiInstance, + struct EPG_TAG* tag, + enum EPG_EVENT_STATE newState); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // Transfer functions where give data back to Kodi, e.g. GetChannels calls TransferChannelEntry + void (*TransferChannelEntry)(void* kodiInstance, + const ADDON_HANDLE handle, + const struct PVR_CHANNEL* chan); + void (*TransferChannelGroup)(void* kodiInstance, + const ADDON_HANDLE handle, + const struct PVR_CHANNEL_GROUP* group); + void (*TransferChannelGroupMember)(void* kodiInstance, + const ADDON_HANDLE handle, + const struct PVR_CHANNEL_GROUP_MEMBER* member); + void (*TransferEpgEntry)(void* kodiInstance, + const ADDON_HANDLE handle, + const struct EPG_TAG* epgentry); + void (*TransferRecordingEntry)(void* kodiInstance, + const ADDON_HANDLE handle, + const struct PVR_RECORDING* recording); + void (*TransferTimerEntry)(void* kodiInstance, + const ADDON_HANDLE handle, + const struct PVR_TIMER* timer); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // Kodi inform interface functions + void (*TriggerChannelUpdate)(void* kodiInstance); + void (*TriggerChannelGroupsUpdate)(void* kodiInstance); + void (*TriggerEpgUpdate)(void* kodiInstance, unsigned int iChannelUid); + void (*TriggerRecordingUpdate)(void* kodiInstance); + void (*TriggerTimerUpdate)(void* kodiInstance); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // Stream demux interface functions + void (*FreeDemuxPacket)(void* kodiInstance, struct DemuxPacket* pPacket); + struct DemuxPacket* (*AllocateDemuxPacket)(void* kodiInstance, int iDataSize); + struct PVR_CODEC (*GetCodecByName)(const void* kodiInstance, const char* strCodecName); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // New functions becomes added below and can be on another API change (where + // breaks min API version) moved up. + } AddonToKodiFuncTable_PVR; + + /*! + * @brief Structure to transfer the methods from addon to Kodi + */ + typedef struct KodiToAddonFuncTable_PVR + { + // Pointer inside addon where used on them to find his instance class (currently unused!) + KODI_HANDLE addonInstance; + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // General interface functions + enum PVR_ERROR(__cdecl* GetCapabilities)(const struct AddonInstance_PVR*, + struct PVR_ADDON_CAPABILITIES*); + enum PVR_ERROR(__cdecl* GetBackendName)(const struct AddonInstance_PVR*, char*, int); + enum PVR_ERROR(__cdecl* GetBackendVersion)(const struct AddonInstance_PVR*, char*, int); + enum PVR_ERROR(__cdecl* GetBackendHostname)(const struct AddonInstance_PVR*, char*, int); + enum PVR_ERROR(__cdecl* GetConnectionString)(const struct AddonInstance_PVR*, char*, int); + enum PVR_ERROR(__cdecl* GetDriveSpace)(const struct AddonInstance_PVR*, uint64_t*, uint64_t*); + enum PVR_ERROR(__cdecl* CallSettingsMenuHook)(const struct AddonInstance_PVR*, + const struct PVR_MENUHOOK*); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // Channel interface functions + + enum PVR_ERROR(__cdecl* GetChannelsAmount)(const struct AddonInstance_PVR*, int*); + enum PVR_ERROR(__cdecl* GetChannels)(const struct AddonInstance_PVR*, ADDON_HANDLE, bool); + enum PVR_ERROR(__cdecl* GetChannelStreamProperties)(const struct AddonInstance_PVR*, + const struct PVR_CHANNEL*, + struct PVR_NAMED_VALUE*, + unsigned int*); + enum PVR_ERROR(__cdecl* GetSignalStatus)(const struct AddonInstance_PVR*, + int, + struct PVR_SIGNAL_STATUS*); + enum PVR_ERROR(__cdecl* GetDescrambleInfo)(const struct AddonInstance_PVR*, + int, + struct PVR_DESCRAMBLE_INFO*); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // Channel group interface functions + enum PVR_ERROR(__cdecl* GetChannelGroupsAmount)(const struct AddonInstance_PVR*, int*); + enum PVR_ERROR(__cdecl* GetChannelGroups)(const struct AddonInstance_PVR*, ADDON_HANDLE, bool); + enum PVR_ERROR(__cdecl* GetChannelGroupMembers)(const struct AddonInstance_PVR*, + ADDON_HANDLE, + const struct PVR_CHANNEL_GROUP*); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // Channel edit interface functions + enum PVR_ERROR(__cdecl* DeleteChannel)(const struct AddonInstance_PVR*, + const struct PVR_CHANNEL*); + enum PVR_ERROR(__cdecl* RenameChannel)(const struct AddonInstance_PVR*, + const struct PVR_CHANNEL*); + enum PVR_ERROR(__cdecl* OpenDialogChannelSettings)(const struct AddonInstance_PVR*, + const struct PVR_CHANNEL*); + enum PVR_ERROR(__cdecl* OpenDialogChannelAdd)(const struct AddonInstance_PVR*, + const struct PVR_CHANNEL*); + enum PVR_ERROR(__cdecl* OpenDialogChannelScan)(const struct AddonInstance_PVR*); + enum PVR_ERROR(__cdecl* CallChannelMenuHook)(const struct AddonInstance_PVR*, + const PVR_MENUHOOK*, + const PVR_CHANNEL*); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // EPG interface functions + enum PVR_ERROR(__cdecl* GetEPGForChannel)( + const struct AddonInstance_PVR*, ADDON_HANDLE, int, time_t, time_t); + enum PVR_ERROR(__cdecl* IsEPGTagRecordable)(const struct AddonInstance_PVR*, + const struct EPG_TAG*, + bool*); + enum PVR_ERROR(__cdecl* IsEPGTagPlayable)(const struct AddonInstance_PVR*, + const struct EPG_TAG*, + bool*); + enum PVR_ERROR(__cdecl* GetEPGTagEdl)(const struct AddonInstance_PVR*, + const struct EPG_TAG*, + struct PVR_EDL_ENTRY[], + int*); + enum PVR_ERROR(__cdecl* GetEPGTagStreamProperties)(const struct AddonInstance_PVR*, + const struct EPG_TAG*, + struct PVR_NAMED_VALUE*, + unsigned int*); + enum PVR_ERROR(__cdecl* SetEPGTimeFrame)(const struct AddonInstance_PVR*, int); + enum PVR_ERROR(__cdecl* CallEPGMenuHook)(const struct AddonInstance_PVR*, + const struct PVR_MENUHOOK*, + const struct EPG_TAG*); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // Recording interface functions + enum PVR_ERROR(__cdecl* GetRecordingsAmount)(const struct AddonInstance_PVR*, bool, int*); + enum PVR_ERROR(__cdecl* GetRecordings)(const struct AddonInstance_PVR*, ADDON_HANDLE, bool); + enum PVR_ERROR(__cdecl* DeleteRecording)(const struct AddonInstance_PVR*, + const struct PVR_RECORDING*); + enum PVR_ERROR(__cdecl* UndeleteRecording)(const struct AddonInstance_PVR*, + const struct PVR_RECORDING*); + enum PVR_ERROR(__cdecl* DeleteAllRecordingsFromTrash)(const struct AddonInstance_PVR*); + enum PVR_ERROR(__cdecl* RenameRecording)(const struct AddonInstance_PVR*, + const struct PVR_RECORDING*); + enum PVR_ERROR(__cdecl* SetRecordingLifetime)(const struct AddonInstance_PVR*, + const struct PVR_RECORDING*); + enum PVR_ERROR(__cdecl* SetRecordingPlayCount)(const struct AddonInstance_PVR*, + const struct PVR_RECORDING*, + int); + enum PVR_ERROR(__cdecl* SetRecordingLastPlayedPosition)(const struct AddonInstance_PVR*, + const struct PVR_RECORDING*, + int); + enum PVR_ERROR(__cdecl* GetRecordingLastPlayedPosition)(const struct AddonInstance_PVR*, + const struct PVR_RECORDING*, + int*); + enum PVR_ERROR(__cdecl* GetRecordingEdl)(const struct AddonInstance_PVR*, + const struct PVR_RECORDING*, + struct PVR_EDL_ENTRY[], + int*); + enum PVR_ERROR(__cdecl* GetRecordingSize)(const struct AddonInstance_PVR*, + const PVR_RECORDING*, + int64_t*); + enum PVR_ERROR(__cdecl* GetRecordingStreamProperties)(const struct AddonInstance_PVR*, + const struct PVR_RECORDING*, + struct PVR_NAMED_VALUE*, + unsigned int*); + enum PVR_ERROR(__cdecl* CallRecordingMenuHook)(const struct AddonInstance_PVR*, + const struct PVR_MENUHOOK*, + const struct PVR_RECORDING*); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // Timer interface functions + enum PVR_ERROR(__cdecl* GetTimerTypes)(const struct AddonInstance_PVR*, + struct PVR_TIMER_TYPE[], + int*); + enum PVR_ERROR(__cdecl* GetTimersAmount)(const struct AddonInstance_PVR*, int*); + enum PVR_ERROR(__cdecl* GetTimers)(const struct AddonInstance_PVR*, ADDON_HANDLE); + enum PVR_ERROR(__cdecl* AddTimer)(const struct AddonInstance_PVR*, const struct PVR_TIMER*); + enum PVR_ERROR(__cdecl* DeleteTimer)(const struct AddonInstance_PVR*, + const struct PVR_TIMER*, + bool); + enum PVR_ERROR(__cdecl* UpdateTimer)(const struct AddonInstance_PVR*, const struct PVR_TIMER*); + enum PVR_ERROR(__cdecl* CallTimerMenuHook)(const struct AddonInstance_PVR*, + const struct PVR_MENUHOOK*, + const struct PVR_TIMER*); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // Powersaving interface functions + enum PVR_ERROR(__cdecl* OnSystemSleep)(const struct AddonInstance_PVR*); + enum PVR_ERROR(__cdecl* OnSystemWake)(const struct AddonInstance_PVR*); + enum PVR_ERROR(__cdecl* OnPowerSavingActivated)(const struct AddonInstance_PVR*); + enum PVR_ERROR(__cdecl* OnPowerSavingDeactivated)(const struct AddonInstance_PVR*); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // Live stream read interface functions + bool(__cdecl* OpenLiveStream)(const struct AddonInstance_PVR*, const struct PVR_CHANNEL*); + void(__cdecl* CloseLiveStream)(const struct AddonInstance_PVR*); + int(__cdecl* ReadLiveStream)(const struct AddonInstance_PVR*, unsigned char*, unsigned int); + int64_t(__cdecl* SeekLiveStream)(const struct AddonInstance_PVR*, int64_t, int); + int64_t(__cdecl* LengthLiveStream)(const struct AddonInstance_PVR*); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // Recording stream read interface functions + bool(__cdecl* OpenRecordedStream)(const struct AddonInstance_PVR*, const struct PVR_RECORDING*); + void(__cdecl* CloseRecordedStream)(const struct AddonInstance_PVR*); + int(__cdecl* ReadRecordedStream)(const struct AddonInstance_PVR*, unsigned char*, unsigned int); + int64_t(__cdecl* SeekRecordedStream)(const struct AddonInstance_PVR*, int64_t, int); + int64_t(__cdecl* LengthRecordedStream)(const struct AddonInstance_PVR*); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // Stream demux interface functions + enum PVR_ERROR(__cdecl* GetStreamProperties)(const struct AddonInstance_PVR*, + struct PVR_STREAM_PROPERTIES*); + struct DemuxPacket*(__cdecl* DemuxRead)(const struct AddonInstance_PVR*); + void(__cdecl* DemuxReset)(const struct AddonInstance_PVR*); + void(__cdecl* DemuxAbort)(const struct AddonInstance_PVR*); + void(__cdecl* DemuxFlush)(const struct AddonInstance_PVR*); + void(__cdecl* SetSpeed)(const struct AddonInstance_PVR*, int); + void(__cdecl* FillBuffer)(const struct AddonInstance_PVR*, bool); + bool(__cdecl* SeekTime)(const struct AddonInstance_PVR*, double, bool, double*); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // General stream interface functions + bool(__cdecl* CanPauseStream)(const struct AddonInstance_PVR*); + void(__cdecl* PauseStream)(const struct AddonInstance_PVR*, bool); + bool(__cdecl* CanSeekStream)(const struct AddonInstance_PVR*); + bool(__cdecl* IsRealTimeStream)(const struct AddonInstance_PVR*); + enum PVR_ERROR(__cdecl* GetStreamTimes)(const struct AddonInstance_PVR*, + struct PVR_STREAM_TIMES*); + enum PVR_ERROR(__cdecl* GetStreamReadChunkSize)(const struct AddonInstance_PVR*, int*); + + //--==----==----==----==----==----==----==----==----==----==----==----==----== + // New functions becomes added below and can be on another API change (where + // breaks min API version) moved up. + } KodiToAddonFuncTable_PVR; + + typedef struct AddonInstance_PVR + { + struct AddonProperties_PVR* props; + struct AddonToKodiFuncTable_PVR* toKodi; + struct KodiToAddonFuncTable_PVR* toAddon; + } AddonInstance_PVR; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_PVR_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/CMakeLists.txt new file mode 100644 index 0000000..0e37ea4 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/CMakeLists.txt @@ -0,0 +1,14 @@ +set(HEADERS pvr_channel_groups.h + pvr_channels.h + pvr_defines.h + pvr_edl.h + pvr_epg.h + pvr_general.h + pvr_menu_hook.h + pvr_recordings.h + pvr_stream.h + pvr_timers.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_c-api_addon-instance_pvr) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channel_groups.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channel_groups.h new file mode 100644 index 0000000..a24d27f --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channel_groups.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_PVR_CHANNEL_GROUPS_H +#define C_API_ADDONINSTANCE_PVR_CHANNEL_GROUPS_H + +#include "pvr_defines.h" + +#include + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C" Definitions group 3 - PVR channel group +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + /*! + * @brief "C" PVR add-on channel group. + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref kodi::addon::PVRChannelGroup for description of values. + */ + typedef struct PVR_CHANNEL_GROUP + { + char strGroupName[PVR_ADDON_NAME_STRING_LENGTH]; + bool bIsRadio; + unsigned int iPosition; + } PVR_CHANNEL_GROUP; + + /*! + * @brief "C" PVR add-on channel group member. + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref kodi::addon::PVRChannelGroupMember for description of values. + */ + typedef struct PVR_CHANNEL_GROUP_MEMBER + { + char strGroupName[PVR_ADDON_NAME_STRING_LENGTH]; + unsigned int iChannelUniqueId; + unsigned int iChannelNumber; + unsigned int iSubChannelNumber; + int iOrder; + } PVR_CHANNEL_GROUP_MEMBER; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_PVR_CHANNEL_GROUPS_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channels.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channels.h new file mode 100644 index 0000000..00daffa --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_channels.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_PVR_CHANNELS_H +#define C_API_ADDONINSTANCE_PVR_CHANNELS_H + +#include "pvr_defines.h" + +#include + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C" Definitions group 2 - PVR channel +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_Channel + /// @brief Denotes that no channel uid is available. + /// + /// Special @ref kodi::addon::PVRTimer::SetClientChannelUid() and + /// @ref kodi::addon::PVRRecording::SetChannelUid() value to indicate that no + /// channel uid is available. + #define PVR_CHANNEL_INVALID_UID -1 + //---------------------------------------------------------------------------- + + /*! + * @brief "C" PVR add-on channel. + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref kodi::addon::PVRChannel for description of values. + */ + typedef struct PVR_CHANNEL + { + unsigned int iUniqueId; + bool bIsRadio; + unsigned int iChannelNumber; + unsigned int iSubChannelNumber; + char strChannelName[PVR_ADDON_NAME_STRING_LENGTH]; + char strMimeType[PVR_ADDON_INPUT_FORMAT_STRING_LENGTH]; + unsigned int iEncryptionSystem; + char strIconPath[PVR_ADDON_URL_STRING_LENGTH]; + bool bIsHidden; + bool bHasArchive; + int iOrder; + } PVR_CHANNEL; + + /*! + * @brief "C" PVR add-on signal status information. + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref kodi::addon::PVRSignalStatus for description of values. + */ + typedef struct PVR_SIGNAL_STATUS + { + char strAdapterName[PVR_ADDON_NAME_STRING_LENGTH]; + char strAdapterStatus[PVR_ADDON_NAME_STRING_LENGTH]; + char strServiceName[PVR_ADDON_NAME_STRING_LENGTH]; + char strProviderName[PVR_ADDON_NAME_STRING_LENGTH]; + char strMuxName[PVR_ADDON_NAME_STRING_LENGTH]; + int iSNR; + int iSignal; + long iBER; + long iUNC; + } PVR_SIGNAL_STATUS; + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo + /// @brief Special @ref cpp_kodi_addon_pvr_Defs_Channel_PVRDescrambleInfo + /// value to indicate that a struct member's value is not available + /// + #define PVR_DESCRAMBLE_INFO_NOT_AVAILABLE -1 + //---------------------------------------------------------------------------- + + /*! + * @brief "C" PVR add-on descramble information. + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref kodi::addon::PVRDescrambleInfo for description of values. + */ + typedef struct PVR_DESCRAMBLE_INFO + { + int iPid; + int iCaid; + int iProvid; + int iEcmTime; + int iHops; + char strCardSystem[PVR_ADDON_DESCRAMBLE_INFO_STRING_LENGTH]; + char strReader[PVR_ADDON_DESCRAMBLE_INFO_STRING_LENGTH]; + char strFrom[PVR_ADDON_DESCRAMBLE_INFO_STRING_LENGTH]; + char strProtocol[PVR_ADDON_DESCRAMBLE_INFO_STRING_LENGTH]; + } PVR_DESCRAMBLE_INFO; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_PVR_CHANNELS_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_defines.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_defines.h new file mode 100644 index 0000000..449000f --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_defines.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_PVR_DEFINES_H +#define C_API_ADDONINSTANCE_PVR_DEFINES_H + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C" Standard PVR definitions +// +// Values related to all parts and not used direct on addon, are to define here. +// +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + /*! + * @brief API array sizes which are used for data exchange between + * Kodi and addon. + */ + ///@{ + #define PVR_ADDON_NAME_STRING_LENGTH 1024 + #define PVR_ADDON_URL_STRING_LENGTH 1024 + #define PVR_ADDON_DESC_STRING_LENGTH 1024 + #define PVR_ADDON_INPUT_FORMAT_STRING_LENGTH 32 + #define PVR_ADDON_EDL_LENGTH 32 + #define PVR_ADDON_TIMERTYPE_ARRAY_SIZE 32 + #define PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE 512 + #define PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE_SMALL 128 + #define PVR_ADDON_TIMERTYPE_STRING_LENGTH 128 + #define PVR_ADDON_ATTRIBUTE_DESC_LENGTH 128 + #define PVR_ADDON_ATTRIBUTE_VALUES_ARRAY_SIZE 512 + #define PVR_ADDON_DESCRAMBLE_INFO_STRING_LENGTH 64 + #define PVR_ADDON_DATE_STRING_LENGTH 32 + ///@} + + /*! + * @brief "C" Representation of a general attribute integer value. + */ + typedef struct PVR_ATTRIBUTE_INT_VALUE + { + int iValue; + char strDescription[PVR_ADDON_ATTRIBUTE_DESC_LENGTH]; + } PVR_ATTRIBUTE_INT_VALUE; + + /*! + * @brief "C" Representation of a named value. + */ + typedef struct PVR_NAMED_VALUE + { + char strName[PVR_ADDON_NAME_STRING_LENGTH]; + char strValue[PVR_ADDON_NAME_STRING_LENGTH]; + } PVR_NAMED_VALUE; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_PVR_DEFINES_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_edl.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_edl.h new file mode 100644 index 0000000..e7cdf06 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_edl.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_PVR_EDL_H +#define C_API_ADDONINSTANCE_PVR_EDL_H + +#include "pvr_defines.h" + +#include + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C" Definitions group 8 - PVR Edit definition list (EDL) +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_EDLEntry_PVR_EDL_TYPE enum PVR_EDL_TYPE + /// @ingroup cpp_kodi_addon_pvr_Defs_EDLEntry + /// @brief **Edit definition list types**\n + /// Possible type values for @ref cpp_kodi_addon_pvr_Defs_EDLEntry_PVREDLEntry. + /// + ///@{ + typedef enum PVR_EDL_TYPE + { + /// @brief __0__ : cut (completely remove content) + PVR_EDL_TYPE_CUT = 0, + + /// @brief __1__ : mute audio + PVR_EDL_TYPE_MUTE = 1, + + /// @brief __2__ : scene markers (chapter seeking) + PVR_EDL_TYPE_SCENE = 2, + + /// @brief __3__ : commercial breaks + PVR_EDL_TYPE_COMBREAK = 3 + } PVR_EDL_TYPE; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief "C" Edit definition list entry. + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref kodi::addon::PVREDLEntry for description of values. + */ + typedef struct PVR_EDL_ENTRY + { + int64_t start; + int64_t end; + enum PVR_EDL_TYPE type; + } PVR_EDL_ENTRY; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_PVR_EDL_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_epg.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_epg.h new file mode 100644 index 0000000..d7512dc --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_epg.h @@ -0,0 +1,658 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_PVR_EPG_H +#define C_API_ADDONINSTANCE_PVR_EPG_H + +#include "pvr_defines.h" + +#include + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C" Definitions group 4 - PVR EPG +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT enum EPG_EVENT_CONTENTMASK (and sub types) + /// @ingroup cpp_kodi_addon_pvr_Defs_epg + /// @brief **EPG entry content event types.**\n + /// These ID's come from the DVB-SI EIT table "content descriptor" + /// Also known under the name "E-book genre assignments". + /// + /// See [ETSI EN 300 468 V1.14.1 (2014-05)](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) + /// about. + /// + /// Values used by this functions: + /// - @ref kodi::addon::PVREPGTag::SetGenreType() + /// - @ref kodi::addon::PVREPGTag::SetGenreSubType() + /// - @ref kodi::addon::PVRRecording::SetGenreType() + /// - @ref kodi::addon::PVRRecording::SetGenreSubType() + /// + /// Following types are listed here: + /// | emum Type | Description + /// |-----------|-------------------- + /// | @ref EPG_EVENT_CONTENTMASK | EPG entry main content to use. + /// | @ref EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_MOVIEDRAMA event types for sub type of "Movie/Drama". + /// | @ref EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS event types for sub type of "News/Current affairs". + /// | @ref EPG_EVENT_CONTENTSUBMASK_SHOW | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SHOW event types for sub type of "Show/Game show". + /// | @ref EPG_EVENT_CONTENTSUBMASK_SPORTS | @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SPORTS event types for sub type of "Sports". + /// | @ref EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_CHILDRENYOUTH event types for sub type of "Children's/Youth programmes". + /// | @ref EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE event types for sub type of "Music/Ballet/Dance". + /// | @ref EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_ARTSCULTURE event types for sub type of "Arts/Culture (without music)". + /// | @ref EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS event types for sub type of "Social/Political issues/Economics". + /// | @ref EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE event types for sub type of "Education/Science/Factual topics". + /// | @ref EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_LEISUREHOBBIES event types for sub type of "Leisure hobbies". + /// | @ref EPG_EVENT_CONTENTSUBMASK_SPECIAL | EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SPECIAL event types for sub type of "Special characteristics". + ///@{ + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT + /// @brief EPG entry main content to use. + /// + ///@{ + typedef enum EPG_EVENT_CONTENTMASK + { + /// @brief __0x00__ : Undefined content mask entry. + EPG_EVENT_CONTENTMASK_UNDEFINED = 0x00, + + /// @brief __0x10__ : Movie/Drama.\n + /// \n + /// See @ref EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA about related sub types. + EPG_EVENT_CONTENTMASK_MOVIEDRAMA = 0x10, + + /// @brief __0x20__ : News/Current affairs.\n + /// \n + /// See @ref EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS about related sub types. + EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS = 0x20, + + /// @brief __0x30__ : Show/Game show.\n + /// \n + /// See @ref EPG_EVENT_CONTENTSUBMASK_SHOW about related sub types. + EPG_EVENT_CONTENTMASK_SHOW = 0x30, + + /// @brief __0x40__ : Sports.\n + /// \n + /// See @ref EPG_EVENT_CONTENTSUBMASK_SPORTS about related sub types. + EPG_EVENT_CONTENTMASK_SPORTS = 0x40, + + /// @brief __0x50__ : Children's/Youth programmes.\n + /// \n + /// See @ref EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH about related sub types. + EPG_EVENT_CONTENTMASK_CHILDRENYOUTH = 0x50, + + /// @brief __0x60__ : Music/Ballet/Dance.\n + /// \n + /// See @ref EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE about related sub types. + EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE = 0x60, + + /// @brief __0x70__ : Arts/Culture (without music).\n + /// \n + /// See @ref EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE about related sub types. + EPG_EVENT_CONTENTMASK_ARTSCULTURE = 0x70, + + /// @brief __0x80__ : Social/Political issues/Economics.\n + /// \n + /// See @ref EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS about related sub types. + EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS = 0x80, + + /// @brief __0x90__ : Education/Science/Factual topics.\n + /// \n + /// See @ref EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE about related sub types. + EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE = 0x90, + + /// @brief __0xA0__ : Leisure hobbies.\n + /// \n + /// See @ref EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES about related sub types. + EPG_EVENT_CONTENTMASK_LEISUREHOBBIES = 0xA0, + + /// @brief __0xB0__ : Special characteristics.\n + /// \n + /// See @ref EPG_EVENT_CONTENTSUBMASK_SPECIAL about related sub types. + EPG_EVENT_CONTENTMASK_SPECIAL = 0xB0, + + /// @brief __0xF0__ User defined. + EPG_EVENT_CONTENTMASK_USERDEFINED = 0xF0, + + /// @brief Used to override standard genre types with a own name about.\n + /// \n + /// Set to this value @ref EPG_GENRE_USE_STRING on following places: + /// - @ref kodi::addon::PVREPGTag::SetGenreType() + /// - @ref kodi::addon::PVREPGTag::SetGenreSubType() + /// - @ref kodi::addon::PVRRecording::SetGenreType() + /// - @ref kodi::addon::PVRRecording::SetGenreSubType() + /// + /// @warning Value here is not a [ETSI EN 300 468 V1.14.1 (2014-05)](https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.14.01_60/en_300468v011401p.pdf) + /// conform. + /// + /// @note This is a own Kodi definition to set that genre is given by own + /// string. Used on @ref kodi::addon::PVREPGTag::SetGenreDescription() and + /// @ref kodi::addon::PVRRecording::SetGenreDescription() + EPG_GENRE_USE_STRING = 0x100 + } EPG_EVENT_CONTENTMASK; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT + /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_MOVIEDRAMA event + /// types for sub type of "Movie/Drama". + /// + ///@{ + typedef enum EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA + { + /// @brief __0x0__ : Movie/drama (general). + EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_GENERAL = 0x0, + + /// @brief __0x1__ : Detective/thriller. + EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_DETECTIVE_THRILLER = 0x1, + + /// @brief __0x2__ : Adventure/western/war. + EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_ADVENTURE_WESTERN_WAR = 0x2, + + /// @brief __0x3__ : Science fiction/fantasy/horror. + EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_SCIENCEFICTION_FANTASY_HORROR = 0x3, + + /// @brief __0x4__ : Comedy. + EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_COMEDY = 0x4, + + /// @brief __0x5__ : Soap/melodrama/folkloric. + EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_SOAP_MELODRAMA_FOLKLORIC = 0x5, + + /// @brief __0x6__ : Romance. + EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_ROMANCE = 0x6, + + /// @brief __0x7__ : Serious/classical/religious/historical movie/drama. + EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_SERIOUS_CLASSICAL_RELIGIOUS_HISTORICAL = 0x7, + + /// @brief __0x8__ : Adult movie/drama. + EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_ADULT = 0x8, + + /// @brief __0xF__ : User defined. + EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA_USERDEFINED = 0xF + } EPG_EVENT_CONTENTSUBMASK_MOVIEDRAMA; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT + /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS event + /// types for sub type of "News/Current affairs". + /// + typedef enum EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS + { + /// @brief __0x0__ : News/current affairs (general). + EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS_GENERAL = 0x0, + + /// @brief __0x1__ : News/weather report. + EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS_WEATHER = 0x1, + + /// @brief __0x2__ : News magazine. + EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS_MAGAZINE = 0x2, + + /// @brief __0x3__ : Documentary. + EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS_DOCUMENTARY = 0x3, + + /// @brief __0x4__ : Discussion/interview/debate + EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS_DISCUSSION_INTERVIEW_DEBATE = 0x4, + + /// @brief __0xF__ : User defined. + EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS_USERDEFINED = 0xF + } EPG_EVENT_CONTENTSUBMASK_NEWSCURRENTAFFAIRS; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT + /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SHOW event + /// types for sub type of "Show/Game show". + /// + typedef enum EPG_EVENT_CONTENTSUBMASK_SHOW + { + /// @brief __0x0__ : Show/game show (general). + EPG_EVENT_CONTENTSUBMASK_SHOW_GENERAL = 0x0, + + /// @brief __0x1__ : Game show/quiz/contest. + EPG_EVENT_CONTENTSUBMASK_SHOW_GAMESHOW_QUIZ_CONTEST = 0x1, + + /// @brief __0x2__ : Variety show. + EPG_EVENT_CONTENTSUBMASK_SHOW_VARIETY_SHOW = 0x2, + + /// @brief __0x3__ : Talk show. + EPG_EVENT_CONTENTSUBMASK_SHOW_TALK_SHOW = 0x3, + + /// @brief __0xF__ : User defined. + EPG_EVENT_CONTENTSUBMASK_SHOW_USERDEFINED = 0xF + } EPG_EVENT_CONTENTSUBMASK_SHOW; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT + /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SPORTS event + /// types for sub type of "Sports". + /// + typedef enum EPG_EVENT_CONTENTSUBMASK_SPORTS + { + /// @brief __0x0__ : Sports (general). + EPG_EVENT_CONTENTSUBMASK_SPORTS_GENERAL = 0x0, + + /// @brief __0x1__ : Special events (Olympic Games, World Cup, etc.). + EPG_EVENT_CONTENTSUBMASK_SPORTS_OLYMPICGAMES_WORLDCUP = 0x1, + + /// @brief __0x2__ : Sports magazines. + EPG_EVENT_CONTENTSUBMASK_SPORTS_SPORTS_MAGAZINES = 0x2, + + /// @brief __0x3__ : Football/soccer. + EPG_EVENT_CONTENTSUBMASK_SPORTS_FOOTBALL_SOCCER = 0x3, + + /// @brief __0x4__ : Tennis/squash. + EPG_EVENT_CONTENTSUBMASK_SPORTS_TENNIS_SQUASH = 0x4, + + /// @brief __0x5__ : Team sports (excluding football). + EPG_EVENT_CONTENTSUBMASK_SPORTS_TEAMSPORTS = 0x5, + + /// @brief __0x6__ : Athletics. + EPG_EVENT_CONTENTSUBMASK_SPORTS_ATHLETICS = 0x6, + + /// @brief __0x7__ : Motor sport. + EPG_EVENT_CONTENTSUBMASK_SPORTS_MOTORSPORT = 0x7, + + /// @brief __0x8__ : Water sport. + EPG_EVENT_CONTENTSUBMASK_SPORTS_WATERSPORT = 0x8, + + /// @brief __0x9__ : Winter sports. + EPG_EVENT_CONTENTSUBMASK_SPORTS_WINTERSPORTS = 0x9, + + /// @brief __0xA__ : Equestrian. + EPG_EVENT_CONTENTSUBMASK_SPORTS_EQUESTRIAN = 0xA, + + /// @brief __0xB__ : Martial sports. + EPG_EVENT_CONTENTSUBMASK_SPORTS_MARTIALSPORTS = 0xB, + + /// @brief __0xF__ : User defined. + EPG_EVENT_CONTENTSUBMASK_SPORTS_USERDEFINED = 0xF + } EPG_EVENT_CONTENTSUBMASK_SPORTS; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT + /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_CHILDRENYOUTH event + /// types for sub type of "Children's/Youth programmes". + /// + typedef enum EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH + { + /// @brief __0x0__ : Children's/youth programmes (general). + EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_GENERAL = 0x0, + + /// @brief __0x1__ : Pre-school children's programmes. + EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_PRESCHOOL_CHILDREN = 0x1, + + /// @brief __0x2__ : Entertainment programmes for 6 to 14. + EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_ENTERTAIN_6TO14 = 0x2, + + /// @brief __0x3__ : Entertainment programmes for 10 to 16. + EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_ENTERTAIN_10TO16 = 0x3, + + /// @brief __0x4__ : Informational/educational/school programmes. + EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_INFORMATIONAL_EDUCATIONAL_SCHOOL = 0x4, + + /// @brief __0x5__ : Cartoons/puppets. + EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_CARTOONS_PUPPETS = 0x5, + + /// @brief __0xF__ : User defined. + EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH_USERDEFINED = 0xF + } EPG_EVENT_CONTENTSUBMASK_CHILDRENYOUTH; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT + /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE event + /// types for sub type of "Music/Ballet/Dance". + /// + typedef enum EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE + { + /// @brief __0x0__ : Music/ballet/dance (general). + EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_GENERAL = 0x0, + + /// @brief __0x1__ : Rock/pop. + EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_ROCKPOP = 0x1, + + /// @brief __0x2__ : Serious music/classical music. + EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_SERIOUSMUSIC_CLASSICALMUSIC = 0x2, + + /// @brief __0x3__ : Folk/traditional music. + EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_FOLK_TRADITIONAL_MUSIC = 0x3, + + /// @brief __0x4__ : Jazz. + EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_JAZZ = 0x4, + + /// @brief __0x5__ : Musical/opera. + EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_MUSICAL_OPERA = 0x5, + + /// @brief __0x6__ : Ballet. + EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_BALLET = 0x6, + + /// @brief __0xF__ : User defined. + EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE_USERDEFINED = 0xF + } EPG_EVENT_CONTENTSUBMASK_MUSICBALLETDANCE; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT + /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_ARTSCULTURE event + /// types for sub type of "Arts/Culture (without music)". + /// + typedef enum EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE + { + /// @brief __0x0__ : Arts/culture (without music, general). + EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_GENERAL = 0x0, + + /// @brief __0x1__ : Performing arts. + EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_PERFORMINGARTS = 0x1, + + /// @brief __0x2__ : Fine arts. + EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_FINEARTS = 0x2, + + /// @brief __0x3__ : Religion. + EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_RELIGION = 0x3, + + /// @brief __0x4__ : Popular culture/traditional arts. + EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_POPULARCULTURE_TRADITIONALARTS = 0x4, + + /// @brief __0x5__ : Literature. + EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_LITERATURE = 0x5, + + /// @brief __0x6__ : Film/cinema. + EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_FILM_CINEMA = 0x6, + + /// @brief __0x7__ : Experimental film/video. + EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_EXPERIMENTALFILM_VIDEO = 0x7, + + /// @brief __0x8__ : Broadcasting/press. + EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_BROADCASTING_PRESS = 0x8, + + /// @brief __0x9__ : New media. + EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_NEWMEDIA = 0x9, + + /// @brief __0xA__ : Arts/culture magazines. + EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_ARTS_CULTUREMAGAZINES = 0xA, + + /// @brief __0xB__ : Fashion. + EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_FASHION = 0xB, + + /// @brief __0xF__ : User defined. + EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE_USERDEFINED = 0xF + } EPG_EVENT_CONTENTSUBMASK_ARTSCULTURE; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT + /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS event + /// types for sub type of "Social/Political issues/Economics". + /// + typedef enum EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS + { + /// @brief __0x0__ : Social/political issues/economics (general). + EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS_GENERAL = 0x0, + + /// @brief __0x1__ : Magazines/reports/documentary. + EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS_MAGAZINES_REPORTS_DOCUMENTARY = 0x1, + + /// @brief __0x2__ : Economics/social advisory. + EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS_ECONOMICS_SOCIALADVISORY = 0x2, + + /// @brief __0x3__ : Remarkable people. + EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS_REMARKABLEPEOPLE = 0x3, + + /// @brief __0xF__ : User defined. + EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS_USERDEFINED = 0xF + } EPG_EVENT_CONTENTSUBMASK_SOCIALPOLITICALECONOMICS; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT + /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE event + /// types for sub type of "Education/Science/Factual topics". + /// + typedef enum EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE + { + /// @brief __0x0__ : Education/science/factual topics (general). + EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_GENERAL = 0x0, + + /// @brief __0x1__ : Nature/animals/environment. + EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_NATURE_ANIMALS_ENVIRONMENT = 0x1, + + /// @brief __0x2__ : Technology/natural sciences. + EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_TECHNOLOGY_NATURALSCIENCES = 0x2, + + /// @brief __0x3__ : Medicine/physiology/psychology. + EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_MEDICINE_PHYSIOLOGY_PSYCHOLOGY = 0x3, + + /// @brief __0x4__ : Foreign countries/expeditions. + EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_FOREIGNCOUNTRIES_EXPEDITIONS = 0x4, + + /// @brief __0x5__ : Social/spiritual sciences. + EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_SOCIAL_SPIRITUALSCIENCES = 0x5, + + /// @brief __0x6__ : Further education. + EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_FURTHEREDUCATION = 0x6, + + /// @brief __0x7__ : Languages. + EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_LANGUAGES = 0x7, + + /// @brief __0xF__ : User defined. + EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE_USERDEFINED = 0xF + } EPG_EVENT_CONTENTSUBMASK_EDUCATIONALSCIENCE; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT + /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_LEISUREHOBBIES event + /// types for sub type of "Leisure hobbies". + /// + typedef enum EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES + { + /// @brief __0x0__ : Leisure hobbies (general) . + EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_GENERAL = 0x0, + + /// @brief __0x1__ : Tourism/travel. + EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_TOURISM_TRAVEL = 0x1, + + /// @brief __0x2__ : Handicraft. + EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_HANDICRAFT = 0x2, + + /// @brief __0x3__ : Motoring. + EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_MOTORING = 0x3, + + /// @brief __0x4__ : Fitness and health. + EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_FITNESSANDHEALTH = 0x4, + + /// @brief __0x5__ : Cooking. + EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_COOKING = 0x5, + + /// @brief __0x6__ : Advertisement/shopping. + EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_ADVERTISEMENT_SHOPPING = 0x6, + + /// @brief __0x7__ : Gardening. + EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_GARDENING = 0x7, + + /// @brief __0xF__ : User defined. + EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES_USERDEFINED = 0xF + } EPG_EVENT_CONTENTSUBMASK_LEISUREHOBBIES; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT + /// @brief EPG entry sub content to @ref EPG_EVENT_CONTENTMASK_SPECIAL event + /// types for sub type of "Special characteristics". + /// + typedef enum EPG_EVENT_CONTENTSUBMASK_SPECIAL + { + /// @brief __0x0__ : Special characteristics / Original language (general). + EPG_EVENT_CONTENTSUBMASK_SPECIAL_GENERAL = 0x0, + + /// @brief __0x1__ : Black and white. + EPG_EVENT_CONTENTSUBMASK_SPECIAL_BLACKANDWHITE = 0x1, + + /// @brief __0x2__ : Unpublished. + EPG_EVENT_CONTENTSUBMASK_SPECIAL_UNPUBLISHED = 0x2, + + /// @brief __0x3__ : Live broadcast. + EPG_EVENT_CONTENTSUBMASK_SPECIAL_LIVEBROADCAST = 0x3, + + /// @brief __0x4__ : Plano-stereoscopic. + EPG_EVENT_CONTENTSUBMASK_SPECIAL_PLANOSTEREOSCOPIC = 0x4, + + /// @brief __0x5__ : Local or regional. + EPG_EVENT_CONTENTSUBMASK_SPECIAL_LOCALORREGIONAL = 0x5, + + /// @brief __0xF__ : User defined. + EPG_EVENT_CONTENTSUBMASK_SPECIAL_USERDEFINED = 0xF + } EPG_EVENT_CONTENTSUBMASK_SPECIAL; + //---------------------------------------------------------------------------- + + ///@} + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg + /// @brief Separator to use in strings containing different tokens, for example + /// writers, directors, actors of an event. + /// + #define EPG_STRING_TOKEN_SEPARATOR "," + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_epg_EPG_TAG_FLAG enum EPG_TAG_FLAG + /// @ingroup cpp_kodi_addon_pvr_Defs_epg + /// @brief Bit field of independent flags associated with the EPG entry.\n + /// Values used by @ref kodi::addon::PVREPGTag::SetFlags(). + /// + /// Here's example about the use of this: + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVREPGTag tag; + /// tag.SetFlags(EPG_TAG_FLAG_IS_SERIES | EPG_TAG_FLAG_IS_NEW); + /// ~~~~~~~~~~~~~ + /// + ///@{ + typedef enum EPG_TAG_FLAG + { + /// @brief __0000 0000__ : Nothing special to say about this entry. + EPG_TAG_FLAG_UNDEFINED = 0, + + /// @brief __0000 0001__ : This EPG entry is part of a series. + EPG_TAG_FLAG_IS_SERIES = (1 << 0), + + /// @brief __0000 0010__ : This EPG entry will be flagged as new. + EPG_TAG_FLAG_IS_NEW = (1 << 1), + + /// @brief __0000 0100__ : This EPG entry will be flagged as a premiere. + EPG_TAG_FLAG_IS_PREMIERE = (1 << 2), + + /// @brief __0000 1000__ : This EPG entry will be flagged as a finale. + EPG_TAG_FLAG_IS_FINALE = (1 << 3), + + /// @brief __0001 0000__ : This EPG entry will be flagged as live. + EPG_TAG_FLAG_IS_LIVE = (1 << 4), + } EPG_TAG_FLAG; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg + /// @brief Special PVREPGTag::SetUniqueBroadcastId value + /// + /// Special @ref kodi::addon::PVREPGTag::SetUniqueBroadcastId() value to + /// indicate that a tag has not a valid EPG event uid. + /// + #define EPG_TAG_INVALID_UID 0 + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg + /// @brief Special @ref kodi::addon::PVREPGTag::SetSeriesNumber(), @ref kodi::addon::PVREPGTag::SetEpisodeNumber() + /// and @ref kodi::addon::PVREPGTag::SetEpisodePartNumber() value to indicate + /// it is not to be used. + /// + #define EPG_TAG_INVALID_SERIES_EPISODE -1 + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_epg + /// @brief Timeframe value for use with @ref kodi::addon::CInstancePVRClient::SetEPGTimeFrame() + /// function to indicate "no timeframe". + /// + #define EPG_TIMEFRAME_UNLIMITED -1 + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_epg_EPG_EVENT_STATE enum EPG_EVENT_STATE + /// @ingroup cpp_kodi_addon_pvr_Defs_epg + /// @brief **EPG event states.**\n + /// Used with @ref kodi::addon::CInstancePVRClient::EpgEventStateChange() + /// callback. + /// + ///@{ + typedef enum EPG_EVENT_STATE + { + /// @brief __0__ : Event created. + EPG_EVENT_CREATED = 0, + + /// @brief __1__ : Event updated. + EPG_EVENT_UPDATED = 1, + + /// @brief __2__ : Event deleted. + EPG_EVENT_DELETED = 2, + } EPG_EVENT_STATE; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief "C" PVR add-on channel group member. + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref kodi::addon::PVREPGTag for description of values. + */ + typedef struct EPG_TAG + { + unsigned int iUniqueBroadcastId; + unsigned int iUniqueChannelId; + const char* strTitle; + time_t startTime; + time_t endTime; + const char* strPlotOutline; + const char* strPlot; + const char* strOriginalTitle; + const char* strCast; + const char* strDirector; + const char* strWriter; + int iYear; + const char* strIMDBNumber; + const char* strIconPath; + int iGenreType; + int iGenreSubType; + const char* strGenreDescription; + const char* strFirstAired; + int iParentalRating; + int iStarRating; + int iSeriesNumber; + int iEpisodeNumber; + int iEpisodePartNumber; + const char* strEpisodeName; + unsigned int iFlags; + const char* strSeriesLink; + } EPG_TAG; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_PVR_EPG_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_general.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_general.h new file mode 100644 index 0000000..e2136f6 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_general.h @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_PVR_GENERAL_H +#define C_API_ADDONINSTANCE_PVR_GENERAL_H + +#include "pvr_defines.h" + +#ifdef BUILD_KODI_ADDON +#include "../../../InputStreamConstants.h" +#else +#include "cores/VideoPlayer/Interface/Addon/InputStreamConstants.h" +#endif + +#include + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C" Definitions group 1 - General PVR +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_General_PVR_ERROR enum PVR_ERROR + /// @ingroup cpp_kodi_addon_pvr_Defs_General + /// @brief **PVR add-on error codes**\n + /// Used as return values on most PVR related functions. + /// + /// In this way, a PVR instance signals errors in its processing and, under + /// certain conditions, allows Kodi to make corrections. + /// + ///@{ + typedef enum PVR_ERROR + { + /// @brief __0__ : No error occurred. + PVR_ERROR_NO_ERROR = 0, + + /// @brief __-1__ : An unknown error occurred. + PVR_ERROR_UNKNOWN = -1, + + /// @brief __-2__ : The method that Kodi called is not implemented by the add-on. + PVR_ERROR_NOT_IMPLEMENTED = -2, + + /// @brief __-3__ : The backend reported an error, or the add-on isn't connected. + PVR_ERROR_SERVER_ERROR = -3, + + /// @brief __-4__ : The command was sent to the backend, but the response timed out. + PVR_ERROR_SERVER_TIMEOUT = -4, + + /// @brief __-5__ : The command was rejected by the backend. + PVR_ERROR_REJECTED = -5, + + /// @brief __-6__ : The requested item can not be added, because it's already present. + PVR_ERROR_ALREADY_PRESENT = -6, + + /// @brief __-7__ : The parameters of the method that was called are invalid for this + /// operation. + PVR_ERROR_INVALID_PARAMETERS = -7, + + /// @brief __-8__ : A recording is running, so the timer can't be deleted without + /// doing a forced delete. + PVR_ERROR_RECORDING_RUNNING = -8, + + /// @brief __-9__ : The command failed. + PVR_ERROR_FAILED = -9, + } PVR_ERROR; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_General_PVR_CONNECTION_STATE enum PVR_CONNECTION_STATE + /// @ingroup cpp_kodi_addon_pvr_Defs_General + /// @brief **PVR backend connection states**\n + /// Used with @ref kodi::addon::CInstancePVRClient::ConnectionStateChange() callback. + /// + /// With this, a PVR instance signals that Kodi should perform special + /// operations. + /// + ///@{ + typedef enum PVR_CONNECTION_STATE + { + /// @brief __0__ : Unknown state (e.g. not yet tried to connect). + PVR_CONNECTION_STATE_UNKNOWN = 0, + + /// @brief __1__ : Backend server is not reachable (e.g. server not existing or + /// network down). + PVR_CONNECTION_STATE_SERVER_UNREACHABLE = 1, + + /// @brief __2__ : Backend server is reachable, but there is not the expected type of + /// server running (e.g. HTSP required, but FTP running at given server:port). + PVR_CONNECTION_STATE_SERVER_MISMATCH = 2, + + /// @brief __3__ : Backend server is reachable, but server version does not match + /// client requirements. + PVR_CONNECTION_STATE_VERSION_MISMATCH = 3, + + /// @brief __4__ : Backend server is reachable, but denies client access (e.g. due + /// to wrong credentials). + PVR_CONNECTION_STATE_ACCESS_DENIED = 4, + + /// @brief __5__ : Connection to backend server is established. + PVR_CONNECTION_STATE_CONNECTED = 5, + + /// @brief __6__ : No connection to backend server (e.g. due to network errors or + /// client initiated disconnect). + PVR_CONNECTION_STATE_DISCONNECTED = 6, + + /// @brief __7__ : Connecting to backend. + PVR_CONNECTION_STATE_CONNECTING = 7, + } PVR_CONNECTION_STATE; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_General_PVR_STREAM_PROPERTY definition PVR_STREAM_PROPERTY + /// @ingroup cpp_kodi_addon_pvr_Defs_General_Inputstream + /// @brief **PVR related stream property values**\n + /// This is used to pass additional data to Kodi on a given PVR stream. + /// + /// Then transferred to livestream, recordings or EPG Tag stream using the + /// properties. + /// + /// This defines are used by: + /// - @ref kodi::addon::CInstancePVRClient::GetChannelStreamProperties() + /// - @ref kodi::addon::CInstancePVRClient::GetEPGTagStreamProperties() + /// - @ref kodi::addon::CInstancePVRClient::GetRecordingStreamProperties() + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// + /// PVR_ERROR CMyPVRInstance::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, + /// std::vector& properties) + /// { + /// ... + /// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM, "inputstream.adaptive"); + /// properties.emplace_back("inputstream.adaptive.manifest_type", "mpd"); + /// properties.emplace_back("inputstream.adaptive.manifest_update_parameter", "full"); + /// properties.emplace_back(PVR_STREAM_PROPERTY_MIMETYPE, "application/xml+dash"); + /// return PVR_ERROR_NO_ERROR; + /// } + /// + /// ... + /// ~~~~~~~~~~~~~ + /// + ///@{ + + /// @brief the URL of the stream that should be played. + /// + #define PVR_STREAM_PROPERTY_STREAMURL "streamurl" + + /// @brief To define in stream properties the name of the inputstream add-on + /// that should be used. + /// + /// Leave blank to use Kodi's built-in playing capabilities or to allow ffmpeg + /// to handle directly set to @ref PVR_STREAM_PROPERTY_VALUE_INPUTSTREAMFFMPEG. + /// + #define PVR_STREAM_PROPERTY_INPUTSTREAM STREAM_PROPERTY_INPUTSTREAM + + /// @brief Identification string for an input stream. + /// + /// This value can be used in addition to @ref PVR_STREAM_PROPERTY_INPUTSTREAM. + /// It is used to provide the respective inpustream addon with additional + /// identification. + /// + /// The difference between this and other stream properties is that it is also + /// passed in the associated @ref kodi::addon::CAddonBase::CreateInstance() + /// call. + /// + /// This makes it possible to select different processing classes within the + /// associated add-on. + /// + /// + ///--------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// + /// // On PVR instance of addon + /// PVR_ERROR CMyPVRInstance::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, + /// std::vector& properties) + /// { + /// ... + /// // For here on example the inpustream is also inside the PVR addon + /// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM, "pvr.my_one"); + /// properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM_INSTANCE_ID, "my_special_id_1"); + /// return PVR_ERROR_NO_ERROR; + /// } + /// + /// ... + /// + /// // On CAddonBase part of addon + /// ADDON_STATUS CMyAddon::CreateInstanceEx(int instanceType, + /// std::string instanceID, + /// KODI_HANDLE instance, + /// KODI_HANDLE& addonInstance + /// const std::string& version) + /// { + /// if (instanceType == ADDON_INSTANCE_INPUTSTREAM) + /// { + /// kodi::Log(ADDON_LOG_INFO, "Creating my special inputstream"); + /// if (instanceID == "my_special_id_1") + /// addonInstance = new CMyPVRClientInstance_Type1(instance, version); + /// else if (instanceID == "my_special_id_2") + /// addonInstance = new CMyPVRClientInstance_Type2(instance, version); + /// return ADDON_STATUS_OK; + /// } + /// else if (...) + /// { + /// ... + /// } + /// return ADDON_STATUS_UNKNOWN; + /// } + /// + /// ... + /// ~~~~~~~~~~~~~ + /// + #define PVR_STREAM_PROPERTY_INPUTSTREAM_INSTANCE_ID STREAM_PROPERTY_INPUTSTREAM_INSTANCE_ID + + /// @brief the MIME type of the stream that should be played. + /// + #define PVR_STREAM_PROPERTY_MIMETYPE "mimetype" + + /// @brief "true" to denote that the stream that should be played is a + /// realtime stream. + /// + /// Any other value indicates that this is no realtime stream. + /// + #define PVR_STREAM_PROPERTY_ISREALTIMESTREAM STREAM_PROPERTY_ISREALTIMESTREAM + + /// @brief "true" to denote that if the stream is from an EPG tag. + /// + /// It should be played is a live stream. Otherwise if it's a EPG tag it will + /// play as normal video. + /// + #define PVR_STREAM_PROPERTY_EPGPLAYBACKASLIVE "epgplaybackaslive" + + /// @brief Special value for @ref PVR_STREAM_PROPERTY_INPUTSTREAM to use + /// ffmpeg to directly play a stream URL. + #define PVR_STREAM_PROPERTY_VALUE_INPUTSTREAMFFMPEG STREAM_PROPERTY_VALUE_INPUTSTREAMFFMPEG + + ///@} + //----------------------------------------------------------------------------- + + /*! + * @brief "C" PVR add-on capabilities. + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref kodi::addon::PVRCapabilities for description of values. + */ + typedef struct PVR_ADDON_CAPABILITIES + { + bool bSupportsEPG; + bool bSupportsEPGEdl; + bool bSupportsTV; + bool bSupportsRadio; + bool bSupportsRecordings; + bool bSupportsRecordingsUndelete; + bool bSupportsTimers; + bool bSupportsChannelGroups; + bool bSupportsChannelScan; + bool bSupportsChannelSettings; + bool bHandlesInputStream; + bool bHandlesDemuxing; + bool bSupportsRecordingPlayCount; + bool bSupportsLastPlayedPosition; + bool bSupportsRecordingEdl; + bool bSupportsRecordingsRename; + bool bSupportsRecordingsLifetimeChange; + bool bSupportsDescrambleInfo; + bool bSupportsAsyncEPGTransfer; + bool bSupportsRecordingSize; + + unsigned int iRecordingsLifetimesSize; + struct PVR_ATTRIBUTE_INT_VALUE recordingsLifetimeValues[PVR_ADDON_ATTRIBUTE_VALUES_ARRAY_SIZE]; + } PVR_ADDON_CAPABILITIES; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_PVR_GENERAL_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_menu_hook.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_menu_hook.h new file mode 100644 index 0000000..2ead263 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_menu_hook.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_PVR_MENUHOOK_H +#define C_API_ADDONINSTANCE_PVR_MENUHOOK_H + +#include "pvr_defines.h" + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C" Definitions group 7 - Menu hook +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_Menuhook_PVR_MENUHOOK_CAT enum PVR_MENUHOOK_CAT + /// @ingroup cpp_kodi_addon_pvr_Defs_Menuhook + /// @brief **PVR context menu hook categories**\n + /// Possible menu types given to Kodi with @ref kodi::addon::CInstancePVRClient::AddMenuHook(). + /// + ///@{ + typedef enum PVR_MENUHOOK_CAT + { + /// @brief __-1__ : Unknown menu hook. + PVR_MENUHOOK_UNKNOWN = -1, + + /// @brief __0__ : All categories. + PVR_MENUHOOK_ALL = 0, + + /// @brief __1__ : For channels. + PVR_MENUHOOK_CHANNEL = 1, + + /// @brief __2__ : For timers. + PVR_MENUHOOK_TIMER = 2, + + /// @brief __3__ : For EPG. + PVR_MENUHOOK_EPG = 3, + + /// @brief __4__ : For recordings. + PVR_MENUHOOK_RECORDING = 4, + + /// @brief __5__ : For deleted recordings. + PVR_MENUHOOK_DELETED_RECORDING = 5, + + /// @brief __6__ : For settings. + PVR_MENUHOOK_SETTING = 6, + } PVR_MENUHOOK_CAT; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief "C" PVR add-on menu hook. + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref kodi::addon::PVRMenuhook for description of values. + */ + typedef struct PVR_MENUHOOK + { + unsigned int iHookId; + unsigned int iLocalizedStringId; + enum PVR_MENUHOOK_CAT category; + } PVR_MENUHOOK; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_PVR_MENUHOOK_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_recordings.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_recordings.h new file mode 100644 index 0000000..2e2c081 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_recordings.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_PVR_RECORDINGS_H +#define C_API_ADDONINSTANCE_PVR_RECORDINGS_H + +#include "pvr_defines.h" + +#include +#include +#include + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C" Definitions group 5 - PVR recordings +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_Recording_PVR_RECORDING_FLAG enum PVR_RECORDING_FLAG + /// @ingroup cpp_kodi_addon_pvr_Defs_Recording + /// @brief **Bit field of independent flags associated with the EPG entry.**\n + /// Values used by @ref kodi::addon::PVRRecording::SetFlags(). + /// + /// Here's example about the use of this: + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVRRecording tag; + /// tag.SetFlags(PVR_RECORDING_FLAG_IS_SERIES | PVR_RECORDING_FLAG_IS_PREMIERE); + /// ~~~~~~~~~~~~~ + /// + ///@{ + typedef enum PVR_RECORDING_FLAG + { + /// @brief __0000 0000__ : Nothing special to say about this recording. + PVR_RECORDING_FLAG_UNDEFINED = 0, + + /// @brief __0000 0001__ : This recording is part of a series. + PVR_RECORDING_FLAG_IS_SERIES = (1 << 0), + + /// @brief __0000 0010__ : This recording will be flagged as new. + PVR_RECORDING_FLAG_IS_NEW = (1 << 1), + + /// @brief __0000 0100__ : This recording will be flagged as a premiere. + PVR_RECORDING_FLAG_IS_PREMIERE = (1 << 2), + + /// @brief __0000 1000__ : This recording will be flagged as a finale. + PVR_RECORDING_FLAG_IS_FINALE = (1 << 3), + + /// @brief __0001 0000__ : This recording will be flagged as live. + PVR_RECORDING_FLAG_IS_LIVE = (1 << 4), + } PVR_RECORDING_FLAG; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording + /// @brief Special @ref kodi::addon::PVRRecording::SetSeriesNumber() and + /// @ref kodi::addon::PVRRecording::SetEpisodeNumber() value to indicate it is + /// not to be used. + /// + /// Used if recording has no valid season and/or episode info. + /// + #define PVR_RECORDING_INVALID_SERIES_EPISODE EPG_TAG_INVALID_SERIES_EPISODE + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_Recording_PVRRecording + /// @brief Value where set in background to inform that related part not used. + /// + /// Normally this related parts need not to set by this as it is default. + #define PVR_RECORDING_VALUE_NOT_AVAILABLE -1 + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_Recording_PVR_RECORDING_CHANNEL_TYPE enum PVR_RECORDING_CHANNEL_TYPE + /// @ingroup cpp_kodi_addon_pvr_Defs_Recording + /// @brief **PVR recording channel types**\n + /// Used on @ref kodi::addon::PVRRecording::SetChannelType() value to set related + /// type. + /// + ///@{ + typedef enum PVR_RECORDING_CHANNEL_TYPE + { + /// @brief __0__ : Unknown type. + PVR_RECORDING_CHANNEL_TYPE_UNKNOWN = 0, + + /// @brief __1__ : TV channel. + PVR_RECORDING_CHANNEL_TYPE_TV = 1, + + /// @brief __2__ : Radio channel. + PVR_RECORDING_CHANNEL_TYPE_RADIO = 2, + } PVR_RECORDING_CHANNEL_TYPE; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief "C" PVR add-on recording. + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref kodi::addon::PVRRecording for description of values. + */ + typedef struct PVR_RECORDING + { + char strRecordingId[PVR_ADDON_NAME_STRING_LENGTH]; + char strTitle[PVR_ADDON_NAME_STRING_LENGTH]; + char strEpisodeName[PVR_ADDON_NAME_STRING_LENGTH]; + int iSeriesNumber; + int iEpisodeNumber; + int iYear; + char strDirectory[PVR_ADDON_URL_STRING_LENGTH]; + char strPlotOutline[PVR_ADDON_DESC_STRING_LENGTH]; + char strPlot[PVR_ADDON_DESC_STRING_LENGTH]; + char strGenreDescription[PVR_ADDON_DESC_STRING_LENGTH]; + char strChannelName[PVR_ADDON_NAME_STRING_LENGTH]; + char strIconPath[PVR_ADDON_URL_STRING_LENGTH]; + char strThumbnailPath[PVR_ADDON_URL_STRING_LENGTH]; + char strFanartPath[PVR_ADDON_URL_STRING_LENGTH]; + time_t recordingTime; + int iDuration; + int iPriority; + int iLifetime; + int iGenreType; + int iGenreSubType; + int iPlayCount; + int iLastPlayedPosition; + bool bIsDeleted; + unsigned int iEpgEventId; + int iChannelUid; + enum PVR_RECORDING_CHANNEL_TYPE channelType; + char strFirstAired[PVR_ADDON_DATE_STRING_LENGTH]; + unsigned int iFlags; + int64_t sizeInBytes; + } PVR_RECORDING; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_PVR_RECORDINGS_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_stream.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_stream.h new file mode 100644 index 0000000..1206c67 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_stream.h @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_PVR_STREAM_H +#define C_API_ADDONINSTANCE_PVR_STREAM_H + +#include "pvr_defines.h" + +#ifdef BUILD_KODI_ADDON +#include "../../../DemuxPacket.h" +#else +#include "cores/VideoPlayer/Interface/Addon/DemuxPacket.h" +#endif + +#include +#include + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C" Definitions group 9 - PVR stream definitions (NOTE: Becomes replaced +// in future by inputstream addon instance way) +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_Stream + /// @brief Maximum of allowed streams + /// + #define PVR_STREAM_MAX_STREAMS 20 + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_Stream + /// @brief Invalid codec identifier + /// + #define PVR_INVALID_CODEC_ID 0 + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_addon_pvr_Defs_Stream + /// @brief Invalid codec + /// + #define PVR_INVALID_CODEC \ + { \ + PVR_CODEC_TYPE_UNKNOWN, PVR_INVALID_CODEC_ID \ + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVR_CODEC_TYPE enum PVR_CODEC_TYPE + /// @ingroup cpp_kodi_addon_pvr_Defs_Stream + /// @brief **Inputstream types**\n + /// To identify type on stream. + /// + /// Used on @ref kodi::addon::PVRStreamProperties::SetCodecType and @ref kodi::addon::PVRStreamProperties::SetCodecType. + /// + ///@{ + typedef enum PVR_CODEC_TYPE + { + /// @brief To set nothing defined. + PVR_CODEC_TYPE_UNKNOWN = -1, + + /// @brief To identify @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties as Video. + PVR_CODEC_TYPE_VIDEO, + + /// @brief To identify @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties as Audio. + PVR_CODEC_TYPE_AUDIO, + + /// @brief To identify @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties as Data. + /// + /// With codec id related source identified. + PVR_CODEC_TYPE_DATA, + + /// @brief To identify @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties as Subtitle. + PVR_CODEC_TYPE_SUBTITLE, + + /// @brief To identify @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties as Radio RDS. + PVR_CODEC_TYPE_RDS, + + PVR_CODEC_TYPE_NB + } PVR_CODEC_TYPE; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_Stream_PVR_CODEC struct PVR_CODEC + /// @ingroup cpp_kodi_addon_pvr_Defs_Stream + /// @brief **Codec identification structure**\n + /// Identifier about stream between Kodi and addon. + /// + ///@{ + typedef struct PVR_CODEC + { + /// @brief Used codec type for stream. + enum PVR_CODEC_TYPE codec_type; + + /// @brief Related codec identifier, normally match the ffmpeg id's. + unsigned int codec_id; + } PVR_CODEC; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief "C" Stream properties + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamProperties for description of values. + */ + typedef struct PVR_STREAM_PROPERTIES + { + unsigned int iStreamCount; + struct PVR_STREAM + { + unsigned int iPID; + enum PVR_CODEC_TYPE iCodecType; + unsigned int iCodecId; + char strLanguage[4]; + int iSubtitleInfo; + int iFPSScale; + int iFPSRate; + int iHeight; + int iWidth; + float fAspect; + int iChannels; + int iSampleRate; + int iBlockAlign; + int iBitRate; + int iBitsPerSample; + } stream[PVR_STREAM_MAX_STREAMS]; + } PVR_STREAM_PROPERTIES; + + /*! + * @brief "C" Times of playing stream (Live TV and recordings) + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref cpp_kodi_addon_pvr_Defs_Stream_PVRStreamTimes for description of values. + */ + typedef struct PVR_STREAM_TIMES + { + time_t startTime; + int64_t ptsStart; + int64_t ptsBegin; + int64_t ptsEnd; + } PVR_STREAM_TIMES; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_PVR_STREAM_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_timers.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_timers.h new file mode 100644 index 0000000..209726d --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_timers.h @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_PVR_TIMERS_H +#define C_API_ADDONINSTANCE_PVR_TIMERS_H + +#include "pvr_defines.h" + +#include +#include +#include + +//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ +// "C" Definitions group 6 - PVR timers +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVR_TIMER_ definition PVR_TIMER (various) + /// @ingroup cpp_kodi_addon_pvr_Defs_Timer + /// @brief **PVR timer various different definitions**\n + /// This mostly used on @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimer "kodi::addon::PVRTimer" + /// to define default or not available. + /// + ///@{ + + //============================================================================ + /// @brief Numeric PVR timer type definitions (@ref kodi::addon::PVRTimer::SetTimerType() + /// values). + /// + /// "Null" value for a numeric timer type. + #define PVR_TIMER_TYPE_NONE 0 + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Special @ref kodi::addon::PVRTimer::SetClientIndex() value to indicate + /// that a timer has not (yet) a valid client index. + /// + /// Timer has not (yet) a valid client index. + #define PVR_TIMER_NO_CLIENT_INDEX 0 + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Special @ref kodi::addon::PVRTimer::SetParentClientIndex() value to + /// indicate that a timer has no parent. + /// + /// Timer has no parent; it was not scheduled by a repeating timer. + #define PVR_TIMER_NO_PARENT PVR_TIMER_NO_CLIENT_INDEX + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Special @ref kodi::addon::PVRTimer::SetEPGUid() value to indicate + /// that a timer has no EPG event uid. + /// + /// Timer has no EPG event unique identifier. + #define PVR_TIMER_NO_EPG_UID EPG_TAG_INVALID_UID + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Special @ref kodi::addon::PVRTimer::SetClientChannelUid() value to + /// indicate "any channel". Useful for some repeating timer types. + /// + /// denotes "any channel", not a specific one. + /// + #define PVR_TIMER_ANY_CHANNEL -1 + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Value where set in background to inform that related part not used. + /// + /// Normally this related parts need not to set by this as it is default. + #define PVR_TIMER_VALUE_NOT_AVAILABLE -1 + //---------------------------------------------------------------------------- + + ///@} + //---------------------------------------------------------------------------- + + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVR_TIMER_TYPES enum PVR_TIMER_TYPES + /// @ingroup cpp_kodi_addon_pvr_Defs_Timer + /// @brief **PVR timer type attributes (@ref kodi::addon::PVRTimerType::SetAttributes() values).**\n + /// To defines the attributes for a type. These values are bit fields that can be + /// used together. + /// + ///-------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::addon::PVRTimerType tag; + /// tag.SetAttributes(PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_IS_REPEATING); + /// ~~~~~~~~~~~~~ + /// + ///@{ + typedef enum PVR_TIMER_TYPES + { + /// @brief __0000 0000 0000 0000 0000 0000 0000 0000__ :\n Empty attribute value. + PVR_TIMER_TYPE_ATTRIBUTE_NONE = 0, + + /// @brief __0000 0000 0000 0000 0000 0000 0000 0001__ :\n Defines whether this is a type for + /// manual (time-based) or epg-based timers. + PVR_TIMER_TYPE_IS_MANUAL = (1 << 0), + + /// @brief __0000 0000 0000 0000 0000 0000 0000 0010__ :\n Defines whether this is a type for + /// repeating or one-shot timers. + PVR_TIMER_TYPE_IS_REPEATING = (1 << 1), + + /// @brief __0000 0000 0000 0000 0000 0000 0000 0100__ :\n Timers of this type must not be edited + /// by Kodi. + PVR_TIMER_TYPE_IS_READONLY = (1 << 2), + + /// @brief __0000 0000 0000 0000 0000 0000 0000 1000__ :\n Timers of this type must not be created + /// by Kodi. All other operations are allowed, though. + PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES = (1 << 3), + + /// @brief __0000 0000 0000 0000 0000 0000 0001 0000__ :\n This type supports enabling/disabling + /// of the timer (@ref kodi::addon::PVRTimer::SetState() with + /// @ref PVR_TIMER_STATE_SCHEDULED | @ref PVR_TIMER_STATE_DISABLED). + PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE = (1 << 4), + + /// @brief __0000 0000 0000 0000 0000 0000 0010 0000__ :\n This type supports channels + /// (@ref kodi::addon::PVRTimer::SetClientChannelUid()). + PVR_TIMER_TYPE_SUPPORTS_CHANNELS = (1 << 5), + + /// @brief __0000 0000 0000 0000 0000 0000 0100 0000__ :\n This type supports a recording start + /// time (@ref kodi::addon::PVRTimer::SetStartTime()). + PVR_TIMER_TYPE_SUPPORTS_START_TIME = (1 << 6), + + /// @brief __0000 0000 0000 0000 0000 0000 1000 0000__ :\n This type supports matching epg episode + /// title using@ref kodi::addon::PVRTimer::SetEPGSearchString(). + PVR_TIMER_TYPE_SUPPORTS_TITLE_EPG_MATCH = (1 << 7), + + /// @brief __0000 0000 0000 0000 0000 0001 0000 0000__ :\n This type supports matching "more" epg + /// data (not just episode title) using @ref kodi::addon::PVRTimer::SetEPGSearchString(). + /// Setting @ref PVR_TIMER_TYPE_SUPPORTS_FULLTEXT_EPG_MATCH implies + /// @ref PVR_TIMER_TYPE_SUPPORTS_TITLE_EPG_MATCH. + PVR_TIMER_TYPE_SUPPORTS_FULLTEXT_EPG_MATCH = (1 << 8), + + /// @brief __0000 0000 0000 0000 0000 0010 0000 0000__ :\n This type supports a first day the + /// timer gets active (@ref kodi::addon::PVRTimer::SetFirstDay()). + PVR_TIMER_TYPE_SUPPORTS_FIRST_DAY = (1 << 9), + + /// @brief __0000 0000 0000 0000 0000 0100 0000 0000__ :\n This type supports weekdays for + /// defining the recording schedule (@ref kodi::addon::PVRTimer::SetWeekdays()). + PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS = (1 << 10), + + /// @brief __0000 0000 0000 0000 0000 1000 0000 0000__ :\n This type supports the "record only new episodes" feature + /// (@ref kodi::addon::PVRTimer::SetPreventDuplicateEpisodes()). + PVR_TIMER_TYPE_SUPPORTS_RECORD_ONLY_NEW_EPISODES = (1 << 11), + + /// @brief __0000 0000 0000 0000 0001 0000 0000 0000__ :\n This type supports pre and post record time (@ref kodi::addon::PVRTimer::SetMarginStart(), + /// @ref kodi::addon::PVRTimer::SetMarginEnd()). + PVR_TIMER_TYPE_SUPPORTS_START_END_MARGIN = (1 << 12), + + /// @brief __0000 0000 0000 0000 0010 0000 0000 0000__ :\n This type supports recording priority (@ref kodi::addon::PVRTimer::SetPriority()). + PVR_TIMER_TYPE_SUPPORTS_PRIORITY = (1 << 13), + + /// @brief __0000 0000 0000 0000 0100 0000 0000 0000__ :\n This type supports recording lifetime (@ref kodi::addon::PVRTimer::SetLifetime()). + PVR_TIMER_TYPE_SUPPORTS_LIFETIME = (1 << 14), + + /// @brief __0000 0000 0000 0000 1000 0000 0000 0000__ :\n This type supports placing recordings in user defined folders + /// (@ref kodi::addon::PVRTimer::SetDirectory()). + PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS = (1 << 15), + + /// @brief __0000 0000 0000 0001 0000 0000 0000 0000__ :\n This type supports a list of recording groups + /// (@ref kodi::addon::PVRTimer::SetRecordingGroup()). + PVR_TIMER_TYPE_SUPPORTS_RECORDING_GROUP = (1 << 16), + + /// @brief __0000 0000 0000 0010 0000 0000 0000 0000__ :\n This type supports a recording end time (@ref kodi::addon::PVRTimer::SetEndTime()). + PVR_TIMER_TYPE_SUPPORTS_END_TIME = (1 << 17), + + /// @brief __0000 0000 0000 0100 0000 0000 0000 0000__ :\n Enables an 'Any Time' over-ride option for start time + /// (using @ref kodi::addon::PVRTimer::SetStartAnyTime()). + PVR_TIMER_TYPE_SUPPORTS_START_ANYTIME = (1 << 18), + + /// @brief __0000 0000 0000 1000 0000 0000 0000 0000__ :\n Enables a separate 'Any Time' over-ride for end time + /// (using @ref kodi::addon::PVRTimer::SetEndAnyTime()). + PVR_TIMER_TYPE_SUPPORTS_END_ANYTIME = (1 << 19), + + /// @brief __0000 0000 0001 0000 0000 0000 0000 0000__ :\n This type supports specifying a maximum recordings setting' + /// (@ref kodi::addon::PVRTimer::SetMaxRecordings()). + PVR_TIMER_TYPE_SUPPORTS_MAX_RECORDINGS = (1 << 20), + + /// @brief __0000 0000 0010 0000 0000 0000 0000 0000__ :\n This type should not appear on any create menus which don't + /// provide an associated @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "EPG tag". + PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE = (1 << 21), + + /// @brief __0000 0000 0100 0000 0000 0000 0000 0000__ :\n This type should not appear on any create menus which provide an + /// associated @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "EPG tag". + PVR_TIMER_TYPE_FORBIDS_EPG_TAG_ON_CREATE = (1 << 22), + + /// @brief __0000 0000 1000 0000 0000 0000 0000 0000__ :\n This type should not appear on any create menus unless associated + /// with an @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "EPG tag" with + /// 'series' attributes. + /// + /// Following conditions allow this: + /// - @ref kodi::addon::PVREPGTag::SetFlags() have flag @ref EPG_TAG_FLAG_IS_SERIES + /// - @ref kodi::addon::PVREPGTag::SetSeriesNumber() > 0 + /// - @ref kodi::addon::PVREPGTag::SetEpisodeNumber() > 0 + /// - @ref kodi::addon::PVREPGTag::SetEpisodePartNumber() > 0 + /// + /// Implies @ref PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE. + PVR_TIMER_TYPE_REQUIRES_EPG_SERIES_ON_CREATE = (1 << 23), + + /// @brief __0000 0001 0000 0000 0000 0000 0000 0000__ :\n This type supports 'any channel', for example when defining a timer + /// rule that should match any channel instaed of a particular channel. + PVR_TIMER_TYPE_SUPPORTS_ANY_CHANNEL = (1 << 24), + + /// @brief __0000 0010 0000 0000 0000 0000 0000 0000__ :\n This type should not appear on any create menus which don't provide + /// an associated @ref cpp_kodi_addon_pvr_Defs_epg_PVREPGTag "EPG tag" with + /// a series link. + PVR_TIMER_TYPE_REQUIRES_EPG_SERIESLINK_ON_CREATE = (1 << 25), + + /// @brief __0000 0100 0000 0000 0000 0000 0000 0000__ :\n This type allows deletion of an otherwise read-only timer. + PVR_TIMER_TYPE_SUPPORTS_READONLY_DELETE = (1 << 26), + + /// @brief __0000 1000 0000 0000 0000 0000 0000 0000__ :\n Timers of this type do trigger a reminder if time is up. + PVR_TIMER_TYPE_IS_REMINDER = (1 << 27), + + /// @brief __0001 0000 0000 0000 0000 0000 0000 0000__ :\n This type supports pre record time (@ref kodi::addon::PVRTimer::SetMarginStart()). + PVR_TIMER_TYPE_SUPPORTS_START_MARGIN = (1 << 28), + + /// @brief __0010 0000 0000 0000 0000 0000 0000 0000__ :\n This type supports post record time (@ref kodi::addon::PVRTimer::SetMarginEnd()). + PVR_TIMER_TYPE_SUPPORTS_END_MARGIN = (1 << 29), + } PVR_TIMER_TYPES; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVR_WEEKDAY enum PVR_WEEKDAY + /// @ingroup cpp_kodi_addon_pvr_Defs_Timer + /// @brief **PVR timer weekdays** (@ref kodi::addon::PVRTimer::SetWeekdays() **values**)\n + /// Used to select the days of a week you want. + /// + /// It can be also used to select several days e.g.: + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// unsigned int day = PVR_WEEKDAY_MONDAY | PVR_WEEKDAY_SATURDAY; + /// ... + /// ~~~~~~~~~~~~~ + /// + ///@{ + typedef enum PVR_WEEKDAYS + { + /// @brief __0000 0000__ : Nothing selected. + PVR_WEEKDAY_NONE = 0, + + /// @brief __0000 0001__ : To select Monday. + PVR_WEEKDAY_MONDAY = (1 << 0), + + /// @brief __0000 0010__ : To select Tuesday. + PVR_WEEKDAY_TUESDAY = (1 << 1), + + /// @brief __0000 0100__ : To select Wednesday. + PVR_WEEKDAY_WEDNESDAY = (1 << 2), + + /// @brief __0000 1000__ : To select Thursday. + PVR_WEEKDAY_THURSDAY = (1 << 3), + + /// @brief __0001 0000__ : To select Friday. + PVR_WEEKDAY_FRIDAY = (1 << 4), + + /// @brief __0010 0000__ : To select Saturday. + PVR_WEEKDAY_SATURDAY = (1 << 5), + + /// @brief __0100 0000__ : To select Sunday. + PVR_WEEKDAY_SUNDAY = (1 << 6), + + /// @brief __0111 1111__ : To select all days of week. + PVR_WEEKDAY_ALLDAYS = PVR_WEEKDAY_MONDAY | PVR_WEEKDAY_TUESDAY | PVR_WEEKDAY_WEDNESDAY | + PVR_WEEKDAY_THURSDAY | PVR_WEEKDAY_FRIDAY | PVR_WEEKDAY_SATURDAY | + PVR_WEEKDAY_SUNDAY + } PVR_WEEKDAY; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_addon_pvr_Defs_Timer_PVR_TIMER_STATE enum PVR_TIMER_STATE + /// @ingroup cpp_kodi_addon_pvr_Defs_Timer + /// @brief **PVR timer states**\n + /// To set within @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimer "kodi::addon::PVRTimer" + /// the needed state about. + /// + ///@{ + typedef enum PVR_TIMER_STATE + { + /// @brief __0__ : The timer was just created on the backend and is not yet active. + /// + /// This state must not be used for timers just created on the client side. + PVR_TIMER_STATE_NEW = 0, + + /// @brief __1__ : The timer is scheduled for recording. + PVR_TIMER_STATE_SCHEDULED = 1, + + /// @brief __2__ : The timer is currently recordings. + PVR_TIMER_STATE_RECORDING = 2, + + /// @brief __3__ : The recording completed successfully. + PVR_TIMER_STATE_COMPLETED = 3, + + /// @brief __4__ : Recording started, but was aborted. + PVR_TIMER_STATE_ABORTED = 4, + + /// @brief __5__ : The timer was scheduled, but was canceled. + PVR_TIMER_STATE_CANCELLED = 5, + + /// @brief __6__ : The scheduled timer conflicts with another one, but will be + /// recorded. + PVR_TIMER_STATE_CONFLICT_OK = 6, + + /// @brief __7__ : The scheduled timer conflicts with another one and won't be + /// recorded. + PVR_TIMER_STATE_CONFLICT_NOK = 7, + + /// @brief __8__ : The timer is scheduled, but can't be recorded for some reason. + PVR_TIMER_STATE_ERROR = 8, + + /// @brief __9__ : The timer was disabled by the user, can be enabled via setting + /// the state to @ref PVR_TIMER_STATE_SCHEDULED. + PVR_TIMER_STATE_DISABLED = 9, + } PVR_TIMER_STATE; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief "C" PVR add-on timer event. + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimer "kodi::addon::PVRTimer" for + * description of values. + */ + typedef struct PVR_TIMER + { + unsigned int iClientIndex; + unsigned int iParentClientIndex; + int iClientChannelUid; + time_t startTime; + time_t endTime; + bool bStartAnyTime; + bool bEndAnyTime; + enum PVR_TIMER_STATE state; + unsigned int iTimerType; + char strTitle[PVR_ADDON_NAME_STRING_LENGTH]; + char strEpgSearchString[PVR_ADDON_NAME_STRING_LENGTH]; + bool bFullTextEpgSearch; + char strDirectory[PVR_ADDON_URL_STRING_LENGTH]; + char strSummary[PVR_ADDON_DESC_STRING_LENGTH]; + int iPriority; + int iLifetime; + int iMaxRecordings; + unsigned int iRecordingGroup; + time_t firstDay; + unsigned int iWeekdays; + unsigned int iPreventDuplicateEpisodes; + unsigned int iEpgUid; + unsigned int iMarginStart; + unsigned int iMarginEnd; + int iGenreType; + int iGenreSubType; + char strSeriesLink[PVR_ADDON_URL_STRING_LENGTH]; + } PVR_TIMER; + + /*! + * @brief "C" PVR add-on timer event type. + * + * Structure used to interface in "C" between Kodi and Addon. + * + * See @ref cpp_kodi_addon_pvr_Defs_Timer_PVRTimerType "kodi::addon::PVRTimerType" for + * description of values. + */ + typedef struct PVR_TIMER_TYPE + { + unsigned int iId; + uint64_t iAttributes; + char strDescription[PVR_ADDON_TIMERTYPE_STRING_LENGTH]; + + unsigned int iPrioritiesSize; + struct PVR_ATTRIBUTE_INT_VALUE priorities[PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE]; + int iPrioritiesDefault; + + unsigned int iLifetimesSize; + struct PVR_ATTRIBUTE_INT_VALUE lifetimes[PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE]; + int iLifetimesDefault; + + unsigned int iPreventDuplicateEpisodesSize; + struct PVR_ATTRIBUTE_INT_VALUE preventDuplicateEpisodes[PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE]; + unsigned int iPreventDuplicateEpisodesDefault; + + unsigned int iRecordingGroupSize; + struct PVR_ATTRIBUTE_INT_VALUE recordingGroup[PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE]; + unsigned int iRecordingGroupDefault; + + unsigned int iMaxRecordingsSize; + struct PVR_ATTRIBUTE_INT_VALUE maxRecordings[PVR_ADDON_TIMERTYPE_VALUES_ARRAY_SIZE_SMALL]; + int iMaxRecordingsDefault; + } PVR_TIMER_TYPE; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_PVR_TIMERS_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/screensaver.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/screensaver.h new file mode 100644 index 0000000..32cf6e1 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/screensaver.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../addon_base.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + struct AddonInstance_Screensaver; + + /*! + * @brief Screensaver properties + * + * Not to be used outside this header. + */ + typedef struct AddonProps_Screensaver + { + ADDON_HARDWARE_CONTEXT device; + int x; + int y; + int width; + int height; + float pixelRatio; + const char* name; + const char* presets; + const char* profile; + } AddonProps_Screensaver; + + /*! + * @brief Screensaver callbacks + * + * Not to be used outside this header. + */ + typedef struct AddonToKodiFuncTable_Screensaver + { + KODI_HANDLE kodiInstance; + } AddonToKodiFuncTable_Screensaver; + + /*! + * @brief Screensaver function hooks + * + * Not to be used outside this header. + */ + typedef struct KodiToAddonFuncTable_Screensaver + { + KODI_HANDLE addonInstance; + bool(__cdecl* Start)(struct AddonInstance_Screensaver* instance); + void(__cdecl* Stop)(struct AddonInstance_Screensaver* instance); + void(__cdecl* Render)(struct AddonInstance_Screensaver* instance); + } KodiToAddonFuncTable_Screensaver; + + /*! + * @brief Screensaver instance + * + * Not to be used outside this header. + */ + typedef struct AddonInstance_Screensaver + { + struct AddonProps_Screensaver* props; + struct AddonToKodiFuncTable_Screensaver* toKodi; + struct KodiToAddonFuncTable_Screensaver* toAddon; + } AddonInstance_Screensaver; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/vfs.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/vfs.h new file mode 100644 index 0000000..a6c3f44 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/vfs.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDONINSTANCE_VFS_H +#define C_API_ADDONINSTANCE_VFS_H + +#include "../addon_base.h" +#include "../filesystem.h" + +#define VFS_FILE_HANDLE void* + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + struct VFSURL + { + const char* url; + const char* domain; + const char* hostname; + const char* filename; + unsigned int port; + const char* options; + const char* username; + const char* password; + const char* redacted; + const char* sharename; + const char* protocol; + }; + + typedef struct VFSGetDirectoryCallbacks /* internal */ + { + bool(__cdecl* get_keyboard_input)(KODI_HANDLE ctx, + const char* heading, + char** input, + bool hidden_input); + void(__cdecl* set_error_dialog)(KODI_HANDLE ctx, + const char* heading, + const char* line1, + const char* line2, + const char* line3); + void(__cdecl* require_authentication)(KODI_HANDLE ctx, const char* url); + KODI_HANDLE ctx; + } VFSGetDirectoryCallbacks; + + typedef struct AddonProps_VFSEntry /* internal */ + { + int dummy; + } AddonProps_VFSEntry; + + typedef struct AddonToKodiFuncTable_VFSEntry /* internal */ + { + KODI_HANDLE kodiInstance; + } AddonToKodiFuncTable_VFSEntry; + + struct AddonInstance_VFSEntry; + typedef struct KodiToAddonFuncTable_VFSEntry /* internal */ + { + KODI_HANDLE addonInstance; + + VFS_FILE_HANDLE(__cdecl* open) + (const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url); + VFS_FILE_HANDLE(__cdecl* open_for_write) + (const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url, bool overwrite); + ssize_t(__cdecl* read)(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + uint8_t* buffer, + size_t buf_size); + ssize_t(__cdecl* write)(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + const uint8_t* buffer, + size_t buf_size); + int64_t(__cdecl* seek)(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + int64_t position, + int whence); + int(__cdecl* truncate)(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + int64_t size); + int64_t(__cdecl* get_length)(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context); + int64_t(__cdecl* get_position)(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context); + int(__cdecl* get_chunk_size)(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context); + bool(__cdecl* io_control_get_seek_possible)(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context); + bool(__cdecl* io_control_get_cache_status)(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + VFS_CACHE_STATUS_DATA* status); + bool(__cdecl* io_control_set_cache_rate)(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + unsigned int rate); + bool(__cdecl* io_control_set_retry)(const struct AddonInstance_VFSEntry* instance, + VFS_FILE_HANDLE context, + bool retry); + int(__cdecl* stat)(const struct AddonInstance_VFSEntry* instance, + const struct VFSURL* url, + struct STAT_STRUCTURE* buffer); + bool(__cdecl* close)(const struct AddonInstance_VFSEntry* instance, VFS_FILE_HANDLE context); + + bool(__cdecl* exists)(const struct AddonInstance_VFSEntry* instance, const struct VFSURL* url); + void(__cdecl* clear_out_idle)(const struct AddonInstance_VFSEntry* instance); + void(__cdecl* disconnect_all)(const struct AddonInstance_VFSEntry* instance); + bool(__cdecl* delete_it)(const struct AddonInstance_VFSEntry* instance, + const struct VFSURL* url); + bool(__cdecl* rename)(const struct AddonInstance_VFSEntry* instance, + const struct VFSURL* url, + const struct VFSURL* url2); + bool(__cdecl* directory_exists)(const struct AddonInstance_VFSEntry* instance, + const struct VFSURL* url); + bool(__cdecl* remove_directory)(const struct AddonInstance_VFSEntry* instance, + const struct VFSURL* url); + bool(__cdecl* create_directory)(const struct AddonInstance_VFSEntry* instance, + const struct VFSURL* url); + bool(__cdecl* get_directory)(const struct AddonInstance_VFSEntry* instance, + const struct VFSURL* url, + struct VFSDirEntry** entries, + int* num_entries, + struct VFSGetDirectoryCallbacks* callbacks); + bool(__cdecl* contains_files)(const struct AddonInstance_VFSEntry* instance, + const struct VFSURL* url, + struct VFSDirEntry** entries, + int* num_entries, + char* rootpath); + void(__cdecl* free_directory)(const struct AddonInstance_VFSEntry* instance, + struct VFSDirEntry* entries, + int num_entries); + } KodiToAddonFuncTable_VFSEntry; + + typedef struct AddonInstance_VFSEntry /* internal */ + { + struct AddonProps_VFSEntry* props; + struct AddonToKodiFuncTable_VFSEntry* toKodi; + struct KodiToAddonFuncTable_VFSEntry* toAddon; + } AddonInstance_VFSEntry; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_ADDONINSTANCE_VFS_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/visualization.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/visualization.h new file mode 100644 index 0000000..913aad8 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon-instance/visualization.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../addon_base.h" + +#define VIZ_LYRICS_SIZE 32768 + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + struct VIS_INFO + { + bool bWantsFreq; + int iSyncDelay; + }; + + struct VIS_TRACK + { + const char *title; + const char *artist; + const char *album; + const char *albumArtist; + const char *genre; + const char *comment; + const char *lyrics; + + const char *reserved1; + const char *reserved2; + + int trackNumber; + int discNumber; + int duration; + int year; + int rating; + + int reserved3; + int reserved4; + }; + + typedef struct AddonProps_Visualization + { + ADDON_HARDWARE_CONTEXT device; + int x; + int y; + int width; + int height; + float pixelRatio; + const char* name; + const char* presets; + const char* profile; + } AddonProps_Visualization; + + typedef struct AddonToKodiFuncTable_Visualization + { + KODI_HANDLE kodiInstance; + void(__cdecl* transfer_preset)(KODI_HANDLE kodiInstance, const char* preset); + void(__cdecl* clear_presets)(KODI_HANDLE kodiInstance); + } AddonToKodiFuncTable_Visualization; + + struct AddonInstance_Visualization; + + typedef struct KodiToAddonFuncTable_Visualization + { + KODI_HANDLE addonInstance; + bool(__cdecl* start)(const struct AddonInstance_Visualization* instance, + int channels, + int samples_per_sec, + int bits_per_sample, + const char* song_name); + void(__cdecl* stop)(const struct AddonInstance_Visualization* instance); + + void(__cdecl* get_info)(const struct AddonInstance_Visualization* instance, + struct VIS_INFO* info); + + void(__cdecl* audio_data)(const struct AddonInstance_Visualization* instance, + const float* audio_data, + int audio_data_length, + float* freq_data, + int freq_data_length); + bool(__cdecl* is_dirty)(const struct AddonInstance_Visualization* instance); + void(__cdecl* render)(const struct AddonInstance_Visualization* instance); + + unsigned int(__cdecl* get_presets)(const struct AddonInstance_Visualization* instance); + int(__cdecl* get_active_preset)(const struct AddonInstance_Visualization* instance); + bool(__cdecl* prev_preset)(const struct AddonInstance_Visualization* instance); + bool(__cdecl* next_preset)(const struct AddonInstance_Visualization* instance); + bool(__cdecl* load_preset)(const struct AddonInstance_Visualization* instance, int select); + bool(__cdecl* random_preset)(const struct AddonInstance_Visualization* instance); + bool(__cdecl* lock_preset)(const struct AddonInstance_Visualization* instance); + bool(__cdecl* rate_preset)(const struct AddonInstance_Visualization* instance, bool plus_minus); + bool(__cdecl* is_locked)(const struct AddonInstance_Visualization* instance); + + bool(__cdecl* update_albumart)(const struct AddonInstance_Visualization* instance, + const char* albumart); + bool(__cdecl* update_track)(const struct AddonInstance_Visualization* instance, + const struct VIS_TRACK* track); + } KodiToAddonFuncTable_Visualization; + + typedef struct AddonInstance_Visualization + { + struct AddonProps_Visualization* props; + struct AddonToKodiFuncTable_Visualization* toKodi; + struct KodiToAddonFuncTable_Visualization* toAddon; + } AddonInstance_Visualization; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon_base.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon_base.h new file mode 100644 index 0000000..faa99fa --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/addon_base.h @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2005-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_ADDON_BASE_H +#define C_API_ADDON_BASE_H + +#if !defined(NOMINMAX) +#define NOMINMAX +#endif + +#include "stdbool.h" +#include "stdint.h" + +#ifndef TARGET_WINDOWS +#ifndef __cdecl +#define __cdecl +#endif +#ifndef __declspec +#define __declspec(X) +#endif +#endif + +#undef ATTRIBUTE_PACKED +#undef PRAGMA_PACK_BEGIN +#undef PRAGMA_PACK_END + +#if defined(__GNUC__) +#define ATTRIBUTE_PACKED __attribute__((packed)) +#define PRAGMA_PACK 0 +#define ATTRIBUTE_HIDDEN __attribute__((visibility("hidden"))) +#endif + +#if !defined(ATTRIBUTE_PACKED) +#define ATTRIBUTE_PACKED +#define PRAGMA_PACK 1 +#endif + +#if !defined(ATTRIBUTE_HIDDEN) +#define ATTRIBUTE_HIDDEN +#endif + +#ifdef _MSC_VER +#define ATTRIBUTE_FORCEINLINE __forceinline +#elif defined(__GNUC__) +#define ATTRIBUTE_FORCEINLINE inline __attribute__((__always_inline__)) +#elif defined(__CLANG__) +#if __has_attribute(__always_inline__) +#define ATTRIBUTE_FORCEINLINE inline __attribute__((__always_inline__)) +#else +#define ATTRIBUTE_FORCEINLINE inline +#endif +#else +#define ATTRIBUTE_FORCEINLINE inline +#endif + +// Hardware specific device context interface +#define ADDON_HARDWARE_CONTEXT void* + +/* + * To have a on add-on and kodi itself handled string always on known size! + */ +#define ADDON_STANDARD_STRING_LENGTH 1024 +#define ADDON_STANDARD_STRING_LENGTH_SMALL 256 + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// @ingroup cpp_kodi_addon_addonbase + /// @brief Return value of functions in @ref cpp_kodi_addon_addonbase "kodi::addon::CAddonBase" + /// and associated classes. + /// + ///@{ + typedef enum ADDON_STATUS + { + /// @brief For everything OK and no error + ADDON_STATUS_OK, + + /// @brief A needed connection was lost + ADDON_STATUS_LOST_CONNECTION, + + /// @brief Addon needs a restart inside Kodi + ADDON_STATUS_NEED_RESTART, + + /// @brief Necessary settings are not yet set + ADDON_STATUS_NEED_SETTINGS, + + /// @brief Unknown and incomprehensible error + ADDON_STATUS_UNKNOWN, + + /// @brief Permanent failure, like failing to resolve methods + ADDON_STATUS_PERMANENT_FAILURE, + + /* internal used return error if function becomes not used from child on + * addon */ + ADDON_STATUS_NOT_IMPLEMENTED + } ADDON_STATUS; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_Defs_AddonLog enum AddonLog + /// @ingroup cpp_kodi_Defs + /// @brief **Log file type definitions**\n + /// These define the types of log entries given with @ref kodi::Log() to Kodi. + /// + /// ------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// kodi::Log(ADDON_LOG_ERROR, "%s: There is an error occurred!", __func__); + /// + /// ~~~~~~~~~~~~~ + /// + ///@{ + typedef enum AddonLog + { + /// @brief **0** : To include debug information in the log file. + ADDON_LOG_DEBUG = 0, + + /// @brief **1** : To include information messages in the log file. + ADDON_LOG_INFO = 1, + + /// @brief **2** : To write warnings in the log file. + ADDON_LOG_WARNING = 2, + + /// @brief **3** : To report error messages in the log file. + ADDON_LOG_ERROR = 3, + + /// @brief **4** : To notify fatal unrecoverable errors, which can may also indicate + /// upcoming crashes. + ADDON_LOG_FATAL = 4 + } AddonLog; + ///@} + //---------------------------------------------------------------------------- + + /*! @brief Standard undefined pointer handle */ + typedef void* KODI_HANDLE; + + /*! + * @brief Handle used to return data from the PVR add-on to CPVRClient + */ + struct ADDON_HANDLE_STRUCT + { + void* callerAddress; /*!< address of the caller */ + void* dataAddress; /*!< address to store data in */ + int dataIdentifier; /*!< parameter to pass back when calling the callback */ + }; + typedef struct ADDON_HANDLE_STRUCT* ADDON_HANDLE; + + /*! + * @brief Callback function tables from addon to Kodi + * Set complete from Kodi! + */ + struct AddonToKodiFuncTable_kodi; + struct AddonToKodiFuncTable_kodi_audioengine; + struct AddonToKodiFuncTable_kodi_filesystem; + struct AddonToKodiFuncTable_kodi_network; + struct AddonToKodiFuncTable_kodi_gui; + typedef struct AddonToKodiFuncTable_Addon + { + // Pointer inside Kodi, used on callback functions to give related handle + // class, for this ADDON::CAddonDll inside Kodi. + KODI_HANDLE kodiBase; + + // Function addresses used for callbacks from addon to Kodi + char* (*get_type_version)(void* kodiBase, int type); + + void (*free_string)(void* kodiBase, char* str); + void (*free_string_array)(void* kodiBase, char** arr, int numElements); + char* (*get_addon_path)(void* kodiBase); + char* (*get_base_user_path)(void* kodiBase); + void (*addon_log_msg)(void* kodiBase, const int loglevel, const char* msg); + + bool (*get_setting_bool)(void* kodiBase, const char* id, bool* value); + bool (*get_setting_int)(void* kodiBase, const char* id, int* value); + bool (*get_setting_float)(void* kodiBase, const char* id, float* value); + bool (*get_setting_string)(void* kodiBase, const char* id, char** value); + + bool (*set_setting_bool)(void* kodiBase, const char* id, bool value); + bool (*set_setting_int)(void* kodiBase, const char* id, int value); + bool (*set_setting_float)(void* kodiBase, const char* id, float value); + bool (*set_setting_string)(void* kodiBase, const char* id, const char* value); + + void* (*get_interface)(void* kodiBase, const char* name, const char* version); + + struct AddonToKodiFuncTable_kodi* kodi; + struct AddonToKodiFuncTable_kodi_audioengine* kodi_audioengine; + struct AddonToKodiFuncTable_kodi_filesystem* kodi_filesystem; + struct AddonToKodiFuncTable_kodi_gui* kodi_gui; + struct AddonToKodiFuncTable_kodi_network* kodi_network; + + // Move up by min version change about + bool (*is_setting_using_default)(void* kodiBase, const char* id); + } AddonToKodiFuncTable_Addon; + + /*! + * @brief Function tables from Kodi to addon + */ + typedef struct KodiToAddonFuncTable_Addon + { + void (*destroy)(); + ADDON_STATUS (*get_status)(); + ADDON_STATUS(*create_instance) + (int instanceType, + const char* instanceID, + KODI_HANDLE instance, + const char* version, + KODI_HANDLE* addonInstance, + KODI_HANDLE parent); + void (*destroy_instance)(int instanceType, KODI_HANDLE instance); + ADDON_STATUS (*set_setting)(const char* settingName, const void* settingValue); + } KodiToAddonFuncTable_Addon; + + /*! + * @brief Main structure passed from kodi to addon with basic information needed to + * create add-on. + */ + typedef struct AddonGlobalInterface + { + // String with full path where add-on is installed (without his name on end) + // Set from Kodi! + const char* libBasePath; + + // Master API version of Kodi itself (ADDON_GLOBAL_VERSION_MAIN) + const char* kodi_base_api_version; + + // Pointer of first created instance, used in case this add-on goes with single way + // Set from Kodi! + KODI_HANDLE firstKodiInstance; + + // Pointer to master base class inside add-on + // Set from addon header (kodi::addon::CAddonBase)! + KODI_HANDLE addonBase; + + // Pointer to a instance used on single way (together with this class) + // Set from addon header (kodi::addon::IAddonInstance)! + KODI_HANDLE globalSingleInstance; + + // Callback function tables from addon to Kodi + // Set from Kodi! + AddonToKodiFuncTable_Addon* toKodi; + + // Function tables from Kodi to addon + // Set from addon header! + KodiToAddonFuncTable_Addon* toAddon; + } AddonGlobalInterface; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_ADDON_BASE_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/audio_engine.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/audio_engine.h new file mode 100644 index 0000000..97510f7 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/audio_engine.h @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2005-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_AUDIO_ENGINE_H +#define C_API_AUDIO_ENGINE_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ + // "C" Definitions, structures and enumerators of audio engine + //{{{ + + //============================================================================ + /// @defgroup cpp_kodi_audioengine_Defs_AudioEngineStreamOptions enum AudioEngineStreamOptions + /// @ingroup cpp_kodi_audioengine_Defs + /// @brief **Bit options to pass to CAEStream**\n + /// A bit field of stream options. + /// + /// + /// ------------------------------------------------------------------------ + /// + /// **Usage example:** + /// ~~~~~~~~~~~~~{.cpp} + /// // Here only as minimal, "format" must be set to wanted types + /// kodi::audioengine::AudioEngineFormat format; + /// m_audioengine = new kodi::audioengine::CAEStream(format, AUDIO_STREAM_FORCE_RESAMPLE | AUDIO_STREAM_AUTOSTART); + /// ~~~~~~~~~~~~~ + /// + ///@{ + typedef enum AudioEngineStreamOptions + { + /// force resample even if rates match + AUDIO_STREAM_FORCE_RESAMPLE = 1 << 0, + /// create the stream paused + AUDIO_STREAM_PAUSED = 1 << 1, + /// autostart the stream when enough data is buffered + AUDIO_STREAM_AUTOSTART = 1 << 2, + } AudioEngineStreamOptions; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_audioengine_Defs_AudioEngineChannel enum AudioEngineChannel + /// @ingroup cpp_kodi_audioengine_Defs + /// @brief **The possible channels**\n + /// Used to set available or used channels on stream. + /// + /// + /// ------------------------------------------------------------------------ + /// + /// **Usage example:** + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::audioengine::AudioEngineFormat format; + /// format.SetChannelLayout(std::vector(AUDIOENGINE_CH_FL, AUDIOENGINE_CH_FR)); + /// ~~~~~~~~~~~~~ + /// + ///@{ + enum AudioEngineChannel + { + /// Used inside to indicate the end of a list and not for addon use directly. + AUDIOENGINE_CH_NULL = -1, + /// RAW Audio format + AUDIOENGINE_CH_RAW, + /// Front left + AUDIOENGINE_CH_FL, + /// Front right + AUDIOENGINE_CH_FR, + /// Front center + AUDIOENGINE_CH_FC, + /// LFE / Subwoofer + AUDIOENGINE_CH_LFE, + /// Back left + AUDIOENGINE_CH_BL, + /// Back right + AUDIOENGINE_CH_BR, + /// Front left over center + AUDIOENGINE_CH_FLOC, + /// Front right over center + AUDIOENGINE_CH_FROC, + /// Back center + AUDIOENGINE_CH_BC, + /// Side left + AUDIOENGINE_CH_SL, + /// Side right + AUDIOENGINE_CH_SR, + /// Top front left + AUDIOENGINE_CH_TFL, + /// Top front right + AUDIOENGINE_CH_TFR, + /// Top front center + AUDIOENGINE_CH_TFC, + /// Top center + AUDIOENGINE_CH_TC, + /// Top back left + AUDIOENGINE_CH_TBL, + /// Top back right + AUDIOENGINE_CH_TBR, + /// Top back center + AUDIOENGINE_CH_TBC, + /// Back left over center + AUDIOENGINE_CH_BLOC, + /// Back right over center + AUDIOENGINE_CH_BROC, + /// Maximum possible value, to use e.g. as size inside list + AUDIOENGINE_CH_MAX + }; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_audioengine_Defs_AudioEngineDataFormat enum AudioEngineDataFormat + /// @ingroup cpp_kodi_audioengine_Defs + /// @brief **Audio sample formats**\n + /// The bit layout of the audio data. + /// + /// LE = Little Endian, BE = Big Endian, NE = Native Endian + /// + /// For planar sample formats, each audio channel is in a separate data plane, + /// and linesize is the buffer size, in bytes, for a single plane. All data + /// planes must be the same size. For packed sample formats, only the first + /// data plane is used, and samples for each channel are interleaved. In this + /// case, linesize is the buffer size, in bytes, for the 1 plane. + /// + /// @note This is ordered from the worst to best preferred formats + /// + /// + /// ------------------------------------------------------------------------ + /// + /// **Usage example:** + /// ~~~~~~~~~~~~~{.cpp} + /// kodi::audioengine::AudioEngineFormat format; + /// format.SetDataFormat(AUDIOENGINE_FMT_FLOATP); + /// ~~~~~~~~~~~~~ + /// + ///@{ + enum AudioEngineDataFormat + { + /// To define format as invalid + AUDIOENGINE_FMT_INVALID = -1, + + /// Unsigned integer 8 bit + AUDIOENGINE_FMT_U8, + + /// Big Endian signed integer 16 bit + AUDIOENGINE_FMT_S16BE, + /// Little Endian signed integer 16 bit + AUDIOENGINE_FMT_S16LE, + /// Native Endian signed integer 16 bit + AUDIOENGINE_FMT_S16NE, + + /// Big Endian signed integer 32 bit + AUDIOENGINE_FMT_S32BE, + /// Little Endian signed integer 32 bit + AUDIOENGINE_FMT_S32LE, + /// Native Endian signed integer 32 bit + AUDIOENGINE_FMT_S32NE, + + /// Big Endian signed integer 24 bit (in 4 bytes) + AUDIOENGINE_FMT_S24BE4, + /// Little Endian signed integer 24 bit (in 4 bytes) + AUDIOENGINE_FMT_S24LE4, + /// Native Endian signed integer 24 bit (in 4 bytes) + AUDIOENGINE_FMT_S24NE4, + /// S32 with bits_per_sample < 32 + AUDIOENGINE_FMT_S24NE4MSB, + + /// Big Endian signed integer 24 bit (3 bytes) + AUDIOENGINE_FMT_S24BE3, + /// Little Endian signed integer 24 bit (3 bytes) + AUDIOENGINE_FMT_S24LE3, + /// Native Endian signed integer 24 bit (3 bytes) + AUDIOENGINE_FMT_S24NE3, + + /// Double floating point + AUDIOENGINE_FMT_DOUBLE, + /// Floating point + AUDIOENGINE_FMT_FLOAT, + + /// **Bitstream**\n + /// RAW Audio format + AUDIOENGINE_FMT_RAW, + + /// **Planar format**\n + /// Unsigned byte + AUDIOENGINE_FMT_U8P, + /// **Planar format**\n + /// Native Endian signed 16 bit + AUDIOENGINE_FMT_S16NEP, + /// **Planar format**\n + /// Native Endian signed 32 bit + AUDIOENGINE_FMT_S32NEP, + /// **Planar format**\n + /// Native Endian signed integer 24 bit (in 4 bytes) + AUDIOENGINE_FMT_S24NE4P, + /// **Planar format**\n + /// S32 with bits_per_sample < 32 + AUDIOENGINE_FMT_S24NE4MSBP, + /// **Planar format**\n + /// Native Endian signed integer 24 bit (in 3 bytes) + AUDIOENGINE_FMT_S24NE3P, + /// **Planar format**\n + /// Double floating point + AUDIOENGINE_FMT_DOUBLEP, + /// **Planar format**\n + /// Floating point + AUDIOENGINE_FMT_FLOATP, + + /// Amount of sample formats. + AUDIOENGINE_FMT_MAX + }; + ///@} + //---------------------------------------------------------------------------- + + /*! + * @brief Internal API structure which are used for data exchange between + * Kodi and addon. + */ + struct AUDIO_ENGINE_FORMAT + { + /*! The stream's data format (eg, AUDIOENGINE_FMT_S16LE) */ + enum AudioEngineDataFormat m_dataFormat; + + /*! The stream's sample rate (eg, 48000) */ + unsigned int m_sampleRate; + + /*! The encoded streams sample rate if a bitstream, otherwise undefined */ + unsigned int m_encodedRate; + + /*! The amount of used speaker channels */ + unsigned int m_channelCount; + + /*! The stream's channel layout */ + enum AudioEngineChannel m_channels[AUDIOENGINE_CH_MAX]; + + /*! The number of frames per period */ + unsigned int m_frames; + + /*! The size of one frame in bytes */ + unsigned int m_frameSize; + }; + + /* A stream handle pointer, which is only used internally by the addon stream handle */ + typedef void AEStreamHandle; + + //}}} + + //¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ + // "C" Internal interface tables for intercommunications between addon and kodi + //{{{ + + /* + * Function address structure, not need to visible on dev kit doxygen + * documentation + */ + typedef struct AddonToKodiFuncTable_kodi_audioengine + { + AEStreamHandle* (*make_stream)(void* kodiBase, + struct AUDIO_ENGINE_FORMAT* format, + unsigned int options); + void (*free_stream)(void* kodiBase, AEStreamHandle* stream); + bool (*get_current_sink_format)(void* kodiBase, struct AUDIO_ENGINE_FORMAT* sink_format); + + // Audio Engine Stream definitions + unsigned int (*aestream_get_space)(void* kodiBase, AEStreamHandle* handle); + unsigned int (*aestream_add_data)(void* kodiBase, + AEStreamHandle* handle, + uint8_t* const* data, + unsigned int offset, + unsigned int frames, + double pts, + bool hasDownmix, + double centerMixLevel); + double (*aestream_get_delay)(void* kodiBase, AEStreamHandle* handle); + bool (*aestream_is_buffering)(void* kodiBase, AEStreamHandle* handle); + double (*aestream_get_cache_time)(void* kodiBase, AEStreamHandle* handle); + double (*aestream_get_cache_total)(void* kodiBase, AEStreamHandle* handle); + void (*aestream_pause)(void* kodiBase, AEStreamHandle* handle); + void (*aestream_resume)(void* kodiBase, AEStreamHandle* handle); + void (*aestream_drain)(void* kodiBase, AEStreamHandle* handle, bool wait); + bool (*aestream_is_draining)(void* kodiBase, AEStreamHandle* handle); + bool (*aestream_is_drained)(void* kodiBase, AEStreamHandle* handle); + void (*aestream_flush)(void* kodiBase, AEStreamHandle* handle); + float (*aestream_get_volume)(void* kodiBase, AEStreamHandle* handle); + void (*aestream_set_volume)(void* kodiBase, AEStreamHandle* handle, float volume); + float (*aestream_get_amplification)(void* kodiBase, AEStreamHandle* handle); + void (*aestream_set_amplification)(void* kodiBase, AEStreamHandle* handle, float amplify); + unsigned int (*aestream_get_frame_size)(void* kodiBase, AEStreamHandle* handle); + unsigned int (*aestream_get_channel_count)(void* kodiBase, AEStreamHandle* handle); + unsigned int (*aestream_get_sample_rate)(void* kodiBase, AEStreamHandle* handle); + enum AudioEngineDataFormat (*aestream_get_data_format)(void* kodiBase, AEStreamHandle* handle); + double (*aestream_get_resample_ratio)(void* kodiBase, AEStreamHandle* handle); + void (*aestream_set_resample_ratio)(void* kodiBase, AEStreamHandle* handle, double ratio); + } AddonToKodiFuncTable_kodi_audioengine; + + //}}} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_AUDIO_ENGINE_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/filesystem.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/filesystem.h new file mode 100644 index 0000000..70f9400 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/filesystem.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_FILESYSTEM_H +#define C_API_FILESYSTEM_H + +#include +#include +#include + +#ifdef _WIN32 // windows +#ifndef _SSIZE_T_DEFINED +typedef intptr_t ssize_t; +#define _SSIZE_T_DEFINED +#endif // !_SSIZE_T_DEFINED + +// Prevent conflicts with Windows macros where have this names. +#ifdef CreateDirectory +#undef CreateDirectory +#endif // CreateDirectory +#ifdef DeleteFile +#undef DeleteFile +#endif // DeleteFile +#ifdef RemoveDirectory +#undef RemoveDirectory +#endif // RemoveDirectory +#endif // _WIN32 + +#ifdef TARGET_POSIX // Linux, Mac, FreeBSD +#include +#endif // TARGET_POSIX + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ + // "C" Definitions, structures and enumerators of filesystem + //{{{ + + //============================================================================ + /// @defgroup cpp_kodi_vfs_Defs_OpenFileFlags enum OpenFileFlags + /// @ingroup cpp_kodi_vfs_Defs + /// @brief **Flags to define way how file becomes opened**\n + /// The values can be used together, e.g. `file.Open("myfile", ADDON_READ_TRUNCATED | ADDON_READ_CHUNKED);` + /// + /// Used on @ref kodi::vfs::CFile::OpenFile(). + /// + ///@{ + typedef enum OpenFileFlags + { + /// @brief **0000 0000 0001** :\n + /// Indicate that caller can handle truncated reads, where function + /// returns before entire buffer has been filled. + ADDON_READ_TRUNCATED = 0x01, + + /// @brief **0000 0000 0010** :\n + /// Indicate that that caller support read in the minimum defined + /// chunk size, this disables internal cache then. + ADDON_READ_CHUNKED = 0x02, + + /// @brief **0000 0000 0100** :\n + /// Use cache to access this file. + ADDON_READ_CACHED = 0x04, + + /// @brief **0000 0000 1000** :\n + /// Open without caching. regardless to file type. + ADDON_READ_NO_CACHE = 0x08, + + /// @brief **0000 0001 0000** :\n + /// Calcuate bitrate for file while reading. + ADDON_READ_BITRATE = 0x10, + + /// @brief **0000 0010 0000** :\n + /// Indicate to the caller we will seek between multiple streams in + /// the file frequently. + ADDON_READ_MULTI_STREAM = 0x20, + + /// @brief **0000 0100 0000** :\n + /// indicate to the caller file is audio and/or video (and e.g. may + /// grow). + ADDON_READ_AUDIO_VIDEO = 0x40, + + /// @brief **0000 1000 0000** :\n + /// Indicate that caller will do write operations before reading. + ADDON_READ_AFTER_WRITE = 0x80, + + /// @brief **0001 0000 0000** :\n + /// Indicate that caller want to reopen a file if its already open. + ADDON_READ_REOPEN = 0x100 + } OpenFileFlags; + ///@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_vfs_Defs_CURLOptiontype enum CURLOptiontype + /// @ingroup cpp_kodi_vfs_Defs + /// @brief **CURL message types**\n + /// Used on kodi::vfs::CFile::CURLAddOption(). + /// + //@{ + typedef enum CURLOptiontype + { + /// @brief Set a general option. + ADDON_CURL_OPTION_OPTION, + + /// @brief Set a protocol option. + /// + /// The following names for *ADDON_CURL_OPTION_PROTOCOL* are possible: + /// + /// | Option name | Description + /// |------------------------------------:|:-------------------------------- + /// | `accept-charset` | Set the "accept-charset" header + /// | `acceptencoding or encoding` | Set the "accept-encoding" header + /// | `active-remote` | Set the "active-remote" header + /// | `auth` | Set the authentication method. Possible values: any, anysafe, digest, ntlm + /// | `connection-timeout` | Set the connection timeout in seconds + /// | `cookie` | Set the "cookie" header + /// | `customrequest` | Set a custom HTTP request like DELETE + /// | `noshout` | Set to true if kodi detects a stream as shoutcast by mistake. + /// | `postdata` | Set the post body (value needs to be base64 encoded). (Implicitly sets the request to POST) + /// | `referer` | Set the "referer" header + /// | `user-agent` | Set the "user-agent" header + /// | `seekable` | Set the stream seekable. 1: enable, 0: disable + /// | `sslcipherlist` | Set list of accepted SSL ciphers. + /// + ADDON_CURL_OPTION_PROTOCOL, + + /// @brief Set User and password + ADDON_CURL_OPTION_CREDENTIALS, + + /// @brief Add a Header + ADDON_CURL_OPTION_HEADER + } CURLOptiontype; + //@} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_vfs_Defs_FilePropertyTypes enum FilePropertyTypes + /// @ingroup cpp_kodi_vfs_Defs + /// @brief **File property types**\n + /// Mostly to read internet sources. + /// + /// Used on kodi::vfs::CFile::GetPropertyValue() and kodi::vfs::CFile::GetPropertyValues(). + /// + //@{ + typedef enum FilePropertyTypes + { + /// @brief Get protocol response line. + ADDON_FILE_PROPERTY_RESPONSE_PROTOCOL, + /// @brief Get a response header. + ADDON_FILE_PROPERTY_RESPONSE_HEADER, + /// @brief Get file content type. + ADDON_FILE_PROPERTY_CONTENT_TYPE, + /// @brief Get file content charset. + ADDON_FILE_PROPERTY_CONTENT_CHARSET, + /// @brief Get file mime type. + ADDON_FILE_PROPERTY_MIME_TYPE, + /// @brief Get file effective URL (last one if redirected). + ADDON_FILE_PROPERTY_EFFECTIVE_URL + } FilePropertyTypes; + //@} + //---------------------------------------------------------------------------- + + //}}} + + //¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ + // "C" Internal interface tables for intercommunications between addon and kodi + //{{{ + + struct KODI_HTTP_HEADER + { + void* handle; + + char* (*get_value)(void* kodiBase, void* handle, const char* param); + char** (*get_values)(void* kodiBase, void* handle, const char* param, int* length); + char* (*get_header)(void* kodiBase, void* handle); + char* (*get_mime_type)(void* kodiBase, void* handle); + char* (*get_charset)(void* kodiBase, void* handle); + char* (*get_proto_line)(void* kodiBase, void* handle); + }; + + struct STAT_STRUCTURE + { + /// ID of device containing file + uint32_t deviceId; + /// Total size, in bytes + uint64_t size; + /// Time of last access + time_t accessTime; + /// Time of last modification + time_t modificationTime; + /// Time of last status change + time_t statusTime; + /// The stat url is a directory + bool isDirectory; + /// The stat url is a symbolic link + bool isSymLink; + /// The stat url is block special + bool isBlock; + /// The stat url is character special + bool isCharacter; + /// The stat url is FIFO special + bool isFifo; + /// The stat url is regular + bool isRegular; + /// The stat url is socket + bool isSocket; + /// The file serial number, which distinguishes this file from all other files on the same + /// device. + uint64_t fileSerialNumber; + }; + + struct VFS_CACHE_STATUS_DATA + { + uint64_t forward; + unsigned int maxrate; + unsigned int currate; + bool lowspeed; + }; + + struct VFSProperty + { + char* name; + char* val; + }; + + struct VFSDirEntry + { + char* label; //!< item label + char* title; //!< item title + char* path; //!< item path + unsigned int num_props; //!< Number of properties attached to item + struct VFSProperty* properties; //!< Properties + time_t date_time; //!< file creation date & time + bool folder; //!< Item is a folder + uint64_t size; //!< Size of file represented by item + }; + + typedef struct AddonToKodiFuncTable_kodi_filesystem + { + bool (*can_open_directory)(void* kodiBase, const char* url); + bool (*create_directory)(void* kodiBase, const char* path); + bool (*remove_directory)(void* kodiBase, const char* path); + bool (*directory_exists)(void* kodiBase, const char* path); + bool (*get_directory)(void* kodiBase, + const char* path, + const char* mask, + struct VFSDirEntry** items, + unsigned int* num_items); + void (*free_directory)(void* kodiBase, struct VFSDirEntry* items, unsigned int num_items); + + bool (*file_exists)(void* kodiBase, const char* filename, bool useCache); + bool (*stat_file)(void* kodiBase, const char* filename, struct STAT_STRUCTURE* buffer); + bool (*delete_file)(void* kodiBase, const char* filename); + bool (*rename_file)(void* kodiBase, const char* filename, const char* newFileName); + bool (*copy_file)(void* kodiBase, const char* filename, const char* dest); + + char* (*get_file_md5)(void* kodiBase, const char* filename); + char* (*get_cache_thumb_name)(void* kodiBase, const char* filename); + char* (*make_legal_filename)(void* kodiBase, const char* filename); + char* (*make_legal_path)(void* kodiBase, const char* path); + char* (*translate_special_protocol)(void* kodiBase, const char* strSource); + bool (*is_internet_stream)(void* kodiBase, const char* path, bool strictCheck); + bool (*is_on_lan)(void* kodiBase, const char* path); + bool (*is_remote)(void* kodiBase, const char* path); + bool (*is_local)(void* kodiBase, const char* path); + bool (*is_url)(void* kodiBase, const char* path); + bool (*get_http_header)(void* kodiBase, const char* url, struct KODI_HTTP_HEADER* headers); + bool (*get_mime_type)(void* kodiBase, const char* url, char** content, const char* useragent); + bool (*get_content_type)(void* kodiBase, + const char* url, + char** content, + const char* useragent); + bool (*get_cookies)(void* kodiBase, const char* url, char** cookies); + bool (*http_header_create)(void* kodiBase, struct KODI_HTTP_HEADER* headers); + void (*http_header_free)(void* kodiBase, struct KODI_HTTP_HEADER* headers); + + void* (*open_file)(void* kodiBase, const char* filename, unsigned int flags); + void* (*open_file_for_write)(void* kodiBase, const char* filename, bool overwrite); + ssize_t (*read_file)(void* kodiBase, void* file, void* ptr, size_t size); + bool (*read_file_string)(void* kodiBase, void* file, char* szLine, int iLineLength); + ssize_t (*write_file)(void* kodiBase, void* file, const void* ptr, size_t size); + void (*flush_file)(void* kodiBase, void* file); + int64_t (*seek_file)(void* kodiBase, void* file, int64_t position, int whence); + int (*truncate_file)(void* kodiBase, void* file, int64_t size); + int64_t (*get_file_position)(void* kodiBase, void* file); + int64_t (*get_file_length)(void* kodiBase, void* file); + double (*get_file_download_speed)(void* kodiBase, void* file); + void (*close_file)(void* kodiBase, void* file); + int (*get_file_chunk_size)(void* kodiBase, void* file); + bool (*io_control_get_seek_possible)(void* kodiBase, void* file); + bool (*io_control_get_cache_status)(void* kodiBase, + void* file, + struct VFS_CACHE_STATUS_DATA* status); + bool (*io_control_set_cache_rate)(void* kodiBase, void* file, unsigned int rate); + bool (*io_control_set_retry)(void* kodiBase, void* file, bool retry); + char** (*get_property_values)( + void* kodiBase, void* file, int type, const char* name, int* numValues); + + void* (*curl_create)(void* kodiBase, const char* url); + bool (*curl_add_option)( + void* kodiBase, void* file, int type, const char* name, const char* value); + bool (*curl_open)(void* kodiBase, void* file, unsigned int flags); + + bool (*get_disk_space)( + void* kodiBase, const char* path, uint64_t* capacity, uint64_t* free, uint64_t* available); + bool (*remove_directory_recursive)(void* kodiBase, const char* path); + } AddonToKodiFuncTable_kodi_filesystem; + + //}}} + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_FILESYSTEM_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/general.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/general.h new file mode 100644 index 0000000..12afd02 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/general.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GENERAL_H +#define C_API_GENERAL_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// \ingroup cpp_kodi_Defs + /// @brief For kodi::CurrentKeyboardLayout used defines + /// + typedef enum StdKbButtons + { + /// The quantity of buttons per row on Kodi's standard keyboard + STD_KB_BUTTONS_PER_ROW = 20, + /// The quantity of rows on Kodi's standard keyboard + STD_KB_BUTTONS_MAX_ROWS = 4, + /// Keyboard layout type, this for initial standard + STD_KB_MODIFIER_KEY_NONE = 0x00, + /// Keyboard layout type, this for shift controled layout (uppercase) + STD_KB_MODIFIER_KEY_SHIFT = 0x01, + /// Keyboard layout type, this to show symbols + STD_KB_MODIFIER_KEY_SYMBOL = 0x02 + } StdKbButtons; + //---------------------------------------------------------------------------- + + //============================================================================ + /// \ingroup cpp_kodi_Defs + /// @brief For kodi::QueueNotification() used message types + /// + typedef enum QueueMsg + { + /// Show info notification message + QUEUE_INFO, + /// Show warning notification message + QUEUE_WARNING, + /// Show error notification message + QUEUE_ERROR, + /// Show with own given image and parts if set on values + QUEUE_OWN_STYLE + } QueueMsg; + //---------------------------------------------------------------------------- + + //============================================================================ + /// \ingroup cpp_kodi_Defs + /// @brief Format codes to get string from them. + /// + /// Used on kodi::GetLanguage(). + /// + typedef enum LangFormats + { + /// two letter code as defined in ISO 639-1 + LANG_FMT_ISO_639_1, + /// three letter code as defined in ISO 639-2/T or ISO 639-2/B + LANG_FMT_ISO_639_2, + /// full language name in English + LANG_FMT_ENGLISH_NAME + } LangFormats; + //---------------------------------------------------------------------------- + + /* + * For interface between add-on and kodi. + * + * This structure defines the addresses of functions stored inside Kodi which + * are then available for the add-on to call + * + * All function pointers there are used by the C++ interface functions below. + * You find the set of them on xbmc/addons/interfaces/General.cpp + * + * Note: For add-on development itself this is not needed + */ + typedef struct AddonKeyboardKeyTable + { + char* keys[STD_KB_BUTTONS_MAX_ROWS][STD_KB_BUTTONS_PER_ROW]; + } AddonKeyboardKeyTable; + typedef struct AddonToKodiFuncTable_kodi + { + char* (*get_addon_info)(void* kodiBase, const char* id); + bool (*open_settings_dialog)(void* kodiBase); + char* (*unknown_to_utf8)(void* kodiBase, const char* source, bool* ret, bool failOnBadChar); + char* (*get_localized_string)(void* kodiBase, long label_id); + char* (*get_language)(void* kodiBase, int format, bool region); + bool (*queue_notification)(void* kodiBase, + int type, + const char* header, + const char* message, + const char* imageFile, + unsigned int displayTime, + bool withSound, + unsigned int messageTime); + void (*get_md5)(void* kodiBase, const char* text, char* md5); + char* (*get_temp_path)(void* kodiBase); + char* (*get_region)(void* kodiBase, const char* id); + void (*get_free_mem)(void* kodiBase, long* free, long* total, bool as_bytes); + int (*get_global_idle_time)(void* kodiBase); + bool (*is_addon_avilable)(void* kodiBase, const char* id, char** version, bool* enabled); + void (*kodi_version)(void* kodiBase, + char** compile_name, + int* major, + int* minor, + char** revision, + char** tag, + char** tagversion); + char* (*get_current_skin_id)(void* kodiBase); + bool (*get_keyboard_layout)(void* kodiBase, + char** layout_name, + int modifier_key, + struct AddonKeyboardKeyTable* layout); + bool (*change_keyboard_layout)(void* kodiBase, char** layout_name); + } AddonToKodiFuncTable_kodi; + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GENERAL_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/CMakeLists.txt new file mode 100644 index 0000000..53c4e60 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/CMakeLists.txt @@ -0,0 +1,8 @@ +set(HEADERS definitions.h + general.h + list_item.h + window.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_c-api_gui) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/CMakeLists.txt new file mode 100644 index 0000000..2e6cd53 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/CMakeLists.txt @@ -0,0 +1,16 @@ +set(HEADERS button.h + edit.h + fade_label.h + image.h + label.h + progress.h + radio_button.h + rendering.h + settings_slider.h + slider.h + spin.h + text_box.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_c-api_gui_controls) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/button.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/button.h new file mode 100644 index 0000000..84fd822 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/button.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_CONTROLS_BUTTON_H +#define C_API_GUI_CONTROLS_BUTTON_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_control_button + { + void (*set_visible)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + void (*set_enabled)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool enabled); + void (*set_label)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* label); + char* (*get_label)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_label2)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* label); + char* (*get_label2)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + } AddonToKodiFuncTable_kodi_gui_control_button; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_CONTROLS_BUTTON_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/edit.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/edit.h new file mode 100644 index 0000000..ca38b27 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/edit.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_CONTROLS_EDIT_H +#define C_API_GUI_CONTROLS_EDIT_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CEdit_Defs + /// @{ + /// @anchor AddonGUIInputType + /// @brief Text input types used on kodi::gui::controls::CEdit + enum AddonGUIInputType + { + /// Text inside edit control only readable + ADDON_INPUT_TYPE_READONLY = -1, + /// Normal text entries + ADDON_INPUT_TYPE_TEXT = 0, + /// To use on edit control only numeric numbers + ADDON_INPUT_TYPE_NUMBER, + /// To insert seconds + ADDON_INPUT_TYPE_SECONDS, + /// To insert time + ADDON_INPUT_TYPE_TIME, + /// To insert a date + ADDON_INPUT_TYPE_DATE, + /// Used for write in IP addresses + ADDON_INPUT_TYPE_IPADDRESS, + /// Text field used as password entry field with not visible text + ADDON_INPUT_TYPE_PASSWORD, + /// Text field used as password entry field with not visible text but + /// returned as MD5 value + ADDON_INPUT_TYPE_PASSWORD_MD5, + /// Use text field for search purpose + ADDON_INPUT_TYPE_SEARCH, + /// Text field as filter + ADDON_INPUT_TYPE_FILTER, + /// + ADDON_INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW + }; + /// @} + //---------------------------------------------------------------------------- + + typedef struct AddonToKodiFuncTable_kodi_gui_control_edit + { + void (*set_visible)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + void (*set_enabled)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool enabled); + void (*set_label)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* label); + char* (*get_label)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_text)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* text); + char* (*get_text)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_cursor_position)(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + unsigned int position); + unsigned int (*get_cursor_position)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_input_type)(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + int type, + const char* heading); + } AddonToKodiFuncTable_kodi_gui_control_edit; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_CONTROLS_EDIT_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/fade_label.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/fade_label.h new file mode 100644 index 0000000..fea014b --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/fade_label.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_CONTROLS_FADE_LABEL_H +#define C_API_GUI_CONTROLS_FADE_LABEL_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_control_fade_label + { + void (*set_visible)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + void (*add_label)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* text); + char* (*get_label)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_scrolling)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool scroll); + void (*reset)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + } AddonToKodiFuncTable_kodi_gui_control_fade_label; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_CONTROLS_FADE_LABEL_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/image.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/image.h new file mode 100644 index 0000000..4a46e6d --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/image.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_CONTROLS_IMAGE_H +#define C_API_GUI_CONTROLS_IMAGE_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_control_image + { + void (*set_visible)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + void (*set_filename)(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* filename, + bool use_cache); + void (*set_color_diffuse)(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + uint32_t color_diffuse); + } AddonToKodiFuncTable_kodi_gui_control_image; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_CONTROLS_IMAGE_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/label.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/label.h new file mode 100644 index 0000000..d8a9fe4 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/label.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_CONTROLS_LABEL_H +#define C_API_GUI_CONTROLS_LABEL_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_control_label + { + void (*set_visible)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + void (*set_label)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* text); + char* (*get_label)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + } AddonToKodiFuncTable_kodi_gui_control_label; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_CONTROLS_LABEL_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/progress.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/progress.h new file mode 100644 index 0000000..88638e0 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/progress.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_CONTROLS_PROGRESS_H +#define C_API_GUI_CONTROLS_PROGRESS_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_control_progress + { + void (*set_visible)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + void (*set_percentage)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, float percent); + float (*get_percentage)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + } AddonToKodiFuncTable_kodi_gui_control_progress; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_CONTROLS_PROGRESS_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/radio_button.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/radio_button.h new file mode 100644 index 0000000..a672d95 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/radio_button.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_CONTROLS_RADIO_BUTTON_H +#define C_API_GUI_CONTROLS_RADIO_BUTTON_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_control_radio_button + { + void (*set_visible)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + void (*set_enabled)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool enabled); + void (*set_label)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* text); + char* (*get_label)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_selected)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool selected); + bool (*is_selected)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + } AddonToKodiFuncTable_kodi_gui_control_radio_button; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_CONTROLS_RADIO_BUTTON_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/rendering.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/rendering.h new file mode 100644 index 0000000..d4053a6 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/rendering.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_CONTROLS_RENDERING_H +#define C_API_GUI_CONTROLS_RENDERING_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_control_rendering + { + void (*set_callbacks)( + KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + KODI_GUI_CLIENT_HANDLE clienthandle, + bool (*createCB)(KODI_GUI_CLIENT_HANDLE, int, int, int, int, ADDON_HARDWARE_CONTEXT), + void (*renderCB)(KODI_GUI_CLIENT_HANDLE), + void (*stopCB)(KODI_GUI_CLIENT_HANDLE), + bool (*dirtyCB)(KODI_GUI_CLIENT_HANDLE)); + void (*destroy)(void* kodiBase, KODI_GUI_CONTROL_HANDLE handle); + } AddonToKodiFuncTable_kodi_gui_control_rendering; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_CONTROLS_RENDERING_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/settings_slider.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/settings_slider.h new file mode 100644 index 0000000..2cbc972 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/settings_slider.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_CONTROLS_SETTINGS_SLIDER_H +#define C_API_GUI_CONTROLS_SETTINGS_SLIDER_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_control_settings_slider + { + void (*set_visible)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + void (*set_enabled)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool enabled); + void (*set_text)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* label); + void (*reset)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_int_range)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int start, int end); + void (*set_int_value)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int value); + int (*get_int_value)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_int_interval)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int interval); + void (*set_percentage)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, float percent); + float (*get_percentage)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_float_range)(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float start, + float end); + void (*set_float_value)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, float value); + float (*get_float_value)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_float_interval)(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float interval); + } AddonToKodiFuncTable_kodi_gui_control_settings_slider; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_CONTROLS_SETTINGS_SLIDER_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/slider.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/slider.h new file mode 100644 index 0000000..0a67208 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/slider.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_CONTROLS_SLIDER_H +#define C_API_GUI_CONTROLS_SLIDER_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_control_slider + { + void (*set_visible)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + void (*set_enabled)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool enabled); + void (*reset)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + char* (*get_description)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_int_range)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int start, int end); + void (*set_int_value)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int value); + int (*get_int_value)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_int_interval)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int interval); + void (*set_percentage)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, float percent); + float (*get_percentage)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_float_range)(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float start, + float end); + void (*set_float_value)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, float value); + float (*get_float_value)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_float_interval)(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float interval); + } AddonToKodiFuncTable_kodi_gui_control_slider; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_CONTROLS_SLIDER_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/spin.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/spin.h new file mode 100644 index 0000000..d5e5c86 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/spin.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_CONTROLS_SPIN_H +#define C_API_GUI_CONTROLS_SPIN_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_control_spin + { + void (*set_visible)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + void (*set_enabled)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool enabled); + void (*set_text)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* text); + void (*reset)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_type)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int type); + void (*add_string_label)(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* label, + const char* value); + void (*set_string_value)(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* value); + char* (*get_string_value)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*add_int_label)(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + const char* label, + int value); + void (*set_int_range)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int start, int end); + void (*set_int_value)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int value); + int (*get_int_value)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_float_range)(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float start, + float end); + void (*set_float_value)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, float value); + float (*get_float_value)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_float_interval)(KODI_HANDLE kodiBase, + KODI_GUI_CONTROL_HANDLE handle, + float interval); + } AddonToKodiFuncTable_kodi_gui_control_spin; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_CONTROLS_SPIN_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/text_box.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/text_box.h new file mode 100644 index 0000000..276d04c --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/controls/text_box.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_CONTROLS_TEXT_BOX_H +#define C_API_GUI_CONTROLS_TEXT_BOX_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_control_text_box + { + void (*set_visible)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, bool visible); + void (*reset)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*set_text)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, const char* text); + char* (*get_text)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle); + void (*scroll)(KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, unsigned int scroll); + void (*set_auto_scrolling)( + KODI_HANDLE kodiBase, KODI_GUI_CONTROL_HANDLE handle, int delay, int time, int repeat); + } AddonToKodiFuncTable_kodi_gui_control_text_box; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_CONTROLS_TEXT_BOX_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/definitions.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/definitions.h new file mode 100644 index 0000000..ec60bc2 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/definitions.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_DEFINITIONS_H +#define C_API_GUI_DEFINITIONS_H + +#include "../addon_base.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef void* KODI_GUI_HANDLE; + typedef void* KODI_GUI_CLIENT_HANDLE; + typedef void* KODI_GUI_CONTROL_HANDLE; + typedef void* KODI_GUI_LISTITEM_HANDLE; + typedef void* KODI_GUI_WINDOW_HANDLE; + + struct AddonToKodiFuncTable_kodi_gui_general; + struct AddonToKodiFuncTable_kodi_gui_control_button; + struct AddonToKodiFuncTable_kodi_gui_control_edit; + struct AddonToKodiFuncTable_kodi_gui_control_fade_label; + struct AddonToKodiFuncTable_kodi_gui_control_label; + struct AddonToKodiFuncTable_kodi_gui_control_image; + struct AddonToKodiFuncTable_kodi_gui_control_progress; + struct AddonToKodiFuncTable_kodi_gui_control_radio_button; + struct AddonToKodiFuncTable_kodi_gui_control_rendering; + struct AddonToKodiFuncTable_kodi_gui_control_settings_slider; + struct AddonToKodiFuncTable_kodi_gui_control_slider; + struct AddonToKodiFuncTable_kodi_gui_control_spin; + struct AddonToKodiFuncTable_kodi_gui_control_text_box; + struct AddonToKodiFuncTable_kodi_gui_dialogContextMenu; + struct AddonToKodiFuncTable_kodi_gui_dialogExtendedProgress; + struct AddonToKodiFuncTable_kodi_gui_dialogFileBrowser; + struct AddonToKodiFuncTable_kodi_gui_dialogKeyboard; + struct AddonToKodiFuncTable_kodi_gui_dialogNumeric; + struct AddonToKodiFuncTable_kodi_gui_dialogOK; + struct AddonToKodiFuncTable_kodi_gui_dialogProgress; + struct AddonToKodiFuncTable_kodi_gui_dialogSelect; + struct AddonToKodiFuncTable_kodi_gui_dialogTextViewer; + struct AddonToKodiFuncTable_kodi_gui_dialogYesNo; + struct AddonToKodiFuncTable_kodi_gui_listItem; + struct AddonToKodiFuncTable_kodi_gui_window; + + typedef struct AddonToKodiFuncTable_kodi_gui + { + struct AddonToKodiFuncTable_kodi_gui_general* general; + struct AddonToKodiFuncTable_kodi_gui_control_button* control_button; + struct AddonToKodiFuncTable_kodi_gui_control_edit* control_edit; + struct AddonToKodiFuncTable_kodi_gui_control_fade_label* control_fade_label; + struct AddonToKodiFuncTable_kodi_gui_control_label* control_label; + struct AddonToKodiFuncTable_kodi_gui_control_image* control_image; + struct AddonToKodiFuncTable_kodi_gui_control_progress* control_progress; + struct AddonToKodiFuncTable_kodi_gui_control_radio_button* control_radio_button; + struct AddonToKodiFuncTable_kodi_gui_control_rendering* control_rendering; + struct AddonToKodiFuncTable_kodi_gui_control_settings_slider* control_settings_slider; + struct AddonToKodiFuncTable_kodi_gui_control_slider* control_slider; + struct AddonToKodiFuncTable_kodi_gui_control_spin* control_spin; + struct AddonToKodiFuncTable_kodi_gui_control_text_box* control_text_box; + KODI_HANDLE control_dummy1; + KODI_HANDLE control_dummy2; + KODI_HANDLE control_dummy3; + KODI_HANDLE control_dummy4; + KODI_HANDLE control_dummy5; + KODI_HANDLE control_dummy6; + KODI_HANDLE control_dummy7; + KODI_HANDLE control_dummy8; + KODI_HANDLE control_dummy9; + KODI_HANDLE control_dummy10; /* This and above used to add new controls */ + struct AddonToKodiFuncTable_kodi_gui_dialogContextMenu* dialogContextMenu; + struct AddonToKodiFuncTable_kodi_gui_dialogExtendedProgress* dialogExtendedProgress; + struct AddonToKodiFuncTable_kodi_gui_dialogFileBrowser* dialogFileBrowser; + struct AddonToKodiFuncTable_kodi_gui_dialogKeyboard* dialogKeyboard; + struct AddonToKodiFuncTable_kodi_gui_dialogNumeric* dialogNumeric; + struct AddonToKodiFuncTable_kodi_gui_dialogOK* dialogOK; + struct AddonToKodiFuncTable_kodi_gui_dialogProgress* dialogProgress; + struct AddonToKodiFuncTable_kodi_gui_dialogSelect* dialogSelect; + struct AddonToKodiFuncTable_kodi_gui_dialogTextViewer* dialogTextViewer; + struct AddonToKodiFuncTable_kodi_gui_dialogYesNo* dialogYesNo; + KODI_HANDLE dialog_dummy1; + KODI_HANDLE dialog_dummy2; + KODI_HANDLE dialog_dummy3; + KODI_HANDLE dialog_dummy4; + KODI_HANDLE dialog_dummy5; + KODI_HANDLE dialog_dummy6; + KODI_HANDLE dialog_dummy7; + KODI_HANDLE dialog_dummy8; + KODI_HANDLE dialog_dummy9; + KODI_HANDLE dialog_dummy10; /* This and above used to add new dialogs */ + struct AddonToKodiFuncTable_kodi_gui_listItem* listItem; + struct AddonToKodiFuncTable_kodi_gui_window* window; + } AddonToKodiFuncTable_kodi_gui; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_DEFINITIONS_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/CMakeLists.txt new file mode 100644 index 0000000..bc35e91 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/CMakeLists.txt @@ -0,0 +1,14 @@ +set(HEADERS context_menu.h + extended_progress.h + filebrowser.h + keyboard.h + numeric.h + ok.h + progress.h + select.h + text_viewer.h + yes_no.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_c-api_gui_dialogs) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/context_menu.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/context_menu.h new file mode 100644 index 0000000..8bb5370 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/context_menu.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_DIALOGS_CONTEXT_MENU_H +#define C_API_GUI_DIALOGS_CONTEXT_MENU_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_dialogContextMenu + { + int (*open)(KODI_HANDLE kodiBase, + const char* heading, + const char* entries[], + unsigned int size); + } AddonToKodiFuncTable_kodi_gui_dialogContextMenu; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_DIALOGS_CONTEXT_MENU_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/extended_progress.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/extended_progress.h new file mode 100644 index 0000000..e53588f --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/extended_progress.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_DIALOGS_EXTENDED_PROGRESS_H +#define C_API_GUI_DIALOGS_EXTENDED_PROGRESS_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_dialogExtendedProgress + { + KODI_GUI_HANDLE (*new_dialog)(KODI_HANDLE kodiBase, const char* title); + void (*delete_dialog)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + char* (*get_title)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + void (*set_title)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, const char* title); + char* (*get_text)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + void (*set_text)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, const char* text); + bool (*is_finished)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + void (*mark_finished)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + float (*get_percentage)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + void (*set_percentage)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, float percentage); + void (*set_progress)(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + int currentItem, + int itemCount); + } AddonToKodiFuncTable_kodi_gui_dialogExtendedProgress; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_DIALOGS_EXTENDED_PROGRESS_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/filebrowser.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/filebrowser.h new file mode 100644 index 0000000..7ae4fac --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/filebrowser.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_DIALOGS_FILEBROWSER_H +#define C_API_GUI_DIALOGS_FILEBROWSER_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_dialogFileBrowser + { + bool (*show_and_get_directory)(KODI_HANDLE kodiBase, + const char* shares, + const char* heading, + const char* path_in, + char** path_out, + bool writeOnly); + bool (*show_and_get_file)(KODI_HANDLE kodiBase, + const char* shares, + const char* mask, + const char* heading, + const char* path_in, + char** path_out, + bool use_thumbs, + bool use_file_directories); + bool (*show_and_get_file_from_dir)(KODI_HANDLE kodiBase, + const char* directory, + const char* mask, + const char* heading, + const char* path_in, + char** path_out, + bool use_thumbs, + bool use_file_directories, + bool singleList); + bool (*show_and_get_file_list)(KODI_HANDLE kodiBase, + const char* shares, + const char* mask, + const char* heading, + char*** file_list, + unsigned int* entries, + bool use_thumbs, + bool use_file_directories); + bool (*show_and_get_source)(KODI_HANDLE kodiBase, + const char* path_in, + char** path_out, + bool allow_network_shares, + const char* additional_share, + const char* type); + bool (*show_and_get_image)(KODI_HANDLE kodiBase, + const char* shares, + const char* heading, + const char* path_in, + char** path_out); + bool (*show_and_get_image_list)(KODI_HANDLE kodiBase, + const char* shares, + const char* heading, + char*** file_list, + unsigned int* entries); + void (*clear_file_list)(KODI_HANDLE kodiBase, char*** file_list, unsigned int entries); + } AddonToKodiFuncTable_kodi_gui_dialogFileBrowser; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_DIALOGS_FILEBROWSER_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/keyboard.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/keyboard.h new file mode 100644 index 0000000..fc3c34c --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/keyboard.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_DIALOGS_KEYBOARD_H +#define C_API_GUI_DIALOGS_KEYBOARD_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_dialogKeyboard + { + bool (*show_and_get_input_with_head)(KODI_HANDLE kodiBase, + const char* text_in, + char** text_out, + const char* heading, + bool allow_empty_result, + bool hiddenInput, + unsigned int auto_close_ms); + bool (*show_and_get_input)(KODI_HANDLE kodiBase, + const char* text_in, + char** text_out, + bool allow_empty_result, + unsigned int auto_close_ms); + bool (*show_and_get_new_password_with_head)(KODI_HANDLE kodiBase, + const char* password_in, + char** password_out, + const char* heading, + bool allow_empty_result, + unsigned int auto_close_ms); + bool (*show_and_get_new_password)(KODI_HANDLE kodiBase, + const char* password_in, + char** password_out, + unsigned int auto_close_ms); + bool (*show_and_verify_new_password_with_head)(KODI_HANDLE kodiBase, + char** password_out, + const char* heading, + bool allow_empty_result, + unsigned int auto_close_ms); + bool (*show_and_verify_new_password)(KODI_HANDLE kodiBase, + char** password_out, + unsigned int auto_close_ms); + int (*show_and_verify_password)(KODI_HANDLE kodiBase, + const char* password_in, + char** password_out, + const char* heading, + int retries, + unsigned int auto_close_ms); + bool (*show_and_get_filter)(KODI_HANDLE kodiBase, + const char* text_in, + char** text_out, + bool searching, + unsigned int auto_close_ms); + bool (*send_text_to_active_keyboard)(KODI_HANDLE kodiBase, + const char* text, + bool close_keyboard); + bool (*is_keyboard_activated)(KODI_HANDLE kodiBase); + } AddonToKodiFuncTable_kodi_gui_dialogKeyboard; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_DIALOGS_KEYBOARD_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/numeric.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/numeric.h new file mode 100644 index 0000000..df23cd7 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/numeric.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_DIALOGS_NUMERIC_H +#define C_API_GUI_DIALOGS_NUMERIC_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_dialogNumeric + { + bool (*show_and_verify_new_password)(KODI_HANDLE kodiBase, char** password); + int (*show_and_verify_password)(KODI_HANDLE kodiBase, + const char* password, + const char* heading, + int retries); + bool (*show_and_verify_input)(KODI_HANDLE kodiBase, + const char* verify_in, + char** verify_out, + const char* heading, + bool verify_input); + bool (*show_and_get_time)(KODI_HANDLE kodiBase, struct tm* time, const char* heading); + bool (*show_and_get_date)(KODI_HANDLE kodiBase, struct tm* date, const char* heading); + bool (*show_and_get_ip_address)(KODI_HANDLE kodiBase, + const char* ip_address_in, + char** ip_address_out, + const char* heading); + bool (*show_and_get_number)(KODI_HANDLE kodiBase, + const char* input_in, + char** input_out, + const char* heading, + unsigned int auto_close_ms); + bool (*show_and_get_seconds)(KODI_HANDLE kodiBase, + const char* time_in, + char** time_out, + const char* heading); + } AddonToKodiFuncTable_kodi_gui_dialogNumeric; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_DIALOGS_NUMERIC_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/ok.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/ok.h new file mode 100644 index 0000000..9f37051 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/ok.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_DIALOGS_OK_H +#define C_API_GUI_DIALOGS_OK_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_dialogOK + { + void (*show_and_get_input_single_text)(KODI_HANDLE kodiBase, + const char* heading, + const char* text); + void (*show_and_get_input_line_text)(KODI_HANDLE kodiBase, + const char* heading, + const char* line0, + const char* line1, + const char* line2); + } AddonToKodiFuncTable_kodi_gui_dialogOK; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_DIALOGS_OK_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/progress.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/progress.h new file mode 100644 index 0000000..f1c8972 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/progress.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_DIALOGS_PROGRESS_H +#define C_API_GUI_DIALOGS_PROGRESS_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_dialogProgress + { + KODI_GUI_HANDLE (*new_dialog)(KODI_HANDLE kodiBase); + void (*delete_dialog)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + void (*open)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + void (*set_heading)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, const char* heading); + void (*set_line)(KODI_HANDLE kodiBase, + KODI_GUI_HANDLE handle, + unsigned int lineNo, + const char* line); + void (*set_can_cancel)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, bool canCancel); + bool (*is_canceled)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + void (*set_percentage)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, int percentage); + int (*get_percentage)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + void (*show_progress_bar)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, bool pnOff); + void (*set_progress_max)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, int max); + void (*set_progress_advance)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle, int nSteps); + bool (*abort)(KODI_HANDLE kodiBase, KODI_GUI_HANDLE handle); + } AddonToKodiFuncTable_kodi_gui_dialogProgress; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_DIALOGS_PROGRESS_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/select.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/select.h new file mode 100644 index 0000000..41ab82f --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/select.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_DIALOGS_SELECT_H +#define C_API_GUI_DIALOGS_SELECT_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_dialogSelect + { + int (*open)(KODI_HANDLE kodiBase, + const char* heading, + const char* entries[], + unsigned int size, + int selected, + unsigned int autoclose); + bool (*open_multi_select)(KODI_HANDLE kodiBase, + const char* heading, + const char* entryIDs[], + const char* entryNames[], + bool entriesSelected[], + unsigned int size, + unsigned int autoclose); + } AddonToKodiFuncTable_kodi_gui_dialogSelect; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_DIALOGS_SELECT_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/text_viewer.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/text_viewer.h new file mode 100644 index 0000000..eb38b0b --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/text_viewer.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_DIALOGS_TEXT_VIEWER_H +#define C_API_GUI_DIALOGS_TEXT_VIEWER_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_dialogTextViewer + { + void (*open)(KODI_HANDLE kodiBase, const char* heading, const char* text); + } AddonToKodiFuncTable_kodi_gui_dialogTextViewer; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_DIALOGS_TEXT_VIEWER_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/yes_no.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/yes_no.h new file mode 100644 index 0000000..01ed806 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/dialogs/yes_no.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_DIALOGS_YES_NO_H +#define C_API_GUI_DIALOGS_YES_NO_H + +#include "../definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_dialogYesNo + { + bool (*show_and_get_input_single_text)(KODI_HANDLE kodiBase, + const char* heading, + const char* text, + bool* canceled, + const char* noLabel, + const char* yesLabel); + bool (*show_and_get_input_line_text)(KODI_HANDLE kodiBase, + const char* heading, + const char* line0, + const char* line1, + const char* line2, + const char* noLabel, + const char* yesLabel); + bool (*show_and_get_input_line_button_text)(KODI_HANDLE kodiBase, + const char* heading, + const char* line0, + const char* line1, + const char* line2, + bool* canceled, + const char* noLabel, + const char* yesLabel); + } AddonToKodiFuncTable_kodi_gui_dialogYesNo; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_DIALOGS_YES_NO_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/general.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/general.h new file mode 100644 index 0000000..d0d256c --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/general.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_GENERAL_H +#define C_API_GUI_GENERAL_H + +#include "definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_general + { + void (*lock)(); + void (*unlock)(); + int (*get_screen_height)(KODI_HANDLE kodiBase); + int (*get_screen_width)(KODI_HANDLE kodiBase); + int (*get_video_resolution)(KODI_HANDLE kodiBase); + int (*get_current_window_dialog_id)(KODI_HANDLE kodiBase); + int (*get_current_window_id)(KODI_HANDLE kodiBase); + ADDON_HARDWARE_CONTEXT (*get_hw_context)(KODI_HANDLE kodiBase); + } AddonToKodiFuncTable_kodi_gui_general; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_GENERAL_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input/CMakeLists.txt new file mode 100644 index 0000000..c0bbd11 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input/CMakeLists.txt @@ -0,0 +1,5 @@ +set(HEADERS action_ids.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_c-api_gui_input) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input/action_ids.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input/action_ids.h new file mode 100644 index 0000000..274f3d9 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/input/action_ids.h @@ -0,0 +1,763 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_ACTION_IDS_H +#define C_API_GUI_ACTION_IDS_H + +/// @defgroup cpp_kodi_gui_Defs_action_ids enum ADDON_ACTION +/// @ingroup cpp_kodi_gui_Defs +/// @brief **Action Id's**\n +/// Actions that we have defined. +/// +///@{ +enum ADDON_ACTION +{ + /// @ingroup cpp_kodi_gui_key_action_ids + ///@{ + + /// @brief `0 `: None. + ADDON_ACTION_NONE = 0, + + /// @brief `1 `: Move left. + ADDON_ACTION_MOVE_LEFT = 1, + + /// @brief `2 `: Move right. + ADDON_ACTION_MOVE_RIGHT = 2, + + /// @brief `3 `: Move up. + ADDON_ACTION_MOVE_UP = 3, + + /// @brief `4 `: Move down. + ADDON_ACTION_MOVE_DOWN = 4, + + /// @brief `5 `: Page up. + ADDON_ACTION_PAGE_UP = 5, + + /// @brief `6 `: Page down. + ADDON_ACTION_PAGE_DOWN = 6, + + /// @brief `7 `: Select item. + ADDON_ACTION_SELECT_ITEM = 7, + + /// @brief `8 `: Highlight item. + ADDON_ACTION_HIGHLIGHT_ITEM = 8, + + /// @brief `9 `: Parent directory. + ADDON_ACTION_PARENT_DIR = 9, + + /// @brief `10 `: Previous menu. + ADDON_ACTION_PREVIOUS_MENU = 10, + + /// @brief `11 `: Show info. + ADDON_ACTION_SHOW_INFO = 11, + + /// @brief `12 `: Pause. + ADDON_ACTION_PAUSE = 12, + + /// @brief `13 `: Stop. + ADDON_ACTION_STOP = 13, + + /// @brief `14 `: Next item. + ADDON_ACTION_NEXT_ITEM = 14, + + /// @brief `15 `: Previous item. + ADDON_ACTION_PREV_ITEM = 15, + + /// @brief `16 `: Can be used to specify specific action in a window, Playback control is handled in ADDON_ACTION_PLAYER_* + ADDON_ACTION_FORWARD = 16, + + /// @brief `17 `: Can be used to specify specific action in a window, Playback control is handled in ADDON_ACTION_PLAYER_* + ADDON_ACTION_REWIND = 17, + + /// @brief `18 `: Toggle between GUI and movie or GUI and visualisation. + ADDON_ACTION_SHOW_GUI = 18, + + /// @brief `19 `: Toggle quick-access zoom modes. Can b used in videoFullScreen.zml window id=2005 + ADDON_ACTION_ASPECT_RATIO = 19, + + /// @brief `20 `: Seek +1% in the movie. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_STEP_FORWARD = 20, + + /// @brief `21 `: Seek -1% in the movie. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_STEP_BACK = 21, + + /// @brief `22 `: Seek +10% in the movie. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_BIG_STEP_FORWARD = 22, + + /// @brief `23 `: Seek -10% in the movie. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_BIG_STEP_BACK = 23, + + /// @brief `24 `: Show/hide OSD. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_SHOW_OSD = 24, + + /// @brief `25 `: Turn subtitles on/off. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_SHOW_SUBTITLES = 25, + + /// @brief `26 `: Switch to next subtitle of movie. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_NEXT_SUBTITLE = 26, + + /// @brief `27 `: Show debug info for VideoPlayer + ADDON_ACTION_PLAYER_DEBUG = 27, + + /// @brief `28 `: Show next picture of slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_NEXT_PICTURE = 28, + + /// @brief `29 `: Show previous picture of slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_PREV_PICTURE = 29, + + /// @brief `30 `: Zoom in picture during slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_ZOOM_OUT = 30, + + /// @brief `31 `: Zoom out picture during slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_ZOOM_IN = 31, + + /// @brief `32 `: Used to toggle between source view and destination view. Can be used in myfiles.xml window id=3 + ADDON_ACTION_TOGGLE_SOURCE_DEST = 32, + + /// @brief `33 `: Used to toggle between current view and playlist view. Can b used in all mymusic xml files + ADDON_ACTION_SHOW_PLAYLIST = 33, + + /// @brief `34 `: Used to queue a item to the playlist. Can b used in all mymusic xml files + ADDON_ACTION_QUEUE_ITEM = 34, + + /// @brief `35 `: Not used anymore + ADDON_ACTION_REMOVE_ITEM = 35, + + /// @brief `36 `: Not used anymore + ADDON_ACTION_SHOW_FULLSCREEN = 36, + + /// @brief `37 `: Zoom 1x picture during slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_ZOOM_LEVEL_NORMAL = 37, + + /// @brief `38 `: Zoom 2x picture during slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_ZOOM_LEVEL_1 = 38, + + /// @brief `39 `: Zoom 3x picture during slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_ZOOM_LEVEL_2 = 39, + + /// @brief `40 `: Zoom 4x picture during slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_ZOOM_LEVEL_3 = 40, + + /// @brief `41 `: Zoom 5x picture during slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_ZOOM_LEVEL_4 = 41, + + /// @brief `42 `: Zoom 6x picture during slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_ZOOM_LEVEL_5 = 42, + + /// @brief `43 `: Zoom 7x picture during slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_ZOOM_LEVEL_6 = 43, + + /// @brief `44 `: Zoom 8x picture during slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_ZOOM_LEVEL_7 = 44, + + /// @brief `45 `: Zoom 9x picture during slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_ZOOM_LEVEL_8 = 45, + + /// @brief `46 `: Zoom 10x picture during slideshow. Can b used in slideshow.xml window id=2007 + ADDON_ACTION_ZOOM_LEVEL_9 = 46, + + /// @brief `47 `: Select next arrow. Can b used in: settingsScreenCalibration.xml windowid=11 + ADDON_ACTION_CALIBRATE_SWAP_ARROWS = 47, + + /// @brief `48 `: Reset calibration to defaults. Can b used in: `settingsScreenCalibration.xml` windowid=11/settingsUICalibration.xml windowid=10 + ADDON_ACTION_CALIBRATE_RESET = 48, + + /// @brief `49 `: Analog thumbstick move. Can b used in: `slideshow.xml` + /// windowid=2007/settingsScreenCalibration.xml windowid=11/settingsUICalibration.xml + /// windowid=10 + /// @note see also ADDON_ACTION_ANALOG_MOVE_X_LEFT, ADDON_ACTION_ANALOG_MOVE_X_RIGHT, + /// ADDON_ACTION_ANALOG_MOVE_Y_UP, ADDON_ACTION_ANALOG_MOVE_Y_DOWN + ADDON_ACTION_ANALOG_MOVE = 49, + + /// @brief `50 `: Rotate current picture clockwise during slideshow. Can be used in slideshow.xml window id=2007 + ADDON_ACTION_ROTATE_PICTURE_CW = 50, + + /// @brief `51 `: Rotate current picture counterclockwise during slideshow. Can be used in slideshow.xml window id=2007 + ADDON_ACTION_ROTATE_PICTURE_CCW = 51, + + /// @brief `52 `: Decrease subtitle/movie Delay. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_SUBTITLE_DELAY_MIN = 52, + + /// @brief `53 `: Increase subtitle/movie Delay. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_SUBTITLE_DELAY_PLUS = 53, + + /// @brief `54 `: Increase avsync delay. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_AUDIO_DELAY_MIN = 54, + + /// @brief `55 `: Decrease avsync delay. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_AUDIO_DELAY_PLUS = 55, + + /// @brief `56 `: Select next language in movie. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_AUDIO_NEXT_LANGUAGE = 56, + + /// @brief `57 `: Switch 2 next resolution. Can b used during screen calibration settingsScreenCalibration.xml windowid=11 + ADDON_ACTION_CHANGE_RESOLUTION = 57, + + /// @brief `58 `: remote keys 0-9. are used by multiple windows + /// for example in videoFullScreen.xml window id=2005 you can + /// enter time (mmss) to jump to particular point in the movie + /// with spincontrols you can enter 3digit number to quickly set + /// spincontrol to desired value + /// + /// Remote key 0 + ADDON_ACTION_REMOTE_0 = 58, + + /// @brief `59 `: Remote key 1 + ADDON_ACTION_REMOTE_1 = 59, + + /// @brief `60 `: Remote key 2 + ADDON_ACTION_REMOTE_2 = 60, + + /// @brief `61 `: Remote key 3 + ADDON_ACTION_REMOTE_3 = 61, + + /// @brief `62 `: Remote key 4 + ADDON_ACTION_REMOTE_4 = 62, + + /// @brief `63 `: Remote key 5 + ADDON_ACTION_REMOTE_5 = 63, + + /// @brief `64 `: Remote key 6 + ADDON_ACTION_REMOTE_6 = 64, + + /// @brief `65 `: Remote key 7 + ADDON_ACTION_REMOTE_7 = 65, + + /// @brief `66 `: Remote key 8 + ADDON_ACTION_REMOTE_8 = 66, + + /// @brief `67 `: Remote key 9 + ADDON_ACTION_REMOTE_9 = 67, + + /// @brief `69 `: Show player process info (video decoder, pixel format, pvr signal strength and the like + ADDON_ACTION_PLAYER_PROCESS_INFO = 69, + + /// @brief `70 `: Program select. + ADDON_ACTION_PLAYER_PROGRAM_SELECT = 70, + + /// @brief `71 `: Resolution select. + ADDON_ACTION_PLAYER_RESOLUTION_SELECT = 71, + + /// @brief `76 `: Jumps a few seconds back during playback of movie. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_SMALL_STEP_BACK = 76, + + /// @brief `77 `: FF in current file played. global action, can be used anywhere + ADDON_ACTION_PLAYER_FORWARD = 77, + + /// @brief `78 `: RW in current file played. global action, can be used anywhere + ADDON_ACTION_PLAYER_REWIND = 78, + + /// @brief `79 `: Play current song. Unpauses song and sets playspeed to 1x. global action, can be used anywhere + ADDON_ACTION_PLAYER_PLAY = 79, + + /// @brief `80 `: Delete current selected item. Can be used in myfiles.xml window id=3 and in myvideoTitle.xml window id=25 + ADDON_ACTION_DELETE_ITEM = 80, + + /// @brief `81 `: Copy current selected item. Can be used in myfiles.xml window id=3 + ADDON_ACTION_COPY_ITEM = 81, + + /// @brief `82 `: move current selected item. Can be used in myfiles.xml window id=3 + ADDON_ACTION_MOVE_ITEM = 82, + + /// @brief `85 `: Take a screenshot. + ADDON_ACTION_TAKE_SCREENSHOT = 85, + + /// @brief `87 `: Rename item. + ADDON_ACTION_RENAME_ITEM = 87, + + /// @brief `87 `: Volume up. + ADDON_ACTION_VOLUME_UP = 88, + + /// @brief `87 `: Volume down. + ADDON_ACTION_VOLUME_DOWN = 89, + + /// @brief `90 `: Volume amplication. + ADDON_ACTION_VOLAMP = 90, + + /// @brief `90 `: Mute. + ADDON_ACTION_MUTE = 91, + + /// @brief `90 `: Nav back. + ADDON_ACTION_NAV_BACK = 92, + + /// @brief `90 `: Volume amp up, + ADDON_ACTION_VOLAMP_UP = 93, + + /// @brief `94 `: Volume amp down. + ADDON_ACTION_VOLAMP_DOWN = 94, + + /// @brief `95 `: Creates an episode bookmark on the currently playing video file containing more than one + /// episode + ADDON_ACTION_CREATE_EPISODE_BOOKMARK = 95, + + /// @brief `96 `: Creates a bookmark of the currently playing video file + ADDON_ACTION_CREATE_BOOKMARK = 96, + + /// @brief `97 `: Goto the next chapter, if not available perform a big step forward + ADDON_ACTION_CHAPTER_OR_BIG_STEP_FORWARD = 97, + + /// @brief `98 `: Goto the previous chapter, if not available perform a big step back + ADDON_ACTION_CHAPTER_OR_BIG_STEP_BACK = 98, + + /// @brief `99 `: Switch to next subtitle of movie, but will not enable/disable the subtitles. Can be used + /// in videoFullScreen.xml window id=2005 + ADDON_ACTION_CYCLE_SUBTITLE = 99, + + /// @brief `100`: Mouse action values start. + /// + /// Ends with @ref ADDON_ACTION_MOUSE_END. + ADDON_ACTION_MOUSE_START = 100, + + /// @brief `100`: Mouse left click. + ADDON_ACTION_MOUSE_LEFT_CLICK = 100, + + /// @brief `101`: Mouse right click. + ADDON_ACTION_MOUSE_RIGHT_CLICK = 101, + + /// @brief `102`: Mouse middle click. + ADDON_ACTION_MOUSE_MIDDLE_CLICK = 102, + + /// @brief `103`: Mouse double click. + ADDON_ACTION_MOUSE_DOUBLE_CLICK = 103, + + /// @brief `104`: Mouse wheel up. + ADDON_ACTION_MOUSE_WHEEL_UP = 104, + + /// @brief `105`: Mouse wheel down. + ADDON_ACTION_MOUSE_WHEEL_DOWN = 105, + + /// @brief `106`: Mouse drag. + ADDON_ACTION_MOUSE_DRAG = 106, + + /// @brief `107`: Mouse move. + ADDON_ACTION_MOUSE_MOVE = 107, + + /// @brief `108`: Mouse long click. + ADDON_ACTION_MOUSE_LONG_CLICK = 108, + + /// @brief `109`: Mouse drag end. + ADDON_ACTION_MOUSE_DRAG_END = 109, + + /// @brief `109`: Mouse action values end. + /// + /// Starts with @ref ADDON_ACTION_MOUSE_START. + ADDON_ACTION_MOUSE_END = 109, + + /// @brief `110`: Backspace. + ADDON_ACTION_BACKSPACE = 110, + + /// @brief `111`: Scroll up. + ADDON_ACTION_SCROLL_UP = 111, + + /// @brief `112`: Scroll down. + ADDON_ACTION_SCROLL_DOWN = 112, + + /// @brief `113`: Analog forward. + ADDON_ACTION_ANALOG_FORWARD = 113, + + /// @brief `114`: Analog rewind. + ADDON_ACTION_ANALOG_REWIND = 114, + + /// @brief `115`: move item up in playlist + ADDON_ACTION_MOVE_ITEM_UP = 115, + + /// @brief `116`: move item down in playlist + ADDON_ACTION_MOVE_ITEM_DOWN = 116, + + /// @brief `117`: pops up the context menu + ADDON_ACTION_CONTEXT_MENU = 117, + + /// @brief `118`: stuff for virtual keyboard shortcuts + ADDON_ACTION_SHIFT = 118, + + /// @brief `119`: stuff for virtual keyboard shortcuts + ADDON_ACTION_SYMBOLS = 119, + + /// @brief `120`: stuff for virtual keyboard shortcuts + ADDON_ACTION_CURSOR_LEFT = 120, + + /// @brief `121`: stuff for virtual keyboard shortcuts + ADDON_ACTION_CURSOR_RIGHT = 121, + + /// @brief `122`: Build in function + ADDON_ACTION_BUILT_IN_FUNCTION = 122, + + /// @brief `114`: Displays current time, can be used in videoFullScreen.xml window id=2005 + ADDON_ACTION_SHOW_OSD_TIME = 123, + + /// @brief `124`: Seeks forward, and displays the seek bar. + ADDON_ACTION_ANALOG_SEEK_FORWARD = 124, + + /// @brief `125`: Seeks backward, and displays the seek bar. + ADDON_ACTION_ANALOG_SEEK_BACK = 125, + + /// @brief `126`: Visualization preset show. + ADDON_ACTION_VIS_PRESET_SHOW = 126, + + /// @brief `128`: Visualization preset next. + ADDON_ACTION_VIS_PRESET_NEXT = 128, + + /// @brief `129`: Visualization preset previous. + ADDON_ACTION_VIS_PRESET_PREV = 129, + + /// @brief `130`: Visualization preset lock. + ADDON_ACTION_VIS_PRESET_LOCK = 130, + + /// @brief `131`: Visualization preset random. + ADDON_ACTION_VIS_PRESET_RANDOM = 131, + + /// @brief `132`: Visualization preset plus. + ADDON_ACTION_VIS_RATE_PRESET_PLUS = 132, + + /// @brief `133`: Visualization preset minus. + ADDON_ACTION_VIS_RATE_PRESET_MINUS = 133, + + /// @brief `134`: Show Videomenu + ADDON_ACTION_SHOW_VIDEOMENU = 134, + + /// @brief `135`: Enter. + ADDON_ACTION_ENTER = 135, + + /// @brief `136`: Increase rating. + ADDON_ACTION_INCREASE_RATING = 136, + + /// @brief `137`: Decrease rating. + ADDON_ACTION_DECREASE_RATING = 137, + + /// @brief `138`: Switch to next scene/cutpoint in movie. + ADDON_ACTION_NEXT_SCENE = 138, + + /// @brief `139`: Switch to previous scene/cutpoint in movie. + ADDON_ACTION_PREV_SCENE = 139, + + /// @brief `140`: Jump through a list or container to next letter. + ADDON_ACTION_NEXT_LETTER = 140, + + /// @brief `141`: Jump through a list or container to previous letter. + ADDON_ACTION_PREV_LETTER = 141, + + /// @brief `142`: Jump direct to a particular letter using SMS-style input + /// + /// Jump to SMS2. + ADDON_ACTION_JUMP_SMS2 = 142, + + /// @brief `143`: Jump to SMS3. + ADDON_ACTION_JUMP_SMS3 = 143, + + /// @brief `144`: Jump to SMS4. + ADDON_ACTION_JUMP_SMS4 = 144, + + /// @brief `145`: Jump to SMS5. + ADDON_ACTION_JUMP_SMS5 = 145, + + /// @brief `146`: Jump to SMS6. + ADDON_ACTION_JUMP_SMS6 = 146, + + /// @brief `147`: Jump to SMS7. + ADDON_ACTION_JUMP_SMS7 = 147, + + /// @brief `148`: Jump to SMS8. + ADDON_ACTION_JUMP_SMS8 = 148, + + /// @brief `149`: Jump to SMS9. + ADDON_ACTION_JUMP_SMS9 = 149, + + /// @brief `150`: Filter clear. + ADDON_ACTION_FILTER_CLEAR = 150, + + /// @brief `151`: Filter SMS2. + ADDON_ACTION_FILTER_SMS2 = 151, + + /// @brief `152`: Filter SMS3. + ADDON_ACTION_FILTER_SMS3 = 152, + + /// @brief `153`: Filter SMS4. + ADDON_ACTION_FILTER_SMS4 = 153, + + /// @brief `154`: Filter SMS5. + ADDON_ACTION_FILTER_SMS5 = 154, + + /// @brief `155`: Filter SMS6. + ADDON_ACTION_FILTER_SMS6 = 155, + + /// @brief `156`: Filter SMS7. + ADDON_ACTION_FILTER_SMS7 = 156, + + /// @brief `157`: Filter SMS8. + ADDON_ACTION_FILTER_SMS8 = 157, + + /// @brief `158`: Filter SMS9. + ADDON_ACTION_FILTER_SMS9 = 158, + + /// @brief `159`: First page. + ADDON_ACTION_FIRST_PAGE = 159, + + /// @brief `160`: Last page. + ADDON_ACTION_LAST_PAGE = 160, + + /// @brief `161`: Audio delay. + ADDON_ACTION_AUDIO_DELAY = 161, + + /// @brief `162`: Subtitle delay. + ADDON_ACTION_SUBTITLE_DELAY = 162, + + /// @brief `163`: Menu. + ADDON_ACTION_MENU = 163, + + /// @brief `164`: Set rating. + ADDON_ACTION_SET_RATING = 164, + + /// @brief `170`: Record. + ADDON_ACTION_RECORD = 170, + + /// @brief `180`: Paste. + ADDON_ACTION_PASTE = 180, + + /// @brief `181`: Next control. + ADDON_ACTION_NEXT_CONTROL = 181, + + /// @brief `182`: Previous control. + ADDON_ACTION_PREV_CONTROL = 182, + + /// @brief `183`: Channel switch. + ADDON_ACTION_CHANNEL_SWITCH = 183, + + /// @brief `184`: Channel up. + ADDON_ACTION_CHANNEL_UP = 184, + + /// @brief `185`: Channel down. + ADDON_ACTION_CHANNEL_DOWN = 185, + + /// @brief `186`: Next channel group. + ADDON_ACTION_NEXT_CHANNELGROUP = 186, + + /// @brief `187`: Previous channel group. + ADDON_ACTION_PREVIOUS_CHANNELGROUP = 187, + + /// @brief `188`: PVR play. + ADDON_ACTION_PVR_PLAY = 188, + + /// @brief `189`: PVR play TV. + ADDON_ACTION_PVR_PLAY_TV = 189, + + /// @brief `190`: PVR play radio. + ADDON_ACTION_PVR_PLAY_RADIO = 190, + + /// @brief `191`: PVR show timer rule. + ADDON_ACTION_PVR_SHOW_TIMER_RULE = 191, + + /// @brief `192`: Channel number sep + ADDON_ACTION_CHANNEL_NUMBER_SEP = 192, + + /// @brief `193`: PVR announce reminders + ADDON_ACTION_PVR_ANNOUNCE_REMINDERS = 193, + + /// @brief `199`: Switch 2 desktop resolution + ADDON_ACTION_TOGGLE_FULLSCREEN = 199, + + /// @brief `200`: Toggle watched status (videos) + ADDON_ACTION_TOGGLE_WATCHED = 200, + + /// @brief `201`: Scan item + ADDON_ACTION_SCAN_ITEM = 201, + + /// @brief `202`: Switch digital <-> analog + ADDON_ACTION_TOGGLE_DIGITAL_ANALOG = 202, + + /// @brief `203`: Reloads CButtonTranslator's keymaps + ADDON_ACTION_RELOAD_KEYMAPS = 203, + + /// @brief `204`: Start the GUIControlProfiler running + ADDON_ACTION_GUIPROFILE_BEGIN = 204, + + /// @brief `215`: Teletext Color button Red to control TopText + ADDON_ACTION_TELETEXT_RED = 215, + + /// @brief `216`: Teletext Color button Green to control TopText + ADDON_ACTION_TELETEXT_GREEN = 216, + + /// @brief `217`: Teletext Color button Yellow to control TopText + ADDON_ACTION_TELETEXT_YELLOW = 217, + + /// @brief `218`: Teletext Color button Blue to control TopText + ADDON_ACTION_TELETEXT_BLUE = 218, + + /// @brief `219`: Increase par. + ADDON_ACTION_INCREASE_PAR = 219, + + /// @brief `220`: Decrease par. + ADDON_ACTION_DECREASE_PAR = 220, + + /// @brief `227`: Shift up video image in VideoPlayer + ADDON_ACTION_VSHIFT_UP = 227, + + /// @brief `228`: Shift down video image in VideoPlayer + ADDON_ACTION_VSHIFT_DOWN = 228, + + /// @brief `229`: Play/pause. If playing it pauses, if paused it plays. + ADDON_ACTION_PLAYER_PLAYPAUSE = 229, + + /// @brief `230`: Shift up subtitles in VideoPlayer + ADDON_ACTION_SUBTITLE_VSHIFT_UP = 230, + + /// @brief `231`: Shift down subtitles in VideoPlayer + ADDON_ACTION_SUBTITLE_VSHIFT_DOWN = 231, + + /// @brief `232`: Toggle vertical alignment of subtitles + ADDON_ACTION_SUBTITLE_ALIGN = 232, + + /// @brief `233`: Filter. + ADDON_ACTION_FILTER = 233, + + /// @brief `234`: Switch player. + ADDON_ACTION_SWITCH_PLAYER = 234, + + /// @brief `235`: Stereo mode next. + ADDON_ACTION_STEREOMODE_NEXT = 235, + + /// @brief `236`: Stereo mode previous. + ADDON_ACTION_STEREOMODE_PREVIOUS = 236, + + /// @brief `237`: Turns 3d mode on/off. + ADDON_ACTION_STEREOMODE_TOGGLE = 237, + + /// @brief `238`: Stereo mode select. + ADDON_ACTION_STEREOMODE_SELECT = 238, + + /// @brief `239`: Stereo mode to mono. + ADDON_ACTION_STEREOMODE_TOMONO = 239, + + /// @brief `240`: Stereo mode set. + ADDON_ACTION_STEREOMODE_SET = 240, + + /// @brief `241`: Settings reset. + ADDON_ACTION_SETTINGS_RESET = 241, + + /// @brief `242`: Settings level change. + ADDON_ACTION_SETTINGS_LEVEL_CHANGE = 242, + + /// @brief `243`: Show autoclosing OSD. Can b used in videoFullScreen.xml window id=2005 + ADDON_ACTION_TRIGGER_OSD = 243, + + /// @brief `244`: Input text. + ADDON_ACTION_INPUT_TEXT = 244, + + /// @brief `245`: Volume set. + ADDON_ACTION_VOLUME_SET = 245, + + /// @brief `246`: Toggle commercial skip. + ADDON_ACTION_TOGGLE_COMMSKIP = 246, + + /// @brief `247`: Browse for subtitle. Can be used in videofullscreen + ADDON_ACTION_BROWSE_SUBTITLE = 247, + + /// @brief `248`: Send a reset command to the active game + ADDON_ACTION_PLAYER_RESET = 248, + + /// @brief `249`: Toggle font. Used in TextViewer dialog + ADDON_ACTION_TOGGLE_FONT = 249, + + /// @brief `250`: Cycle video streams. Used in videofullscreen. + ADDON_ACTION_VIDEO_NEXT_STREAM = 250, + + /// @brief `251`: Used to queue an item to the next position in the playlist + ADDON_ACTION_QUEUE_ITEM_NEXT = 251, + + /// @brief `247`: Toggle display HDR on/off + ADDON_ACTION_HDR_TOGGLE = 260, + + /// @brief `300`: Voice actions + ADDON_ACTION_VOICE_RECOGNIZE = 300, + + // Number 347 used om front by ADDON_ACTION_BROWSE_SUBTITLE + + /// @brief `401`: Touch actions + ADDON_ACTION_TOUCH_TAP = 401, + + /// @brief `410`: Touch actions + ADDON_ACTION_TOUCH_TAP_TEN = 410, + + /// @brief `411`: Touch actions + ADDON_ACTION_TOUCH_LONGPRESS = 411, + + /// @brief `412`: Touch actions + ADDON_ACTION_TOUCH_LONGPRESS_TEN = 420, + + /// @brief `500`: Gesture notify. + ADDON_ACTION_GESTURE_NOTIFY = 500, + + /// @brief `501`: Gesture begin. + ADDON_ACTION_GESTURE_BEGIN = 501, + + /// @brief `502`: Send action with point and currentPinchScale (fingers together < 1.0 -> fingers apart > 1.0) + ADDON_ACTION_GESTURE_ZOOM = 502, + + /// @brief `503`: Gesture rotate. + ADDON_ACTION_GESTURE_ROTATE = 503, + + /// @brief `504`: Gesture pan. + ADDON_ACTION_GESTURE_PAN = 504, + + /// @brief `505`: Gesture was interrupted in unspecified state + ADDON_ACTION_GESTURE_ABORT = 505, + + /// @brief `511`: Gesture swipe left. + ADDON_ACTION_GESTURE_SWIPE_LEFT = 511, + + /// @brief `520`: Gesture swipe left ten + ADDON_ACTION_GESTURE_SWIPE_LEFT_TEN = 520, + + /// @brief `521`: Gesture swipe right + ADDON_ACTION_GESTURE_SWIPE_RIGHT = 521, + + /// @brief `530`: Gesture swipe right ten + ADDON_ACTION_GESTURE_SWIPE_RIGHT_TEN = 530, + + /// @brief `531`: Gesture swipe up + ADDON_ACTION_GESTURE_SWIPE_UP = 531, + + /// @brief `540`: Gesture swipe up ten + ADDON_ACTION_GESTURE_SWIPE_UP_TEN = 540, + + /// @brief `541`: Gesture swipe down. + ADDON_ACTION_GESTURE_SWIPE_DOWN = 541, + + /// @brief `550`: Gesture swipe down ten. + ADDON_ACTION_GESTURE_SWIPE_DOWN_TEN = 550, + + /// @brief `599`: 5xx is reserved for additional gesture actions + ADDON_ACTION_GESTURE_END = 599, + + // other, non-gesture actions + + /// @brief `601`: Analog thumbstick move, horizontal axis, left; see ADDON_ACTION_ANALOG_MOVE + ADDON_ACTION_ANALOG_MOVE_X_LEFT = 601, + + /// @brief `602`: Analog thumbstick move, horizontal axis, right; see ADDON_ACTION_ANALOG_MOVE + ADDON_ACTION_ANALOG_MOVE_X_RIGHT = 602, + + /// @brief `603`: Analog thumbstick move, vertical axis, up; see ADDON_ACTION_ANALOG_MOVE + ADDON_ACTION_ANALOG_MOVE_Y_UP = 603, + + /// @brief `604`: Analog thumbstick move, vertical axis, down; see ADDON_ACTION_ANALOG_MOVE + ADDON_ACTION_ANALOG_MOVE_Y_DOWN = 604, + + /// @brief `998`: ERROR action is used to play an error sound. + ADDON_ACTION_ERROR = 998, + + /// @brief `999`: The NOOP action can be specified to disable an input event. This is + /// useful in user keyboard.xml etc to disable actions specified in the + /// system mappings. + ADDON_ACTION_NOOP = 999 + ///@} +}; +///@} + +#endif /* !C_API_GUI_ACTION_IDS_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/list_item.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/list_item.h new file mode 100644 index 0000000..f0c4dc7 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/list_item.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_LIST_ITEM_H +#define C_API_GUI_LIST_ITEM_H + +#include "definitions.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct AddonToKodiFuncTable_kodi_gui_listItem + { + KODI_GUI_LISTITEM_HANDLE(*create) + (KODI_HANDLE kodiBase, + const char* label, + const char* label2, + const char* path); + void (*destroy)(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle); + + char* (*get_label)(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle); + void (*set_label)(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle, const char* label); + char* (*get_label2)(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle); + void (*set_label2)(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle, const char* label); + char* (*get_art)(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle, const char* type); + void (*set_art)(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + const char* type, + const char* image); + char* (*get_path)(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle); + void (*set_path)(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle, const char* path); + char* (*get_property)(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle, const char* key); + void (*set_property)(KODI_HANDLE kodiBase, + KODI_GUI_LISTITEM_HANDLE handle, + const char* key, + const char* value); + void (*select)(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle, bool select); + bool (*is_selected)(KODI_HANDLE kodiBase, KODI_GUI_LISTITEM_HANDLE handle); + } AddonToKodiFuncTable_kodi_gui_listItem; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_LIST_ITEM_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/window.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/window.h new file mode 100644 index 0000000..0f844f5 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/gui/window.h @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_GUI_WINDOW_H +#define C_API_GUI_WINDOW_H + +#include "definitions.h" +#include "input/action_ids.h" + +#include + +#define ADDON_MAX_CONTEXT_ENTRIES 20 +#define ADDON_MAX_CONTEXT_ENTRY_NAME_LENGTH 80 + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct gui_context_menu_pair + { + unsigned int id; + char name[ADDON_MAX_CONTEXT_ENTRY_NAME_LENGTH]; + } gui_context_menu_pair; + + typedef struct AddonToKodiFuncTable_kodi_gui_window + { + /* Window creation functions */ + KODI_GUI_WINDOW_HANDLE(*create) + (KODI_HANDLE kodiBase, + const char* xml_filename, + const char* default_skin, + bool as_dialog, + bool is_media); + void (*destroy)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + + void (*set_callbacks)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + KODI_GUI_CLIENT_HANDLE clienthandle, + bool (*CBInit)(KODI_GUI_CLIENT_HANDLE), + bool (*CBFocus)(KODI_GUI_CLIENT_HANDLE, int), + bool (*CBClick)(KODI_GUI_CLIENT_HANDLE, int), + bool (*CBOnAction)(KODI_GUI_CLIENT_HANDLE, enum ADDON_ACTION), + void (*CBGetContextButtons)( + KODI_GUI_CLIENT_HANDLE, int, gui_context_menu_pair*, unsigned int*), + bool (*CBOnContextButton)(KODI_GUI_CLIENT_HANDLE, int, unsigned int)); + bool (*show)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + bool (*close)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + bool (*do_modal)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + + /* Window control functions */ + bool (*set_focus_id)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + int (*get_focus_id)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + void (*set_control_label)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id, + const char* label); + void (*set_control_visible)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id, + bool visible); + void (*set_control_selected)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int control_id, + bool selected); + + /* Window property functions */ + void (*set_property)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + const char* value); + void (*set_property_int)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + int value); + void (*set_property_bool)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + bool value); + void (*set_property_double)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + double value); + char* (*get_property)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, const char* key); + int (*get_property_int)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, const char* key); + bool (*get_property_bool)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, const char* key); + double (*get_property_double)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key); + void (*clear_properties)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + void (*clear_property)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, const char* key); + + /* List item functions */ + void (*clear_item_list)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + void (*add_list_item)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + KODI_GUI_LISTITEM_HANDLE item, + int list_position); + void (*remove_list_item_from_position)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int list_position); + void (*remove_list_item)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + KODI_GUI_LISTITEM_HANDLE item); + KODI_GUI_LISTITEM_HANDLE(*get_list_item) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int list_position); + void (*set_current_list_position)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + int list_position); + int (*get_current_list_position)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + int (*get_list_size)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + void (*set_container_property)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* key, + const char* value); + void (*set_container_content)(KODI_HANDLE kodiBase, + KODI_GUI_WINDOW_HANDLE handle, + const char* value); + int (*get_current_container_id)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + + /* Various functions */ + void (*mark_dirty_region)(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle); + + /* GUI control access functions */ + KODI_GUI_CONTROL_HANDLE(*get_control_button) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_edit) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_fade_label) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_image) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_label) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_progress) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_radio_button) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_render_addon) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_settings_slider) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_slider) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_spin) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_text_box) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_dummy1) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_dummy2) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_dummy3) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_dummy4) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_dummy5) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_dummy6) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_dummy7) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_dummy8) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_dummy9) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + KODI_GUI_CONTROL_HANDLE(*get_control_dummy10) + (KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id); + /* This above used to add new get_control_* functions */ + } AddonToKodiFuncTable_kodi_gui_window; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !C_API_GUI_WINDOW_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/network.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/network.h new file mode 100644 index 0000000..88d5231 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/network.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_NETWORK_H +#define C_API_NETWORK_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + /* + * For interface between add-on and kodi. + * + * This structure defines the addresses of functions stored inside Kodi which + * are then available for the add-on to call + * + * All function pointers there are used by the C++ interface functions below. + * You find the set of them on xbmc/addons/interfaces/General.cpp + * + * Note: For add-on development itself this is not needed + */ + typedef struct AddonToKodiFuncTable_kodi_network + { + bool (*wake_on_lan)(void* kodiBase, const char* mac); + char* (*get_ip_address)(void* kodiBase); + char* (*dns_lookup)(void* kodiBase, const char* url, bool* ret); + char* (*url_encode)(void* kodiBase, const char* url); + char* (*get_hostname)(void* kodiBase); + bool (*is_local_host)(void* kodiBase, const char* hostname); + bool (*is_host_on_lan)(void* kodiBase, const char* hostname, bool offLineCheck); + char* (*get_user_agent)(void* kodiBase); + } AddonToKodiFuncTable_kodi_network; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* C_API_NETWORK_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/c-api/platform/android/system.h b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/platform/android/system.h new file mode 100644 index 0000000..568a2fd --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/c-api/platform/android/system.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef C_API_PLATFORM_ANDROID_H +#define C_API_PLATFORM_ANDROID_H + +#define INTERFACE_ANDROID_SYSTEM_NAME "ANDROID_SYSTEM" +#define INTERFACE_ANDROID_SYSTEM_VERSION "1.0.2" +#define INTERFACE_ANDROID_SYSTEM_VERSION_MIN "1.0.1" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + struct AddonToKodiFuncTable_android_system + { + void* (*get_jni_env)(); + int (*get_sdk_version)(); + const char *(*get_class_name)(); + }; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !C_API_PLATFORM_ANDROID_H */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/gui/CMakeLists.txt new file mode 100644 index 0000000..8f12955 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/CMakeLists.txt @@ -0,0 +1,8 @@ +set(HEADERS General.h + ListItem.h + Window.h + renderHelper.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_gui) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/General.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/General.h new file mode 100644 index 0000000..85ba3f2 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/General.h @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../AddonBase.h" +#include "../c-api/gui/general.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ + +//============================================================================== +/// @addtogroup cpp_kodi_gui_general +/// Permits the use of the required functions of the add-on to Kodi. +/// +/// These are pure functions them no other initialization need. +/// +/// It has the header @ref kodi/gui/General.h "#include " be included +/// to enjoy it. +/// + +//============================================================================== +/// @ingroup cpp_kodi_gui_general +/// @brief Performs a graphical lock of rendering engine. +/// +inline void ATTRIBUTE_HIDDEN Lock() +{ + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->general->lock(); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_general +/// @brief Performs a graphical unlock of previous locked rendering engine. +/// +inline void ATTRIBUTE_HIDDEN Unlock() +{ + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->general->unlock(); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_general +/// @brief Return the the current screen height with pixel. +/// +/// @return Screen height with pixel +/// +inline int ATTRIBUTE_HIDDEN GetScreenHeight() +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->general->get_screen_height( + CAddonBase::m_interface->toKodi->kodiBase); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_general +/// @brief Return the the current screen width with pixel. +/// +/// @return Screen width with pixel +/// +inline int ATTRIBUTE_HIDDEN GetScreenWidth() +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->general->get_screen_width( + CAddonBase::m_interface->toKodi->kodiBase); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_general +/// @brief Return the the current screen rendering resolution. +/// +/// @return Current screen rendering resolution +/// +inline int ATTRIBUTE_HIDDEN GetVideoResolution() +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->general->get_video_resolution( + CAddonBase::m_interface->toKodi->kodiBase); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_general +/// @brief Returns the id for the current 'active' dialog as an integer. +/// +/// @return The currently active dialog Id +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// .. +/// int wid = kodi::gui::GetCurrentWindowDialogId(); +/// .. +/// ~~~~~~~~~~~~~ +/// +inline int ATTRIBUTE_HIDDEN GetCurrentWindowDialogId() +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->general->get_current_window_dialog_id( + CAddonBase::m_interface->toKodi->kodiBase); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_general +/// @brief Returns the id for the current 'active' window as an integer. +/// +/// @return The currently active window Id +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// .. +/// int wid = kodi::gui::GetCurrentWindowId(); +/// .. +/// ~~~~~~~~~~~~~ +/// +inline int ATTRIBUTE_HIDDEN GetCurrentWindowId() +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->general->get_current_window_id( + CAddonBase::m_interface->toKodi->kodiBase); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_general +/// @brief To get hardware specific device context interface. +/// +/// @return A pointer to the used device with @ref cpp_kodi_Defs_HardwareContext "kodi::HardwareContext" +/// +/// @warning This function is only be supported under Windows, on all other +/// OS it return `nullptr`! +/// +/// @note Returned Windows class pointer is `ID3D11DeviceContext1`. +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// .. +/// ID3D11DeviceContext1* context = static_cast(kodi::gui::GetHWContext()); +/// .. +/// ~~~~~~~~~~~~~ +/// +inline kodi::HardwareContext GetHWContext() +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->general->get_hw_context( + CAddonBase::m_interface->toKodi->kodiBase); +} +//------------------------------------------------------------------------------ + +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/ListItem.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/ListItem.h new file mode 100644 index 0000000..3a4d50b --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/ListItem.h @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../AddonBase.h" +#include "../c-api/gui/list_item.h" + +#ifdef __cplusplus + +#include + +namespace kodi +{ +namespace gui +{ + +class CWindow; + +class ATTRIBUTE_HIDDEN CAddonGUIControlBase +{ +public: + KODI_GUI_LISTITEM_HANDLE GetControlHandle() const { return m_controlHandle; } + +protected: + explicit CAddonGUIControlBase(CAddonGUIControlBase* window) + : m_controlHandle(nullptr), + m_interface(::kodi::addon::CAddonBase::m_interface->toKodi), + m_Window(window) + { + } + + virtual ~CAddonGUIControlBase() = default; + + friend class CWindow; + + KODI_GUI_LISTITEM_HANDLE m_controlHandle; + AddonToKodiFuncTable_Addon* m_interface; + CAddonGUIControlBase* m_Window; + +private: + CAddonGUIControlBase() = delete; + CAddonGUIControlBase(const CAddonGUIControlBase&) = delete; + CAddonGUIControlBase& operator=(const CAddonGUIControlBase&) = delete; +}; + +class CListItem; + +//============================================================================== +/// @addtogroup cpp_kodi_gui_windows_listitem +/// @brief @cpp_class{ kodi::gui::CListItem } +/// **Selectable window list item**\n +/// The list item control is used for creating item lists in Kodi. +/// +/// The with @ref ListItem.h "#include " given +/// class is used to create a item entry for a list on window and to support it's +/// control. +/// +class ATTRIBUTE_HIDDEN CListItem : public CAddonGUIControlBase +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief Class constructor with parameters. + /// + /// @param[in] label [opt] Item label + /// @param[in] label2 [opt] Second Item label (if needed) + /// @param[in] path [opt] Path to where item is defined + /// + CListItem(const std::string& label = "", + const std::string& label2 = "", + const std::string& path = "") + : CAddonGUIControlBase(nullptr) + { + m_controlHandle = m_interface->kodi_gui->listItem->create(m_interface->kodiBase, label.c_str(), + label2.c_str(), path.c_str()); + } + + /* + * Constructor used for parts given by list items from addon window + * + * Related to call of "std::shared_ptr kodi::gui::CWindow::GetListItem(int listPos)" + * Not needed for addon development itself + */ + explicit CListItem(KODI_GUI_LISTITEM_HANDLE listItemHandle) : CAddonGUIControlBase(nullptr) + { + m_controlHandle = listItemHandle; + } + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief Class destructor + /// + ~CListItem() override + { + m_interface->kodi_gui->listItem->destroy(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief Returns the listitem label. + /// + /// @return Label of item + /// + std::string GetLabel() + { + std::string label; + char* ret = m_interface->kodi_gui->listItem->get_label(m_interface->kodiBase, m_controlHandle); + if (ret != nullptr) + { + if (std::strlen(ret)) + label = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return label; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief Sets the listitem label. + /// + /// @param[in] label string or unicode - text string. + /// + void SetLabel(const std::string& label) + { + m_interface->kodi_gui->listItem->set_label(m_interface->kodiBase, m_controlHandle, + label.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief Returns the second listitem label. + /// + /// @return Second label of item + /// + std::string GetLabel2() + { + std::string label; + char* ret = m_interface->kodi_gui->listItem->get_label2(m_interface->kodiBase, m_controlHandle); + if (ret != nullptr) + { + if (std::strlen(ret)) + label = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return label; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief Sets the listitem's label2. + /// + /// @param[in] label string or unicode - text string. + /// + void SetLabel2(const std::string& label) + { + m_interface->kodi_gui->listItem->set_label2(m_interface->kodiBase, m_controlHandle, + label.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief Sets the listitem's art + /// + /// @param[in] type Type of Art to set + /// - Some default art values (any string possible): + /// | value (type) | Type | + /// |:-------------:|:--------------------------------------------------| + /// | thumb | string - image filename + /// | poster | string - image filename + /// | banner | string - image filename + /// | fanart | string - image filename + /// | clearart | string - image filename + /// | clearlogo | string - image filename + /// | landscape | string - image filename + /// | icon | string - image filename + /// @return The url to use for Art + /// + std::string GetArt(const std::string& type) + { + std::string strReturn; + char* ret = m_interface->kodi_gui->listItem->get_art(m_interface->kodiBase, m_controlHandle, + type.c_str()); + if (ret != nullptr) + { + if (std::strlen(ret)) + strReturn = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return strReturn; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief Sets the listitem's art + /// + /// @param[in] type Type of Art to set + /// @param[in] url The url to use for Art + /// - Some default art values (any string possible): + /// | value (type) | Type | + /// |:-------------:|:--------------------------------------------------| + /// | thumb | string - image filename + /// | poster | string - image filename + /// | banner | string - image filename + /// | fanart | string - image filename + /// | clearart | string - image filename + /// | clearlogo | string - image filename + /// | landscape | string - image filename + /// | icon | string - image filename + /// + void SetArt(const std::string& type, const std::string& url) + { + m_interface->kodi_gui->listItem->set_art(m_interface->kodiBase, m_controlHandle, type.c_str(), + url.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief Returns the path / filename of this listitem. + /// + /// @return Path string + /// + std::string GetPath() + { + std::string strReturn; + char* ret = m_interface->kodi_gui->listItem->get_path(m_interface->kodiBase, m_controlHandle); + if (ret != nullptr) + { + if (std::strlen(ret)) + strReturn = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return strReturn; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief Sets the listitem's path. + /// + /// @param[in] path string or unicode - path, activated when item is clicked. + /// + /// @note You can use the above as keywords for arguments. + /// + void SetPath(const std::string& path) + { + m_interface->kodi_gui->listItem->set_path(m_interface->kodiBase, m_controlHandle, path.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief Sets a listitem property, similar to an infolabel. + /// + /// @param[in] key string - property name. + /// @param[in] value string or unicode - value of property. + /// + /// @note Key is NOT case sensitive. + /// You can use the above as keywords for arguments and skip certain@n + /// optional arguments.\n + /// Once you use a keyword, all following arguments require the + /// keyword. + /// + /// Some of these are treated internally by Kodi, such as the + /// 'StartOffset' property, which is the offset in seconds at which to + /// start playback of an item. Others may be used in the skin to add + /// extra information, such as 'WatchedCount' for tvshow items + /// + void SetProperty(const std::string& key, const std::string& value) + { + m_interface->kodi_gui->listItem->set_property(m_interface->kodiBase, m_controlHandle, + key.c_str(), value.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief Returns a listitem property as a string, similar to an infolabel. + /// + /// @param[in] key string - property name. + /// @return string - List item property + /// + /// @note Key is NOT case sensitive.\n + /// You can use the above as keywords for arguments and skip certain + /// optional arguments.\n + /// Once you use a keyword, all following arguments require the + /// keyword. + /// + std::string GetProperty(const std::string& key) + { + std::string label; + char* ret = m_interface->kodi_gui->listItem->get_property(m_interface->kodiBase, + m_controlHandle, key.c_str()); + if (ret != nullptr) + { + if (std::strlen(ret)) + label = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return label; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief To control selection of item in list (also multiple selection, + /// in list on serveral items possible). + /// + /// @param[in] selected if true becomes set as selected + /// + void Select(bool selected) + { + m_interface->kodi_gui->listItem->select(m_interface->kodiBase, m_controlHandle, selected); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_listitem + /// @brief Returns the listitem's selected status. + /// + /// @return true if selected, otherwise false + /// + bool IsSelected() + { + return m_interface->kodi_gui->listItem->is_selected(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- +}; + +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/Window.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/Window.h new file mode 100644 index 0000000..3066b3c --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/Window.h @@ -0,0 +1,915 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../AddonBase.h" +#include "../c-api/gui/window.h" +#include "ListItem.h" +#include "input/ActionIDs.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_windows_window_Defs Definitions, structures and enumerators +/// @ingroup cpp_kodi_gui_windows_window +/// @brief **Library definition values**\n +/// Additional values, structures and things that are used in the Window class. +/// +/// ------------------------------------------------------------------------ +/// +/// @link cpp_kodi_gui_windows_window Go back to normal functions from CWindow@endlink +/// + +//============================================================================== +/// @ingroup cpp_kodi_gui_windows_window_Defs +/// @brief **Handler for addon-sided processing class**\n +/// If the callback functions used by the window are not used directly in the +/// @ref cpp_kodi_gui_windows_window "CWindow" class and are outside of it. +/// +/// This value here corresponds to a `void*` and returns the address +/// requested by the add-on for callbacks. +/// +using ClientHandle = KODI_GUI_CLIENT_HANDLE; +//------------------------------------------------------------------------------ + +class CListItem; + +//============================================================================== +/// @addtogroup cpp_kodi_gui_windows_window +/// @brief @cpp_class{ kodi::gui::CWindow } +/// **Main window control class**\n +/// The addon uses its own skin xml file and displays it in Kodi using this class. +/// +/// The with @ref Window.h "#include " +/// included file brings support to create a window or dialog on Kodi. +/// +/// The add-on has to integrate its own @ref cpp_kodi_gui_windows_window_callbacks "callback functions" +/// in order to process the necessary user access to its window. +/// +/// +/// -------------------------------------------------------------------------- +/// +/// **Window header example:** +/// ~~~~~~~~~~~~~{.xml} +/// +/// +/// RunScript(script.foobar) +/// SetProperty(foo,bar) +/// 2 +/// 9000 +/// 0xff00ff00 +/// 50,51,509,510 +/// Window.IsActive(Home) +/// WindowOpen +/// WindowClose +/// 1 +/// +/// 40 +/// 50 +/// Window.IsActive(Home) +/// +/// MyVideos +/// +/// +/// +/// .... +/// +/// +/// ~~~~~~~~~~~~~ +/// +/// -------------------------------------------------------------------------- +/// +/// On functions defined input variable controlId (GUI control identifier) +/// is the on window.xml defined value behind type added with id="..." and +/// used to identify for changes there and on callbacks. +/// +/// ~~~~~~~~~~~~~{.xml} +/// +/// Title Label +/// ... +/// +/// +/// progress control +/// ... +/// +/// ~~~~~~~~~~~~~ +/// +/// +class ATTRIBUTE_HIDDEN CWindow : public CAddonGUIControlBase +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Class constructor with needed values for window / dialog. + /// + /// Creates a new Window class. + /// + /// @param[in] xmlFilename XML file for the skin + /// @param[in] defaultSkin Default skin to use if needed not available + /// @param[in] asDialog Use window as dialog if set + /// @param[in] isMedia [opt] bool - if False, create a regular window. + /// if True, create a mediawindow. (default=false) + /// + /// @note `isMedia` value as true only usable for windows not for dialogs. + /// + CWindow(const std::string& xmlFilename, + const std::string& defaultSkin, + bool asDialog, + bool isMedia = false) + : CAddonGUIControlBase(nullptr) + { + m_controlHandle = m_interface->kodi_gui->window->create( + m_interface->kodiBase, xmlFilename.c_str(), defaultSkin.c_str(), asDialog, isMedia); + if (!m_controlHandle) + kodi::Log(ADDON_LOG_FATAL, "kodi::gui::CWindow can't create window class from Kodi !!!"); + m_interface->kodi_gui->window->set_callbacks(m_interface->kodiBase, m_controlHandle, this, + CBOnInit, CBOnFocus, CBOnClick, CBOnAction, + CBGetContextButtons, CBOnContextButton); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup CWindow + /// @brief Class destructor. + /// + ~CWindow() override + { + if (m_controlHandle) + m_interface->kodi_gui->window->destroy(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Show this window. + /// + /// Shows this window by activating it, calling close() after it wil activate + /// the current window again. + /// + /// @note If your Add-On ends this window will be closed to. To show it forever, + /// make a loop at the end of your Add-On or use @ref DoModal() instead. + /// + /// @warning If used must be the class be global present until Kodi becomes + /// closed. The creation can be done before "Show" becomes called, but + /// not delete class after them. + /// + /// @return Return true if call and show is successed, if false was something + /// failed to get needed skin parts. + /// + bool Show() + { + return m_interface->kodi_gui->window->show(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Closes this window. + /// + /// Closes this window by activating the old window. + /// @note The window is not deleted with this method. + /// + void Close() { m_interface->kodi_gui->window->close(m_interface->kodiBase, m_controlHandle); } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Display this window until close() is called. + /// + void DoModal() + { + m_interface->kodi_gui->window->do_modal(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Gives the control with the supplied focus. + /// + /// @param[in] controlId On skin defined id of control + /// @return Return true if call and focus is successed, if false was something + /// failed to get needed skin parts + /// + bool SetFocusId(int controlId) + { + return m_interface->kodi_gui->window->set_focus_id(m_interface->kodiBase, m_controlHandle, + controlId); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Returns the id of the control which is focused. + /// + /// @return Focused control id + /// + int GetFocusId() + { + return m_interface->kodi_gui->window->get_focus_id(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief To set the used label on given control id. + /// + /// @param[in] controlId Control id where label need to set + /// @param[in] label Label to use + /// + void SetControlLabel(int controlId, const std::string& label) + { + m_interface->kodi_gui->window->set_control_label(m_interface->kodiBase, m_controlHandle, + controlId, label.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief To set the visibility on given control id. + /// + /// @param[in] controlId Control id where visibility is changed + /// @param[in] visible Boolean value with `true` for visible, `false` for hidden + /// + void SetControlVisible(int controlId, bool visible) + { + m_interface->kodi_gui->window->set_control_visible(m_interface->kodiBase, m_controlHandle, + controlId, visible); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief To set the selection on given control id. + /// + /// @param[in] controlId Control id where selection is changed + /// @param[in] selected Boolean value with `true` for selected, `false` for not + /// + void SetControlSelected(int controlId, bool selected) + { + m_interface->kodi_gui->window->set_control_selected(m_interface->kodiBase, m_controlHandle, + controlId, selected); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Sets a window property, similar to an infolabel. + /// + /// @param[in] key string - property name. + /// @param[in] value string or unicode - value of property. + /// + /// @note Key is NOT case sensitive. Setting value to an empty string is + /// equivalent to clearProperty(key).\n + /// You can use the above as keywords for arguments and skip certain + /// optional arguments.\n + /// Once you use a keyword, all following arguments require the keyword. + /// + void SetProperty(const std::string& key, const std::string& value) + { + m_interface->kodi_gui->window->set_property(m_interface->kodiBase, m_controlHandle, key.c_str(), + value.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Returns a window property as a string, similar to an infolabel. + /// + /// @param[in] key string - property name. + /// @return The property as string (if present) + /// + /// @note Key is NOT case sensitive. Setting value to an empty string is + /// equivalent to clearProperty(key).\n + /// You can use the above as keywords for arguments and skip certain + /// optional arguments.\n + /// Once you use a keyword, all following arguments require the keyword. + /// + std::string GetProperty(const std::string& key) const + { + std::string label; + char* ret = m_interface->kodi_gui->window->get_property(m_interface->kodiBase, m_controlHandle, + key.c_str()); + if (ret != nullptr) + { + if (std::strlen(ret)) + label = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return label; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Sets a window property with integer value + /// + /// @param[in] key string - property name. + /// @param[in] value integer value to set + /// + void SetPropertyInt(const std::string& key, int value) + { + m_interface->kodi_gui->window->set_property_int(m_interface->kodiBase, m_controlHandle, + key.c_str(), value); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Returns a window property with integer value + /// + /// @param[in] key string - property name. + /// @return integer value of property + /// + int GetPropertyInt(const std::string& key) const + { + return m_interface->kodi_gui->window->get_property_int(m_interface->kodiBase, m_controlHandle, + key.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Sets a window property with boolean value + /// + /// @param[in] key string - property name. + /// @param[in] value boolean value to set + /// + void SetPropertyBool(const std::string& key, bool value) + { + m_interface->kodi_gui->window->set_property_bool(m_interface->kodiBase, m_controlHandle, + key.c_str(), value); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Returns a window property with boolean value + /// + /// @param[in] key string - property name. + /// @return boolean value of property + /// + bool GetPropertyBool(const std::string& key) const + { + return m_interface->kodi_gui->window->get_property_bool(m_interface->kodiBase, m_controlHandle, + key.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Sets a window property with double value + /// + /// @param[in] key string - property name. + /// @param[in] value double value to set + /// + void SetPropertyDouble(const std::string& key, double value) + { + m_interface->kodi_gui->window->set_property_double(m_interface->kodiBase, m_controlHandle, + key.c_str(), value); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Returns a window property with double value + /// + /// @param[in] key string - property name. + /// @return double value of property + /// + double GetPropertyDouble(const std::string& key) const + { + return m_interface->kodi_gui->window->get_property_double(m_interface->kodiBase, + m_controlHandle, key.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Remove all present properties from window + /// + void ClearProperties() + { + m_interface->kodi_gui->window->clear_properties(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Clears the specific window property. + /// + /// @param[in] key string - property name. + /// + /// @note Key is NOT case sensitive. Equivalent to SetProperty(key, "") + /// You can use the above as keywords for arguments and skip certain + /// optional arguments. + /// Once you use a keyword, all following arguments require the + /// keyword. + /// + /// + ///----------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// .. + /// ClearProperty('Category') + /// .. + /// ~~~~~~~~~~~~~ + /// + void ClearProperty(const std::string& key) + { + m_interface->kodi_gui->window->clear_property(m_interface->kodiBase, m_controlHandle, + key.c_str()); + } + //---------------------------------------------------------------------------- + + /// @{ + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Function delete all entries in integrated list. + /// + void ClearList() + { + m_interface->kodi_gui->window->clear_item_list(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief To add a list item in the on window integrated list. + /// + /// @param[in] item List item to add + /// @param[in] itemPosition [opt] The position for item, default is on end + /// + void AddListItem(std::shared_ptr item, int itemPosition = -1) + { + m_interface->kodi_gui->window->add_list_item(m_interface->kodiBase, m_controlHandle, + item->m_controlHandle, itemPosition); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief To add a list item based upon string in the on window integrated list. + /// + /// @param[in] item List item to add + /// @param[in] itemPosition [opt] The position for item, default is on end + /// + void AddListItem(const std::string item, int itemPosition = -1) + { + m_interface->kodi_gui->window->add_list_item( + m_interface->kodiBase, m_controlHandle, + std::make_shared(item)->m_controlHandle, itemPosition); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Remove list item on position. + /// + /// @param[in] itemPosition List position to remove + /// + void RemoveListItem(int itemPosition) + { + m_interface->kodi_gui->window->remove_list_item_from_position(m_interface->kodiBase, + m_controlHandle, itemPosition); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Remove item with given control class from list. + /// + /// @param[in] item List item control class to remove + /// + void RemoveListItem(std::shared_ptr item) + { + m_interface->kodi_gui->window->remove_list_item(m_interface->kodiBase, m_controlHandle, + item->m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief To get list item control class on wanted position. + /// + /// @param[in] listPos Position from where control is needed + /// @return The list item control class or null if not found + /// + /// @warning Function returns a new generated **CListItem** class! + /// + std::shared_ptr GetListItem(int listPos) + { + KODI_GUI_LISTITEM_HANDLE handle = m_interface->kodi_gui->window->get_list_item( + m_interface->kodiBase, m_controlHandle, listPos); + if (!handle) + return std::shared_ptr(); + + return std::make_shared(handle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief To set position of selected part in list. + /// + /// @param[in] listPos Position to use + /// + void SetCurrentListPosition(int listPos) + { + m_interface->kodi_gui->window->set_current_list_position(m_interface->kodiBase, m_controlHandle, + listPos); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief To get current selected position in list + /// + /// @return Current list position + /// + int GetCurrentListPosition() + { + return m_interface->kodi_gui->window->get_current_list_position(m_interface->kodiBase, + m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief To get the amount of entries in the list. + /// + /// @return Size of in window integrated control class + /// + int GetListSize() + { + return m_interface->kodi_gui->window->get_list_size(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Sets a container property, similar to an infolabel. + /// + /// @param[in] key string - property name. + /// @param[in] value string or unicode - value of property. + /// + /// @note Key is NOT case sensitive.\n + /// You can use the above as keywords for arguments and skip certain + /// optional arguments.\n + /// Once you use a keyword, all following arguments require the keyword. + /// + void SetContainerProperty(const std::string& key, const std::string& value) + { + m_interface->kodi_gui->window->set_container_property(m_interface->kodiBase, m_controlHandle, + key.c_str(), value.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Sets the content type of the container. + /// + /// @param[in] value string or unicode - content value. + /// + /// __Available content types__ + /// | Name | Media | + /// |:-----------:|:-----------------------------------------| + /// | actors | Videos + /// | addons | Addons, Music, Pictures, Programs, Videos + /// | albums | Music, Videos + /// | artists | Music, Videos + /// | countries | Music, Videos + /// | directors | Videos + /// | files | Music, Videos + /// | games | Games + /// | genres | Music, Videos + /// | images | Pictures + /// | mixed | Music, Videos + /// | movies | Videos + /// | Musicvideos | Music, Videos + /// | playlists | Music, Videos + /// | seasons | Videos + /// | sets | Videos + /// | songs | Music + /// | studios | Music, Videos + /// | tags | Music, Videos + /// | tvshows | Videos + /// | videos | Videos + /// | years | Music, Videos + /// + void SetContainerContent(const std::string& value) + { + m_interface->kodi_gui->window->set_container_content(m_interface->kodiBase, m_controlHandle, + value.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief Get the id of the currently visible container. + /// + /// @return currently visible container id + /// + int GetCurrentContainerId() + { + return m_interface->kodi_gui->window->get_current_container_id(m_interface->kodiBase, + m_controlHandle); + } + //---------------------------------------------------------------------------- + /// @} + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window + /// @brief To inform Kodi that it need to render region new. + /// + void MarkDirtyRegion() + { + return m_interface->kodi_gui->window->mark_dirty_region(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_gui_windows_window_callbacks Callback functions from Kodi to add-on + /// @ingroup cpp_kodi_gui_windows_window + /// @{ + /// @brief GUI window callback functions.\n + /// Functions to handle control callbacks from Kodi + /// + /// ------------------------------------------------------------------------ + /// + /// @link cpp_kodi_gui_windows_window Go back to normal functions from CWindow@endlink + // + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window_callbacks + /// @brief OnInit method. + /// + /// @return Return true if initialize was done successful + /// + /// + virtual bool OnInit() { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window_callbacks + /// @brief OnFocus method. + /// + /// @param[in] controlId GUI control identifier + /// @return Return true if focus condition was handled there or false to handle + /// them by Kodi itself + /// + /// + virtual bool OnFocus(int controlId) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window_callbacks + /// @brief OnClick method. + /// + /// @param[in] controlId GUI control identifier + /// @return Return true if click was handled there or false to handle them by + /// Kodi itself + /// + /// + virtual bool OnClick(int controlId) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window_callbacks + /// @brief OnAction method. + /// + /// @param[in] actionId The action id to perform, see + /// @ref kodi_key_action_ids to get list of + /// them + /// @return Return true if action was handled there + /// or false to handle them by Kodi itself + /// + /// + /// This method will receive all actions that the main program will send + /// to this window. + /// + /// @note + /// - By default, only the @c ADDON_ACTION_PREVIOUS_MENU and @c ADDON_ACTION_NAV_BACK actions are handled. + /// - Overwrite this method to let your code handle all actions. + /// - Don't forget to capture @ref ADDON_ACTION_PREVIOUS_MENU or @ref ADDON_ACTION_NAV_BACK, else the user can't close this window. + /// + /// + ///---------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// .. + /// // Window used with parent / child way + /// bool cYOUR_CLASS::OnAction(ADDON_ACTION actionId) + /// { + /// switch (action) + /// { + /// case ADDON_ACTION_PREVIOUS_MENU: + /// case ADDON_ACTION_NAV_BACK: + /// printf("action recieved: previous"); + /// Close(); + /// return true; + /// case ADDON_ACTION_SHOW_INFO: + /// printf("action recieved: show info"); + /// break; + /// case ADDON_ACTION_STOP: + /// printf("action recieved: stop"); + /// break; + /// case ADDON_ACTION_PAUSE: + /// printf("action recieved: pause"); + /// break; + /// default: + /// break; + /// } + /// return false; + /// } + /// .. + /// ~~~~~~~~~~~~~ + /// + virtual bool OnAction(ADDON_ACTION actionId) + { + switch (actionId) + { + case ADDON_ACTION_PREVIOUS_MENU: + case ADDON_ACTION_NAV_BACK: + Close(); + return true; + default: + break; + } + return false; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window_callbacks + /// @brief Get context menu buttons for list entry. + /// + /// @param[in] itemNumber Selected list item entry + /// @param[in] buttons List where context menus becomes added with his + /// identifier and name + /// + virtual void GetContextButtons(int itemNumber, + std::vector>& buttons) + { + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window_callbacks + /// @brief Called after selection in context menu. + /// + /// @param[in] itemNumber Selected list item entry + /// @param[in] button The pressed button id + /// @return true if handled, otherwise false + /// + virtual bool OnContextButton(int itemNumber, unsigned int button) { return false; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_window_callbacks + /// @brief **Set independent callbacks** + /// + /// If the class is used independent (with "new CWindow") and + /// not as parent (with \"cCLASS_own : public @ref cpp_kodi_gui_windows_window "kodi::gui::CWindow"\") from own must be the + /// callback from Kodi to add-on overdriven with own functions! + /// + /// @param[in] cbhdl The pointer to own handle data structure / class + /// @param[in] CBOnInit Own defined window init function + /// @param[in] CBOnFocus Own defined focus function + /// @param[in] CBOnClick Own defined click function + /// @param[in] CBOnAction Own defined action function + /// @param[in] CBGetContextButtons [opt] To get context menu entries for + /// lists function + /// @param[in] CBOnContextButton [opt] Used context menu entry function + /// + /// + ///---------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// ... + /// + /// bool OnInit(kodi::gui::ClientHandle cbhdl) + /// { + /// ... + /// return true; + /// } + /// + /// bool OnFocus(kodi::gui::ClientHandle cbhdl, int controlId) + /// { + /// ... + /// return true; + /// } + /// + /// bool OnClick(kodi::gui::ClientHandle cbhdl, int controlId) + /// { + /// ... + /// return true; + /// } + /// + /// bool OnAction(kodi::gui::ClientHandle cbhdl, ADDON_ACTION actionId) + /// { + /// ... + /// return true; + /// } + /// + /// ... + /// // Somewhere where you create the window + /// CWindow myWindow = new CWindow; + /// myWindow->SetIndependentCallbacks(myWindow, OnInit, OnFocus, OnClick, OnAction); + /// ... + /// ~~~~~~~~~~~~~ + /// + void SetIndependentCallbacks(kodi::gui::ClientHandle cbhdl, + bool (*CBOnInit)(kodi::gui::ClientHandle cbhdl), + bool (*CBOnFocus)(kodi::gui::ClientHandle cbhdl, int controlId), + bool (*CBOnClick)(kodi::gui::ClientHandle cbhdl, int controlId), + bool (*CBOnAction)(kodi::gui::ClientHandle cbhdl, + ADDON_ACTION actionId), + void (*CBGetContextButtons)(kodi::gui::ClientHandle cbhdl, + int itemNumber, + gui_context_menu_pair* buttons, + unsigned int* size) = nullptr, + bool (*CBOnContextButton)(kodi::gui::ClientHandle cbhdl, + int itemNumber, + unsigned int button) = nullptr) + { + if (!cbhdl || !CBOnInit || !CBOnFocus || !CBOnClick || !CBOnAction) + { + kodi::Log(ADDON_LOG_FATAL, "kodi::gui::CWindow::%s called with nullptr !!!", __FUNCTION__); + return; + } + + m_interface->kodi_gui->window->set_callbacks(m_interface->kodiBase, m_controlHandle, cbhdl, + CBOnInit, CBOnFocus, CBOnClick, CBOnAction, + CBGetContextButtons, CBOnContextButton); + } + //---------------------------------------------------------------------------- + /// @} + +private: + static bool CBOnInit(KODI_GUI_CLIENT_HANDLE cbhdl) + { + return static_cast(cbhdl)->OnInit(); + } + + static bool CBOnFocus(KODI_GUI_CLIENT_HANDLE cbhdl, int controlId) + { + return static_cast(cbhdl)->OnFocus(controlId); + } + + static bool CBOnClick(KODI_GUI_CLIENT_HANDLE cbhdl, int controlId) + { + return static_cast(cbhdl)->OnClick(controlId); + } + + static bool CBOnAction(KODI_GUI_CLIENT_HANDLE cbhdl, ADDON_ACTION actionId) + { + return static_cast(cbhdl)->OnAction(actionId); + } + + static void CBGetContextButtons(KODI_GUI_CLIENT_HANDLE cbhdl, + int itemNumber, + gui_context_menu_pair* buttons, + unsigned int* size) + { + std::vector> buttonList; + static_cast(cbhdl)->GetContextButtons(itemNumber, buttonList); + if (!buttonList.empty()) + { + unsigned int presentSize = static_cast(buttonList.size()); + if (presentSize > *size) + kodi::Log(ADDON_LOG_WARNING, "GetContextButtons: More as allowed '%i' entries present!", + *size); + else + *size = presentSize; + for (unsigned int i = 0; i < *size; ++i) + { + buttons[i].id = buttonList[i].first; + strncpy(buttons[i].name, buttonList[i].second.c_str(), ADDON_MAX_CONTEXT_ENTRY_NAME_LENGTH); + } + } + } + + static bool CBOnContextButton(KODI_GUI_CLIENT_HANDLE cbhdl, int itemNumber, unsigned int button) + { + return static_cast(cbhdl)->OnContextButton(itemNumber, button); + } +}; + +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Button.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Button.h new file mode 100644 index 0000000..873a549 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Button.h @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../c-api/gui/controls/button.h" +#include "../Window.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace controls +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_windows_controls_CButton Control Button +/// @ingroup cpp_kodi_gui_windows_controls +/// @brief @cpp_class{ kodi::gui::controls::CButton } +/// **Standard push button control for window**\n +/// The button control is used for creating push buttons in Kodi. +/// +/// You can choose the position, size, and look of the button, as well as +/// choosing what action(s) should be performed when pushed. +/// +/// It has the header @ref Button.h "#include " +/// be included to enjoy it. +/// +/// Here you find the needed skin part for a @ref skin_Button_control "button control" +/// +/// @note The call of the control is only possible from the corresponding +/// window as its class and identification number is required. +/// +class ATTRIBUTE_HIDDEN CButton : public CAddonGUIControlBase +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CButton + /// @brief Construct a new control. + /// + /// @param[in] window Related window control class + /// @param[in] controlId Used skin xml control id + /// + CButton(CWindow* window, int controlId) : CAddonGUIControlBase(window) + { + m_controlHandle = m_interface->kodi_gui->window->get_control_button( + m_interface->kodiBase, m_Window->GetControlHandle(), controlId); + if (!m_controlHandle) + kodi::Log(ADDON_LOG_FATAL, "kodi::gui::CButton can't create control class from Kodi !!!"); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CButton + /// @brief Destructor. + /// + ~CButton() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CButton + /// @brief Set the control on window to visible. + /// + /// @param[in] visible If true visible, otherwise hidden + /// + void SetVisible(bool visible) + { + m_interface->kodi_gui->control_button->set_visible(m_interface->kodiBase, m_controlHandle, + visible); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CButton + /// @brief Set's the control's enabled/disabled state. + /// + /// @param[in] enabled If true enabled, otherwise disabled + /// + void SetEnabled(bool enabled) + { + m_interface->kodi_gui->control_button->set_enabled(m_interface->kodiBase, m_controlHandle, + enabled); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CButton + /// @brief To set the text string on button. + /// + /// @param[in] label Text to show + /// + void SetLabel(const std::string& label) + { + m_interface->kodi_gui->control_button->set_label(m_interface->kodiBase, m_controlHandle, + label.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CButton + /// @brief Get the used text from button. + /// + /// @return Text shown + /// + std::string GetLabel() const + { + std::string label; + char* ret = + m_interface->kodi_gui->control_button->get_label(m_interface->kodiBase, m_controlHandle); + if (ret != nullptr) + { + if (std::strlen(ret)) + label = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return label; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CButton + /// @brief If two labels are used for button becomes it set with them. + /// + /// @param[in] label Text for second label + /// + void SetLabel2(const std::string& label) + { + m_interface->kodi_gui->control_button->set_label2(m_interface->kodiBase, m_controlHandle, + label.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CButton + /// @brief Get the second label if present. + /// + /// @return Second label + /// + std::string GetLabel2() const + { + std::string label; + char* ret = + m_interface->kodi_gui->control_button->get_label2(m_interface->kodiBase, m_controlHandle); + if (ret != nullptr) + { + if (std::strlen(ret)) + label = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return label; + } + //---------------------------------------------------------------------------- +}; + +} /* namespace controls */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/CMakeLists.txt new file mode 100644 index 0000000..3fdab01 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/CMakeLists.txt @@ -0,0 +1,16 @@ +set(HEADERS Button.h + Edit.h + FadeLabel.h + Image.h + Label.h + Progress.h + RadioButton.h + Rendering.h + SettingsSlider.h + Slider.h + Spin.h + TextBox.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_gui_controls) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Edit.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Edit.h new file mode 100644 index 0000000..00c6231 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Edit.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../c-api/gui/controls/edit.h" +#include "../Window.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace controls +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_windows_controls_CEdit Control Edit +/// @ingroup cpp_kodi_gui_windows_controls +/// @brief @cpp_class{ kodi::gui::controls::CEdit } +/// **Editable window text control used as an input control for the osd keyboard +/// and other input fields**\n +/// The edit control allows a user to input text in Kodi. +/// +/// You can choose the font, size, colour, location and header of the text to be +/// displayed. +/// +/// It has the header @ref Edit.h "#include " +/// be included to enjoy it. +/// +/// Here you find the needed skin partfor a @ref skin_Edit_control "edit control". +/// +/// @note The call of the control is only possible from the corresponding +/// window as its class and identification number is required. +/// + +//============================================================================== +// see gui/definition.h for use of group "cpp_kodi_gui_windows_controls_CEdit_Defs" +/// +/// @defgroup cpp_kodi_gui_windows_controls_CEdit_Defs Definitions, structures and enumerators +/// @ingroup cpp_kodi_gui_windows_controls_CEdit +/// @brief **Library definition values** +/// + +class ATTRIBUTE_HIDDEN CEdit : public CAddonGUIControlBase +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CEdit + /// @brief Construct a new control. + /// + /// @param[in] window Related window control class + /// @param[in] controlId Used skin xml control id + /// + CEdit(CWindow* window, int controlId) : CAddonGUIControlBase(window) + { + m_controlHandle = m_interface->kodi_gui->window->get_control_edit( + m_interface->kodiBase, m_Window->GetControlHandle(), controlId); + if (!m_controlHandle) + kodi::Log(ADDON_LOG_FATAL, + "kodi::gui::control::CEdit can't create control class from Kodi !!!"); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CEdit + /// @brief Destructor. + /// + ~CEdit() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CEdit + /// @brief Set the control on window to visible. + /// + /// @param[in] visible If true visible, otherwise hidden + /// + void SetVisible(bool visible) + { + m_interface->kodi_gui->control_edit->set_visible(m_interface->kodiBase, m_controlHandle, + visible); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CEdit + /// @brief Set's the control's enabled/disabled state. + /// + /// @param[in] enabled If true enabled, otherwise disabled + /// + void SetEnabled(bool enabled) + { + m_interface->kodi_gui->control_edit->set_enabled(m_interface->kodiBase, m_controlHandle, + enabled); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CEdit + /// @brief To set the text string on edit control. + /// + /// @param[in] label Text to show + /// + void SetLabel(const std::string& label) + { + m_interface->kodi_gui->control_edit->set_label(m_interface->kodiBase, m_controlHandle, + label.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CEdit + /// @brief Returns the text heading for this edit control. + /// + /// @return Heading text + /// + std::string GetLabel() const + { + std::string label; + char* ret = + m_interface->kodi_gui->control_edit->get_label(m_interface->kodiBase, m_controlHandle); + if (ret != nullptr) + { + if (std::strlen(ret)) + label = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return label; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CEdit + /// @brief Set's text heading for this edit control. + /// + /// @param[in] text string or unicode - text string. + /// + void SetText(const std::string& text) + { + m_interface->kodi_gui->control_edit->set_text(m_interface->kodiBase, m_controlHandle, + text.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CEdit + /// @brief Returns the text value for this edit control. + /// + /// @return Text value of control + /// + std::string GetText() const + { + std::string text; + char* ret = + m_interface->kodi_gui->control_edit->get_text(m_interface->kodiBase, m_controlHandle); + if (ret != nullptr) + { + if (std::strlen(ret)) + text = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return text; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CEdit + /// @brief Set the cursor position on text. + /// + /// @param[in] position The position to set + /// + void SetCursorPosition(unsigned int position) + { + m_interface->kodi_gui->control_edit->set_cursor_position(m_interface->kodiBase, m_controlHandle, + position); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CEdit + /// @brief To get current cursor position on text field. + /// + /// @return The current cursor position + /// + unsigned int GetCursorPosition() + { + return m_interface->kodi_gui->control_edit->get_cursor_position(m_interface->kodiBase, + m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CEdit + /// @brief To set field input type which are defined on @ref AddonGUIInputType. + /// + /// @param[in] type The @ref AddonGUIInputType "Add-on input type" to use + /// @param[in] heading The heading text for related keyboard dialog + /// + void SetInputType(AddonGUIInputType type, const std::string& heading) + { + m_interface->kodi_gui->control_edit->set_input_type(m_interface->kodiBase, m_controlHandle, + static_cast(type), heading.c_str()); + } + //---------------------------------------------------------------------------- +}; + +} /* namespace controls */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/FadeLabel.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/FadeLabel.h new file mode 100644 index 0000000..01847fb --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/FadeLabel.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../c-api/gui/controls/fade_label.h" +#include "../Window.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace controls +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_windows_controls_CFadeLabel Control Fade Label +/// @ingroup cpp_kodi_gui_windows_controls +/// @brief @cpp_class{ kodi::gui::controls::CFadeLabel } +/// **Window control used to show multiple pieces of text in the same position, +/// by fading from one to the other**\n +/// The fade label control is used for displaying multiple pieces of text in +/// the same space in Kodi. +/// +/// You can choose the font, size, colour, location and contents of the text to +/// be displayed. The first piece of information to display fades in over 50 +/// frames, then scrolls off to the left. Once it is finished scrolling off +/// screen, the second piece of information fades in and the process repeats. +/// A fade label control is not supported in a list container. +/// +/// It has the header @ref FadeLabel.h "#include " +/// be included to enjoy it. +/// +/// Here you find the needed skin part for a @ref Fade_Label_Control "fade label control". +/// +/// @note The call of the control is only possible from the corresponding +/// window as its class and identification number is required. +/// +class ATTRIBUTE_HIDDEN CFadeLabel : public CAddonGUIControlBase +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CFadeLabel + /// @brief Construct a new control. + /// + /// @param[in] window Related window control class + /// @param[in] controlId Used skin xml control id + /// + CFadeLabel(CWindow* window, int controlId) : CAddonGUIControlBase(window) + { + m_controlHandle = m_interface->kodi_gui->window->get_control_fade_label( + m_interface->kodiBase, m_Window->GetControlHandle(), controlId); + if (!m_controlHandle) + kodi::Log(ADDON_LOG_FATAL, + "kodi::gui::controls::CFadeLabel can't create control class from Kodi !!!"); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CFadeLabel + /// @brief Destructor. + /// + ~CFadeLabel() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CFadeLabel + /// @brief Set the control on window to visible. + /// + /// @param[in] visible If true visible, otherwise hidden + /// + void SetVisible(bool visible) + { + m_interface->kodi_gui->control_fade_label->set_visible(m_interface->kodiBase, m_controlHandle, + visible); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CFadeLabel + /// @brief To add additional text string on fade label. + /// + /// @param[in] label Text to show + /// + void AddLabel(const std::string& label) + { + m_interface->kodi_gui->control_fade_label->add_label(m_interface->kodiBase, m_controlHandle, + label.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CFadeLabel + /// @brief Get the used text from button. + /// + /// @return Text shown + /// + std::string GetLabel() const + { + std::string label; + char* ret = m_interface->kodi_gui->control_fade_label->get_label(m_interface->kodiBase, + m_controlHandle); + if (ret != nullptr) + { + if (std::strlen(ret)) + label = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return label; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CFadeLabel + /// @brief To enable or disable scrolling on fade label. + /// + /// @param[in] scroll To enable scrolling set to true, otherwise is disabled + /// + void SetScrolling(bool scroll) + { + m_interface->kodi_gui->control_fade_label->set_scrolling(m_interface->kodiBase, m_controlHandle, + scroll); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CFadeLabel + /// @brief To reset al inserted labels. + /// + void Reset() + { + m_interface->kodi_gui->control_fade_label->reset(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- +}; + +} /* namespace controls */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Image.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Image.h new file mode 100644 index 0000000..9dc493e --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Image.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../c-api/gui/controls/image.h" +#include "../Window.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace controls +{ + +//============================================================================ +/// @defgroup cpp_kodi_gui_windows_controls_CImage Control Image +/// @ingroup cpp_kodi_gui_windows_controls +/// @brief @cpp_class{ kodi::gui::controls::CImage } +/// **Window control used to show an image.**\n +/// The image control is used for displaying images in Kodi. You can choose +/// the position, size, transparency and contents of the image to be displayed. +/// +/// It has the header @ref Image.h "#include " +/// be included to enjoy it. +/// +/// Here you find the needed skin part for a @ref Image_Control "image control". +/// +/// @note The call of the control is only possible from the corresponding +/// window as its class and identification number is required. +/// +class ATTRIBUTE_HIDDEN CImage : public CAddonGUIControlBase +{ +public: + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CImage + /// @brief Construct a new control. + /// + /// @param[in] window Related window control class + /// @param[in] controlId Used skin xml control id + /// + CImage(CWindow* window, int controlId) : CAddonGUIControlBase(window) + { + m_controlHandle = m_interface->kodi_gui->window->get_control_image( + m_interface->kodiBase, m_Window->GetControlHandle(), controlId); + if (!m_controlHandle) + kodi::Log(ADDON_LOG_FATAL, + "kodi::gui::controls::CImage can't create control class from Kodi !!!"); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CImage + /// @brief Destructor. + /// + ~CImage() override = default; + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CImage + /// @brief Set the control on window to visible. + /// + /// @param[in] visible If true visible, otherwise hidden + /// + void SetVisible(bool visible) + { + m_interface->kodi_gui->control_image->set_visible(m_interface->kodiBase, m_controlHandle, + visible); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CImage + /// @brief To set the filename used on image control. + /// + /// @param[in] filename Image file to use + /// @param[in] useCache To define storage of image, default is in cache, if + /// false becomes it loaded always on changes again + /// + void SetFileName(const std::string& filename, bool useCache = true) + { + m_interface->kodi_gui->control_image->set_filename(m_interface->kodiBase, m_controlHandle, + filename.c_str(), useCache); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CImage + /// @brief To set set the diffuse color on image. + /// + /// @param[in] colorDiffuse Color to use for diffuse + /// + void SetColorDiffuse(uint32_t colorDiffuse) + { + m_interface->kodi_gui->control_image->set_color_diffuse(m_interface->kodiBase, m_controlHandle, + colorDiffuse); + } + //-------------------------------------------------------------------------- +}; + +} /* namespace controls */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Label.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Label.h new file mode 100644 index 0000000..d10b85f --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Label.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../c-api/gui/controls/label.h" +#include "../Window.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace controls +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_windows_controls_CLabel Control Label +/// @ingroup cpp_kodi_gui_windows_controls +/// @brief @cpp_class{ kodi::gui::controls::CLabel } +/// **Window control used to show some lines of text**\n +/// The label control is used for displaying text in Kodi. You can choose +/// the font, size, colour, location and contents of the text to be displayed. +/// +/// It has the header @ref Label.h "#include " +/// be included to enjoy it. +/// +/// Here you find the needed skin part for a @ref Label_Control "label control". +/// +/// @note The call of the control is only possible from the corresponding +/// window as its class and identification number is required. +/// +class ATTRIBUTE_HIDDEN CLabel : public CAddonGUIControlBase +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CLabel + /// @brief Construct a new control. + /// + /// @param[in] window Related window control class + /// @param[in] controlId Used skin xml control id + /// + CLabel(CWindow* window, int controlId) : CAddonGUIControlBase(window) + { + m_controlHandle = m_interface->kodi_gui->window->get_control_label( + m_interface->kodiBase, m_Window->GetControlHandle(), controlId); + if (!m_controlHandle) + kodi::Log(ADDON_LOG_FATAL, + "kodi::gui::controls::CLabel can't create control class from Kodi !!!"); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CLabel + /// @brief Destructor. + /// + ~CLabel() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CLabel + /// @brief Set the control on window to visible. + /// + /// @param[in] visible If true visible, otherwise hidden + /// + void SetVisible(bool visible) + { + m_interface->kodi_gui->control_label->set_visible(m_interface->kodiBase, m_controlHandle, + visible); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CLabel + /// @brief To set the text string on label. + /// + /// @param[in] text Text to show + /// + void SetLabel(const std::string& text) + { + m_interface->kodi_gui->control_label->set_label(m_interface->kodiBase, m_controlHandle, + text.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CLabel + /// @brief Get the used text from control. + /// + /// @return Used text on label control + /// + std::string GetLabel() const + { + std::string label; + char* ret = + m_interface->kodi_gui->control_label->get_label(m_interface->kodiBase, m_controlHandle); + if (ret != nullptr) + { + if (std::strlen(ret)) + label = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return label; + } + //---------------------------------------------------------------------------- +}; + +} /* namespace controls */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Progress.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Progress.h new file mode 100644 index 0000000..83b16aa --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Progress.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../c-api/gui/controls/progress.h" +#include "../Window.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace controls +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_windows_controls_CProgress Control Progress +/// @ingroup cpp_kodi_gui_windows_controls +/// @brief @cpp_class{ kodi::gui::controls::CProgress } +/// **Window control to show the progress of a particular operation**\n +/// The progress control is used to show the progress of an item that may take +/// a long time, or to show how far through a movie you are. +/// +/// You can choose the position, size, and look of the progress control. +/// +/// It has the header @ref Progress.h "#include " +/// be included to enjoy it. +/// +/// Here you find the needed skin part for a @ref Progress_Control "progress control". +/// +/// @note The call of the control is only possible from the corresponding +/// window as its class and identification number is required. +/// +class ATTRIBUTE_HIDDEN CProgress : public CAddonGUIControlBase +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CProgress + /// @brief Construct a new control. + /// + /// @param[in] window Related window control class + /// @param[in] controlId Used skin xml control id + /// + CProgress(CWindow* window, int controlId) : CAddonGUIControlBase(window) + { + m_controlHandle = m_interface->kodi_gui->window->get_control_progress( + m_interface->kodiBase, m_Window->GetControlHandle(), controlId); + if (!m_controlHandle) + kodi::Log(ADDON_LOG_FATAL, + "kodi::gui::controls::CProgress can't create control class from Kodi !!!"); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CProgress + /// @brief Destructor. + /// + ~CProgress() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CProgress + /// @brief Set the control on window to visible. + /// + /// @param[in] visible If true visible, otherwise hidden + /// + void SetVisible(bool visible) + { + m_interface->kodi_gui->control_progress->set_visible(m_interface->kodiBase, m_controlHandle, + visible); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CProgress + /// @brief To set Percent position of control. + /// + /// @param[in] percent The percent position to use + /// + void SetPercentage(float percent) + { + m_interface->kodi_gui->control_progress->set_percentage(m_interface->kodiBase, m_controlHandle, + percent); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CProgress + /// @brief Get the active percent position of progress bar. + /// + /// @return Progress position as percent + /// + float GetPercentage() const + { + return m_interface->kodi_gui->control_progress->get_percentage(m_interface->kodiBase, + m_controlHandle); + } + //---------------------------------------------------------------------------- +}; + +} /* namespace controls */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/RadioButton.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/RadioButton.h new file mode 100644 index 0000000..3b6a23c --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/RadioButton.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../c-api/gui/controls/radio_button.h" +#include "../Window.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace controls +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_windows_controls_CRadioButton Control Radio Button +/// @ingroup cpp_kodi_gui_windows_controls +/// @brief @cpp_class{ kodi::gui::controls::CRadioButton } +/// **Window control for a radio button (as used for on/off settings)**\n +/// The radio button control is used for creating push button on/off settings +/// in Kodi. +/// +/// You can choose the position, size, and look of the button. When the user +/// clicks on the radio button, the state will change, toggling the extra +/// textures (textureradioon and textureradiooff). Used for settings +/// controls. +/// +/// It has the header @ref RadioButton.h "#include " +/// be included to enjoy it. +/// +/// Here you find the needed skin part for a @ref Radio_button_control "radio button control". +/// +/// @note The call of the control is only possible from the corresponding +/// window as its class and identification number is required. +/// +/// +/// -------------------------------------------------------------------------- +/// **Example:** +/// ~~~~~~~~~~~~cpp +/// #include +/// +/// #define MY_RADIO_BUTTON_CONTROL 1 +/// +/// class CMyWindow : public kodi::gui::CWindow +/// { +/// public: +/// CMyWindow() +/// +/// void ShowWindow(); +/// +/// bool OnInit() override; +/// bool OnClick(int controlId) override; +/// +/// private: +/// kodi::gui::controls::CSpin m_myRadioButtonControl; +/// }; +/// +/// CMyWindow::CMyWindow() +/// : kodi::gui::CWindow("my_skin.xml", "skin.estuary", true, false), +/// m_myRadioButtonControl(this, MY_RADIO_BUTTON_CONTROL) +/// { +/// } +/// +/// void CMyWindow::ShowWindow() +/// { +/// kodi::gui::CWindow::DoModal(); +/// } +/// +/// bool CMyWindow::OnInit() +/// { +/// m_myRadioButtonControl.SetSelected(false); // can also on skin set to default +/// return true; +/// } +/// +/// bool CMyWindow::OnClick(int controlId) +/// { +/// if (controlId == MY_RADIO_BUTTON_CONTROL) +/// { +/// bool selected = m_myRadioButtonControl.IsSelected(); +/// ... +/// } +/// return true; +/// } +/// return false; +/// } +/// ~~~~~~~~~~~~ +/// +class ATTRIBUTE_HIDDEN CRadioButton : public CAddonGUIControlBase +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CRadioButton + /// @brief Construct a new control. + /// + /// @param[in] window Related window control class + /// @param[in] controlId Used skin xml control id + /// + CRadioButton(CWindow* window, int controlId) : CAddonGUIControlBase(window) + { + m_controlHandle = m_interface->kodi_gui->window->get_control_radio_button( + m_interface->kodiBase, m_Window->GetControlHandle(), controlId); + if (!m_controlHandle) + kodi::Log(ADDON_LOG_FATAL, + "kodi::gui::controls::CRadioButton can't create control class from Kodi !!!"); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CRadioButton + /// @brief Destructor. + /// + ~CRadioButton() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CRadioButton. + /// @brief Set the control on window to visible. + /// + /// @param[in] visible If true visible, otherwise hidden + /// + void SetVisible(bool visible) + { + m_interface->kodi_gui->control_radio_button->set_visible(m_interface->kodiBase, m_controlHandle, + visible); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CRadioButton + /// @brief Set's the control's enabled/disabled state. + /// + /// @param[in] enabled If true enabled, otherwise disabled + /// + void SetEnabled(bool enabled) + { + m_interface->kodi_gui->control_radio_button->set_enabled(m_interface->kodiBase, m_controlHandle, + enabled); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CRadioButton + /// @brief To set the text string on radio button. + /// + /// @param[in] label Text to show + /// + void SetLabel(const std::string& label) + { + m_interface->kodi_gui->control_radio_button->set_label(m_interface->kodiBase, m_controlHandle, + label.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CRadioButton + /// @brief Get the used text from control. + /// + /// @return Text shown + /// + std::string GetLabel() const + { + std::string label; + char* ret = m_interface->kodi_gui->control_radio_button->get_label(m_interface->kodiBase, + m_controlHandle); + if (ret != nullptr) + { + if (std::strlen(ret)) + label = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return label; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CRadioButton + /// @brief To set radio button condition to on or off. + /// + /// @param[in] selected true set radio button to selection on, otherwise off + /// + void SetSelected(bool selected) + { + m_interface->kodi_gui->control_radio_button->set_selected(m_interface->kodiBase, + m_controlHandle, selected); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CRadioButton + /// @brief Get the current selected condition of radio button. + /// + /// @return Selected condition + /// + bool IsSelected() const + { + return m_interface->kodi_gui->control_radio_button->is_selected(m_interface->kodiBase, + m_controlHandle); + } + //---------------------------------------------------------------------------- +}; + +} /* namespace controls */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Rendering.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Rendering.h new file mode 100644 index 0000000..7f5feef --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Rendering.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../c-api/gui/controls/rendering.h" +#include "../Window.h" +#include "../renderHelper.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace controls +{ + +//============================================================================ +/// @defgroup cpp_kodi_gui_windows_controls_CRendering Control Rendering +/// @ingroup cpp_kodi_gui_windows_controls +/// @brief @cpp_class{ kodi::gui::controls::CRendering } +/// **Window control for rendering own parts**\n +/// This rendering control is used when own parts are needed. +/// +/// You have the control over them to render direct OpenGL or DirectX content +/// to the screen set by the size of them. +/// +/// Alternative can be the virtual functions from t his been ignored if the +/// callbacks are defined by the @ref CRendering_SetIndependentCallbacks +/// function and class is used as single and not as a parent class. +/// +/// It has the header @ref Rendering.h "#include " +/// be included to enjoy it. +/// +/// Here you find the needed skin part for a @ref Addon_Rendering_control "rendering control". +/// +/// @note The call of the control is only possible from the corresponding +/// window as its class and identification number is required. +/// +class ATTRIBUTE_HIDDEN CRendering : public CAddonGUIControlBase +{ +public: + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CRendering + /// @brief Construct a new control. + /// + /// @param[in] window Related window control class + /// @param[in] controlId Used skin xml control id + /// + CRendering(CWindow* window, int controlId) : CAddonGUIControlBase(window) + { + m_controlHandle = m_interface->kodi_gui->window->get_control_render_addon( + m_interface->kodiBase, m_Window->GetControlHandle(), controlId); + if (m_controlHandle) + m_interface->kodi_gui->control_rendering->set_callbacks(m_interface->kodiBase, + m_controlHandle, this, OnCreateCB, + OnRenderCB, OnStopCB, OnDirtyCB); + else + kodi::Log(ADDON_LOG_FATAL, "kodi::gui::controls::%s can't create control class from Kodi !!!", + __FUNCTION__); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CRendering + /// @brief Destructor. + /// + ~CRendering() override + { + m_interface->kodi_gui->control_rendering->destroy(m_interface->kodiBase, m_controlHandle); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CRendering + /// @brief To create rendering control on Add-on. + /// + /// Function creates the needed rendering control for Kodi which becomes + /// handled and processed from Add-on + /// + /// @note This is callback function from Kodi to Add-on and not to use + /// for calls from add-on to this function. + /// + /// @param[in] x Horizontal position + /// @param[in] y Vertical position + /// @param[in] w Width of control + /// @param[in] h Height of control + /// @param[in] device The device to use. For OpenGL is empty on Direct X is + /// the needed device send. + /// @return Add-on needs to return true if successed, otherwise false. + /// + /// @note The @ref kodi::HardwareContext is basically a simple pointer which + /// has to be changed to the desired format at the corresponding places using + /// `static_cast<...>(...)`. + /// + virtual bool Create(int x, int y, int w, int h, kodi::HardwareContext device) { return false; } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CRendering + /// @brief Render process call from Kodi. + /// + /// @note This is callback function from Kodi to Add-on and not to use for + /// calls from add-on to this function. + /// + virtual void Render() {} + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CRendering + /// @brief Call from Kodi to stop rendering process. + /// + /// @note This is callback function from Kodi to Add-on and not to use + /// for calls from add-on to this function. + /// + virtual void Stop() {} + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CRendering + /// @brief Call from Kodi where add-on becomes asked about dirty rendering + /// region. + /// + /// @note This is callback function from Kodi to Add-on and not to use + /// for calls from add-on to this function. + /// + /// @return True if a render region is dirty and need rendering. + /// + virtual bool Dirty() { return false; } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CRendering + /// @anchor CRendering_SetIndependentCallbacks + /// @brief If the class is used independent (with "new CRendering") + /// and not as parent (with "cCLASS_own : CRendering") from own must + /// be the callback from Kodi to add-on overdriven with own functions! + /// + /// @param[in] cbhdl Addon related class point where becomes given as value on + /// related functions. + /// @param[in] CBCreate External creation function pointer, see also @ref Create + /// about related values + /// @param[in] CBRender External render function pointer, see also @ref Render + /// about related values + /// @param[in] CBStop External stop function pointer, see also @ref Stop + /// about related values + /// @param[in] CBDirty External dirty function pointer, see also @ref Dirty + /// about related values + /// + void SetIndependentCallbacks(kodi::gui::ClientHandle cbhdl, + bool (*CBCreate)(kodi::gui::ClientHandle cbhdl, + int x, + int y, + int w, + int h, + kodi::HardwareContext device), + void (*CBRender)(kodi::gui::ClientHandle cbhdl), + void (*CBStop)(kodi::gui::ClientHandle cbhdl), + bool (*CBDirty)(kodi::gui::ClientHandle cbhdl)) + { + if (!cbhdl || !CBCreate || !CBRender || !CBStop || !CBDirty) + { + kodi::Log(ADDON_LOG_ERROR, "kodi::gui::controls::%s called with nullptr !!!", __FUNCTION__); + return; + } + + m_interface->kodi_gui->control_rendering->set_callbacks( + m_interface->kodiBase, m_controlHandle, cbhdl, CBCreate, CBRender, CBStop, CBDirty); + } + //-------------------------------------------------------------------------- + +private: + /* + * Defined callback functions from Kodi to add-on, for use in parent / child system + * (is private)! + */ + static bool OnCreateCB( + KODI_GUI_CLIENT_HANDLE cbhdl, int x, int y, int w, int h, ADDON_HARDWARE_CONTEXT device) + { + static_cast(cbhdl)->m_renderHelper = kodi::gui::GetRenderHelper(); + return static_cast(cbhdl)->Create(x, y, w, h, device); + } + + static void OnRenderCB(KODI_GUI_CLIENT_HANDLE cbhdl) + { + if (!static_cast(cbhdl)->m_renderHelper) + return; + static_cast(cbhdl)->m_renderHelper->Begin(); + static_cast(cbhdl)->Render(); + static_cast(cbhdl)->m_renderHelper->End(); + } + + static void OnStopCB(KODI_GUI_CLIENT_HANDLE cbhdl) + { + static_cast(cbhdl)->Stop(); + static_cast(cbhdl)->m_renderHelper = nullptr; + } + + static bool OnDirtyCB(KODI_GUI_CLIENT_HANDLE cbhdl) + { + return static_cast(cbhdl)->Dirty(); + } + + std::shared_ptr m_renderHelper; +}; + +} /* namespace controls */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/SettingsSlider.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/SettingsSlider.h new file mode 100644 index 0000000..5557fc4 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/SettingsSlider.h @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../c-api/gui/controls/settings_slider.h" +#include "../Window.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace controls +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_windows_controls_CSettingsSlider Control Settings Slider +/// @ingroup cpp_kodi_gui_windows_controls +/// @brief @cpp_class{ kodi::gui::controls::CSettingsSlider } +/// **Window control for moveable slider with text name**\n +/// The settings slider control is used in the settings screens for when an +/// option is best specified on a sliding scale. +/// +/// You can choose the position, size, and look of the slider control. It is +/// basically a cross between the button control and a slider control. It has a +/// label and focus and non focus textures, as well as a slider control on the +/// right. +/// +/// It has the header @ref SettingsSlider.h "#include " +/// be included to enjoy it. +/// +/// Here you find the needed skin part for a @ref Settings_Slider_Control "settings slider control". +/// +/// @note The call of the control is only possible from the corresponding +/// window as its class and identification number is required. +/// +class ATTRIBUTE_HIDDEN CSettingsSlider : public CAddonGUIControlBase +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief Construct a new control. + /// + /// @param[in] window Related window control class + /// @param[in] controlId Used skin xml control id + /// + CSettingsSlider(CWindow* window, int controlId) : CAddonGUIControlBase(window) + { + m_controlHandle = m_interface->kodi_gui->window->get_control_settings_slider( + m_interface->kodiBase, m_Window->GetControlHandle(), controlId); + if (!m_controlHandle) + kodi::Log(ADDON_LOG_FATAL, + "kodi::gui::controls::CSettingsSlider can't create control class from Kodi !!!"); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief Destructor. + /// + ~CSettingsSlider() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief Set the control on window to visible. + /// + /// @param[in] visible If true visible, otherwise hidden + /// + void SetVisible(bool visible) + { + m_interface->kodi_gui->control_settings_slider->set_visible(m_interface->kodiBase, + m_controlHandle, visible); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief Set's the control's enabled/disabled state. + /// + /// @param[in] enabled If true enabled, otherwise disabled + /// + void SetEnabled(bool enabled) + { + m_interface->kodi_gui->control_settings_slider->set_enabled(m_interface->kodiBase, + m_controlHandle, enabled); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief To set the text string on settings slider. + /// + /// @param[in] text Text to show + /// + void SetText(const std::string& text) + { + m_interface->kodi_gui->control_settings_slider->set_text(m_interface->kodiBase, m_controlHandle, + text.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief To reset slider on defaults. + /// + void Reset() + { + m_interface->kodi_gui->control_settings_slider->reset(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief To set the the range as integer of slider, e.g. -10 is the slider + /// start and e.g. +10 is the from here defined position where it reach the + /// end. + /// + /// Ad default is the range from 0 to 100. + /// + /// The integer interval is as default 1 and can be changed with + /// @ref SetIntInterval. + /// + /// @param[in] start Integer start value + /// @param[in] end Integer end value + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used. + /// + void SetIntRange(int start, int end) + { + m_interface->kodi_gui->control_settings_slider->set_int_range(m_interface->kodiBase, + m_controlHandle, start, end); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief Set the slider position with the given integer value. The Range + /// must be defined with a call from @ref SetIntRange before. + /// + /// @param[in] value Position in range to set with integer + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used. + /// + void SetIntValue(int value) + { + m_interface->kodi_gui->control_settings_slider->set_int_value(m_interface->kodiBase, + m_controlHandle, value); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief To get the current position as integer value. + /// + /// @return The position as integer + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used. + /// + int GetIntValue() const + { + return m_interface->kodi_gui->control_settings_slider->get_int_value(m_interface->kodiBase, + m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief To set the interval steps of slider, as default is it 1. If it + /// becomes changed with this function will a step of the user with the + /// value fixed here be executed. + /// + /// @param[in] interval Intervall step to set. + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used. + /// + void SetIntInterval(int interval) + { + m_interface->kodi_gui->control_settings_slider->set_int_interval(m_interface->kodiBase, + m_controlHandle, interval); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief Sets the percent of the slider. + /// + /// @param[in] percent float - Percent value of slide + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used. + /// + void SetPercentage(float percent) + { + m_interface->kodi_gui->control_settings_slider->set_percentage(m_interface->kodiBase, + m_controlHandle, percent); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief Returns a float of the percent of the slider. + /// + /// @return float - Percent of slider + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used. + /// + float GetPercentage() const + { + return m_interface->kodi_gui->control_settings_slider->get_percentage(m_interface->kodiBase, + m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief To set the the range as float of slider, e.g. -25.0 is the slider + /// start and e.g. +25.0 is the from here defined position where it reach + /// the end. + /// + /// As default is the range 0.0 to 1.0. + /// + /// The float interval is as default 0.1 and can be changed with + /// @ref SetFloatInterval. + /// + /// @param[in] start Integer start value + /// @param[in] end Integer end value + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used. + /// + void SetFloatRange(float start, float end) + { + m_interface->kodi_gui->control_settings_slider->set_float_range(m_interface->kodiBase, + m_controlHandle, start, end); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief Set the slider position with the given float value. The Range can + /// be defined with a call from @ref SetIntRange before, as default it + /// is 0.0 to 1.0. + /// + /// @param[in] value Position in range to set with float + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used. + /// + void SetFloatValue(float value) + { + m_interface->kodi_gui->control_settings_slider->set_float_value(m_interface->kodiBase, + m_controlHandle, value); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief To get the current position as float value. + /// + /// @return The position as float + /// + float GetFloatValue() const + { + return m_interface->kodi_gui->control_settings_slider->get_float_value(m_interface->kodiBase, + m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSettingsSlider + /// @brief To set the interval steps of slider, as default is it 0.1 If it + /// becomes changed with this function will a step of the user with the + /// value fixed here be executed. + /// + /// @param[in] interval Intervall step to set. + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used. + /// + void SetFloatInterval(float interval) + { + m_interface->kodi_gui->control_settings_slider->set_float_interval(m_interface->kodiBase, + m_controlHandle, interval); + } + //---------------------------------------------------------------------------- +}; + +} /* namespace controls */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Slider.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Slider.h new file mode 100644 index 0000000..077def8 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Slider.h @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../c-api/gui/controls/slider.h" +#include "../Window.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace controls +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_windows_controls_CSlider Control Slider +/// @ingroup cpp_kodi_gui_windows_controls +/// @brief @cpp_class{ kodi::gui::controls::CSlider } +/// **Window control for moveable slider**\n +/// The slider control is used for things where a sliding bar best represents +/// the operation at hand (such as a volume control or seek control). +/// +/// You can choose the position, size, and look of the slider control. +/// +/// It has the header @ref Slider.h "#include " +/// be included to enjoy it. +/// +/// Here you find the needed skin part for a @ref Slider_Control "slider control". +/// +/// @note The call of the control is only possible from the corresponding +/// window as its class and identification number is required. +/// +class ATTRIBUTE_HIDDEN CSlider : public CAddonGUIControlBase +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief Construct a new control. + /// + /// @param[in] window Related window control class + /// @param[in] controlId Used skin xml control id + /// + CSlider(CWindow* window, int controlId) : CAddonGUIControlBase(window) + { + m_controlHandle = m_interface->kodi_gui->window->get_control_slider( + m_interface->kodiBase, m_Window->GetControlHandle(), controlId); + if (!m_controlHandle) + kodi::Log(ADDON_LOG_FATAL, + "kodi::gui::controls::CSlider can't create control class from Kodi !!!"); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief Destructor. + /// + ~CSlider() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief Set the control on window to visible. + /// + /// @param[in] visible If true visible, otherwise hidden + /// + void SetVisible(bool visible) + { + m_interface->kodi_gui->control_slider->set_visible(m_interface->kodiBase, m_controlHandle, + visible); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief Set's the control's enabled/disabled state. + /// + /// @param[in] enabled If true enabled, otherwise disabled + /// + void SetEnabled(bool enabled) + { + m_interface->kodi_gui->control_slider->set_enabled(m_interface->kodiBase, m_controlHandle, + enabled); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief To reset slider on defaults. + /// + void Reset() + { + m_interface->kodi_gui->control_slider->reset(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief With GetDescription becomes a string value of position returned. + /// + /// @return Text string about current slider position + /// + /// The following are the text definition returned from this: + /// | Value | Without range selection | With range selection | + /// |:---------:|:------------------------|:-------------------------------| + /// | float | %2.2f | [%2.2f, %2.2f] | + /// | integer | %i | [%i, %i] | + /// | percent | %i%% | [%i%%, %i%%] | + /// + std::string GetDescription() const + { + std::string text; + char* ret = m_interface->kodi_gui->control_slider->get_description(m_interface->kodiBase, + m_controlHandle); + if (ret != nullptr) + { + if (std::strlen(ret)) + text = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return text; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief To set the the range as integer of slider, e.g. -10 is the slider + /// start and e.g. +10 is the from here defined position where it reach the + /// end. + /// + /// Ad default is the range from 0 to 100. + /// + /// The integer interval is as default 1 and can be changed with + /// @ref SetIntInterval. + /// + /// @param[in] start Integer start value + /// @param[in] end Integer end value + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only one + /// each can be used. + /// + void SetIntRange(int start, int end) + { + m_interface->kodi_gui->control_slider->set_int_range(m_interface->kodiBase, m_controlHandle, + start, end); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief Set the slider position with the given integer value. The Range + /// must be defined with a call from @ref SetIntRange before. + /// + /// @param[in] value Position in range to set with integer + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only one + /// each can be used. + /// + void SetIntValue(int value) + { + m_interface->kodi_gui->control_slider->set_int_value(m_interface->kodiBase, m_controlHandle, + value); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief To get the current position as integer value. + /// + /// @return The position as integer + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used. + /// + int GetIntValue() const + { + return m_interface->kodi_gui->control_slider->get_int_value(m_interface->kodiBase, + m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief To set the interval steps of slider, as default is it 1. If it + /// becomes changed with this function will a step of the user with the + /// value fixed here be executed. + /// + /// @param[in] interval Intervall step to set. + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only one + /// each can be used. + /// + void SetIntInterval(int interval) + { + m_interface->kodi_gui->control_slider->set_int_interval(m_interface->kodiBase, m_controlHandle, + interval); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief Sets the percent of the slider. + /// + /// @param[in] percent float - Percent value of slide + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only one + /// each can be used. + /// + void SetPercentage(float percent) + { + m_interface->kodi_gui->control_slider->set_percentage(m_interface->kodiBase, m_controlHandle, + percent); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief Returns a float of the percent of the slider. + /// + /// @return float - Percent of slider + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only one + /// each can be used. + /// + float GetPercentage() const + { + return m_interface->kodi_gui->control_slider->get_percentage(m_interface->kodiBase, + m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief To set the the range as float of slider, e.g. -25.0 is the slider + /// start and e.g. +25.0 is the from here defined position where it reach + /// the end. + /// + /// As default is the range 0.0 to 1.0. + /// + /// The float interval is as default 0.1 and can be changed with + /// @ref SetFloatInterval. + /// + /// @param[in] start Integer start value + /// @param[in] end Integer end value + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used. + /// + void SetFloatRange(float start, float end) + { + m_interface->kodi_gui->control_slider->set_float_range(m_interface->kodiBase, m_controlHandle, + start, end); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief Set the slider position with the given float value. The Range + /// can be defined with a call from @ref SetIntRange before, as default it + /// is 0.0 to 1.0. + /// + /// @param[in] value Position in range to set with float + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only one + /// each can be used. + /// + void SetFloatValue(float value) + { + m_interface->kodi_gui->control_slider->set_float_value(m_interface->kodiBase, m_controlHandle, + value); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief To get the current position as float value. + /// + /// @return The position as float + /// + float GetFloatValue() const + { + return m_interface->kodi_gui->control_slider->get_float_value(m_interface->kodiBase, + m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSlider + /// @brief To set the interval steps of slider, as default is it 0.1 If it + /// becomes changed with this function will a step of the user with the + /// value fixed here be executed. + /// + /// @param[in] interval Intervall step to set. + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used. + /// + void SetFloatInterval(float interval) + { + m_interface->kodi_gui->control_slider->set_float_interval(m_interface->kodiBase, + m_controlHandle, interval); + } + //---------------------------------------------------------------------------- +}; + +} /* namespace controls */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Spin.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Spin.h new file mode 100644 index 0000000..6c55243 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/Spin.h @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../c-api/gui/controls/spin.h" +#include "../Window.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace controls +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_windows_controls_CSpin Control Spin +/// @ingroup cpp_kodi_gui_windows_controls +/// @brief @cpp_class{ kodi::gui::controls::CSpin } +/// **Window control used for cycling up/down controls**\n +/// The settings spin control is used in the settings screens for when a list +/// of options can be chosen from using up/down arrows. +/// +/// You can choose the position, size, and look of the spin control. It is +/// basically a cross between the button control and a spin control. It has a +/// label and focus and non focus textures, as well as a spin control on the +/// right. +/// +/// It has the header @ref Spin.h "#include " +/// be included to enjoy it. +/// +/// Here you find the needed skin part for a @ref Spin_Control "spin control". +/// +/// @note The call of the control is only possible from the corresponding +/// window as its class and identification number is required. +/// +/// -------------------------------------------------------------------------- +/// **Example:** +/// ~~~~~~~~~~~~cpp +/// #include +/// +/// #define MY_SPIN_CONTROL 1 +/// +/// class CMyWindow : public kodi::gui::CWindow +/// { +/// public: +/// CMyWindow() +/// +/// void ShowWindow(); +/// +/// bool OnInit() override; +/// bool OnClick(int controlId) override; +/// +/// private: +/// kodi::gui::controls::CSpin m_mySpinControl; +/// }; +/// +/// CMyWindow::CMyWindow() +/// : kodi::gui::CWindow("my_skin.xml", "skin.estuary", true, false), +/// m_mySpinControl(this, MY_SPIN_CONTROL) +/// { +/// } +/// +/// void CMyWindow::ShowWindow() +/// { +/// kodi::gui::CWindow::DoModal(); +/// } +/// +/// bool CMyWindow::OnInit() +/// { +/// m_mySpinControl.SetType(kodi::gui::controls::ADDON_SPIN_CONTROL_TYPE_INT); +/// m_mySpinControl.SetIntRange(1, 80); +/// return true; +/// } +/// +/// bool CMyWindow::OnClick(int controlId) +/// { +/// if (controlId == MY_SPIN_CONTROL) +/// { +/// int value = m_mySpinControl.GetIntValue(); +/// ... +/// } +/// return true; +/// } +/// return false; +/// } +/// ~~~~~~~~~~~~ +/// + + +//============================================================================== +/// @ingroup cpp_kodi_gui_windows_controls_CSpin +/// @anchor AddonGUISpinControlType +/// @brief The values here defines the used value format for steps on +/// spin control. +/// +typedef enum AddonGUISpinControlType +{ + /// One spin step interpreted as integer + ADDON_SPIN_CONTROL_TYPE_INT = 1, + /// One spin step interpreted as floating point value + ADDON_SPIN_CONTROL_TYPE_FLOAT = 2, + /// One spin step interpreted as text string + ADDON_SPIN_CONTROL_TYPE_TEXT = 3, + /// One spin step interpreted as a page change value + ADDON_SPIN_CONTROL_TYPE_PAGE = 4 +} AddonGUISpinControlType; +//------------------------------------------------------------------------------ + +class ATTRIBUTE_HIDDEN CSpin : public CAddonGUIControlBase +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief Construct a new control. + /// + /// @param[in] window Related window control class + /// @param[in] controlId Used skin xml control id + /// + CSpin(CWindow* window, int controlId) : CAddonGUIControlBase(window) + { + m_controlHandle = m_interface->kodi_gui->window->get_control_spin( + m_interface->kodiBase, m_Window->GetControlHandle(), controlId); + if (!m_controlHandle) + kodi::Log(ADDON_LOG_FATAL, + "kodi::gui::controls::CSpin can't create control class from Kodi !!!"); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief Destructor. + /// + ~CSpin() override = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief Set the control on window to visible. + /// + /// @param[in] visible If true visible, otherwise hidden + /// + void SetVisible(bool visible) + { + m_interface->kodi_gui->control_spin->set_visible(m_interface->kodiBase, m_controlHandle, + visible); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief Set's the control's enabled/disabled state. + /// + /// @param[in] enabled If true enabled, otherwise disabled + /// + void SetEnabled(bool enabled) + { + m_interface->kodi_gui->control_spin->set_enabled(m_interface->kodiBase, m_controlHandle, + enabled); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief To set the text string on spin control. + /// + /// @param[in] text Text to show as name for spin + /// + void SetText(const std::string& text) + { + m_interface->kodi_gui->control_spin->set_text(m_interface->kodiBase, m_controlHandle, + text.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief To reset spin control to defaults. + /// + void Reset() + { + m_interface->kodi_gui->control_spin->reset(m_interface->kodiBase, m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief To set the with SpinControlType defined types of spin. + /// + /// @param[in] type The type to use + /// + /// @note See description of @ref AddonGUISpinControlType for available types. + /// + void SetType(AddonGUISpinControlType type) + { + m_interface->kodi_gui->control_spin->set_type(m_interface->kodiBase, m_controlHandle, + (int)type); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief To add a label entry in spin defined with a value as string. + /// + /// Format must be set to @ref ADDON_SPIN_CONTROL_TYPE_TEXT to use this function. + /// + /// @param[in] label Label string to view on skin + /// @param[in] value String value to use for selection of them + /// + void AddLabel(const std::string& label, const std::string& value) + { + m_interface->kodi_gui->control_spin->add_string_label(m_interface->kodiBase, m_controlHandle, + label.c_str(), value.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief To add a label entry in spin defined with a value as integer. + /// + /// Format must be set to @ref ADDON_SPIN_CONTROL_TYPE_INT to use this function. + /// + /// @param[in] label Label string to view on skin + /// @param[in] value Integer value to use for selection of them. + /// + void AddLabel(const std::string& label, int value) + { + m_interface->kodi_gui->control_spin->add_int_label(m_interface->kodiBase, m_controlHandle, + label.c_str(), value); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief To change the spin to position with them string as value. + /// + /// Format must be set to @ref ADDON_SPIN_CONTROL_TYPE_TEXT to use this function. + /// + /// @param[in] value String value to change to + /// + void SetStringValue(const std::string& value) + { + m_interface->kodi_gui->control_spin->set_string_value(m_interface->kodiBase, m_controlHandle, + value.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief To get the current spin control position with text string value. + /// + /// Format must be set to @ref ADDON_SPIN_CONTROL_TYPE_TEXT to use this function. + /// + /// @return Currently selected string value + /// + std::string GetStringValue() const + { + std::string value; + char* ret = m_interface->kodi_gui->control_spin->get_string_value(m_interface->kodiBase, + m_controlHandle); + if (ret != nullptr) + { + if (std::strlen(ret)) + value = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return value; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief To set the the range as integer of slider, e.g. -10 is the slider + /// start and e.g. +10 is the from here defined position where it reach the + /// end. + /// + /// Ad default is the range from 0 to 100. + /// + /// @param[in] start Integer start value + /// @param[in] end Integer end value + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used and must be defined with @ref SetType before. + /// + void SetIntRange(int start, int end) + { + m_interface->kodi_gui->control_spin->set_int_range(m_interface->kodiBase, m_controlHandle, + start, end); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief Set the slider position with the given integer value. The Range + /// must be defined with a call from @ref SetIntRange before. + /// + /// @param[in] value Position in range to set with integer + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used and must be defined with @ref SetType before. + /// + void SetIntValue(int value) + { + m_interface->kodi_gui->control_spin->set_int_value(m_interface->kodiBase, m_controlHandle, + value); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief To get the current position as integer value. + /// + /// @return The position as integer + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used and must be defined with @ref SetType before. + /// + int GetIntValue() const + { + return m_interface->kodi_gui->control_spin->get_int_value(m_interface->kodiBase, + m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief To set the the range as float of spin, e.g. -25.0 is the spin + /// start and e.g. +25.0 is the from here defined position where it reach + /// the end. + /// + /// As default is the range 0.0 to 1.0. + /// + /// The float interval is as default 0.1 and can be changed with + /// @ref SetFloatInterval. + /// + /// @param[in] start Integer start value + /// @param[in] end Integer end value + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used and must be defined with @ref SetType before. + /// + void SetFloatRange(float start, float end) + { + m_interface->kodi_gui->control_spin->set_float_range(m_interface->kodiBase, m_controlHandle, + start, end); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief Set the spin position with the given float value. The Range + /// can be defined with a call from @ref SetIntRange before, as default it + /// is 0.0 to 1.0. + /// + /// @param[in] value Position in range to set with float + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used and must be defined with @ref SetType before. + /// + void SetFloatValue(float value) + { + m_interface->kodi_gui->control_spin->set_float_value(m_interface->kodiBase, m_controlHandle, + value); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief To get the current position as float value. + /// + /// @return The position as float + /// + float GetFloatValue() const + { + return m_interface->kodi_gui->control_spin->get_float_value(m_interface->kodiBase, + m_controlHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_windows_controls_CSpin + /// @brief To set the interval steps of spin, as default is it 0.1 If it + /// becomes changed with this function will a step of the user with the + /// value fixed here be executed. + /// + /// @param[in] interval Intervall step to set. + /// + /// @note Percent, floating point or integer are alone possible. Combining + /// these different values can be not together and can, therefore, only + /// one each can be used and must be defined with @ref SetType before. + /// + void SetFloatInterval(float interval) + { + m_interface->kodi_gui->control_spin->set_float_interval(m_interface->kodiBase, m_controlHandle, + interval); + } + //---------------------------------------------------------------------------- +}; + +} /* namespace controls */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/TextBox.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/TextBox.h new file mode 100644 index 0000000..2634568 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/controls/TextBox.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../c-api/gui/controls/text_box.h" +#include "../Window.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace controls +{ + +//============================================================================ +/// @defgroup cpp_kodi_gui_windows_controls_CTextBox Control Text Box +/// @ingroup cpp_kodi_gui_windows_controls +/// @brief @cpp_class{ kodi::gui::controls::CTextBox } +/// **Used to show a multi-page piece of text**\n +/// The text box control can be used to display descriptions, help texts or +/// other larger texts. +/// +/// It corresponds to the representation which is also to be seen on the +/// @ref CDialogTextViewer. +/// +/// It has the header @ref TextBox.h "#include " +/// be included to enjoy it. +/// +/// Here you find the needed skin part for a @ref Text_Box "textbox control". +/// +/// @note The call of the control is only possible from the corresponding +/// window as its class and identification number is required. +/// +class ATTRIBUTE_HIDDEN CTextBox : public CAddonGUIControlBase +{ +public: + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CTextBox + /// @brief Construct a new control. + /// + /// @param[in] window related window control class + /// @param[in] controlId Used skin xml control id + /// + CTextBox(CWindow* window, int controlId) : CAddonGUIControlBase(window) + { + m_controlHandle = m_interface->kodi_gui->window->get_control_text_box( + m_interface->kodiBase, m_Window->GetControlHandle(), controlId); + if (!m_controlHandle) + kodi::Log(ADDON_LOG_FATAL, + "kodi::gui::controls::CTextBox can't create control class from Kodi !!!"); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CTextBox + /// @brief Destructor. + /// + ~CTextBox() override = default; + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CTextBox + /// @brief Set the control on window to visible. + /// + /// @param[in] visible If true visible, otherwise hidden + /// + void SetVisible(bool visible) + { + m_interface->kodi_gui->control_text_box->set_visible(m_interface->kodiBase, m_controlHandle, + visible); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CTextBox + /// @brief To reset box an remove all the text. + /// + void Reset() { m_interface->kodi_gui->control_text_box->reset(m_controlHandle, m_controlHandle); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CTextBox + /// @brief To set the text on box. + /// + /// @param[in] text Text to show + /// + void SetText(const std::string& text) + { + m_interface->kodi_gui->control_text_box->set_text(m_interface->kodiBase, m_controlHandle, + text.c_str()); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CTextBox + /// @brief Get the used text from control. + /// + /// @return Text shown + /// + std::string GetText() const + { + std::string text; + char* ret = + m_interface->kodi_gui->control_text_box->get_text(m_interface->kodiBase, m_controlHandle); + if (ret != nullptr) + { + if (std::strlen(ret)) + text = ret; + m_interface->free_string(m_interface->kodiBase, ret); + } + return text; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CTextBox + /// @brief To scroll text on other position. + /// + /// @param[in] position The line position to scroll to + /// + void Scroll(unsigned int position) + { + m_interface->kodi_gui->control_text_box->scroll(m_interface->kodiBase, m_controlHandle, + position); + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_windows_controls_CTextBox + /// @brief To set automatic scrolling of textbox + /// + /// Specifies the timing and conditions of any autoscrolling this textbox + /// should have. Times are in milliseconds. The content is delayed for the + /// given delay, then scrolls at a rate of one line per time interval until + /// the end. If the repeat tag is present, it then delays for the repeat + /// time, fades out over 1 second, and repeats. It does not wrap or reset + /// to the top at the end of the scroll. + /// + /// @param[in] delay Content delay + /// @param[in] time One line per time interval + /// @param[in] repeat Delays with given time, fades out over 1 second, and + /// repeats + /// + void SetAutoScrolling(int delay, int time, int repeat) + { + m_interface->kodi_gui->control_text_box->set_auto_scrolling( + m_interface->kodiBase, m_controlHandle, delay, time, repeat); + } + //-------------------------------------------------------------------------- +}; + +} /* namespace controls */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/CMakeLists.txt new file mode 100644 index 0000000..9aaee4f --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/CMakeLists.txt @@ -0,0 +1,14 @@ +set(HEADERS ContextMenu.h + ExtendedProgress.h + FileBrowser.h + Keyboard.h + Numeric.h + OK.h + Progress.h + Select.h + TextViewer.h + YesNo.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_gui_dialogs) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/ContextMenu.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/ContextMenu.h new file mode 100644 index 0000000..b576b9a --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/ContextMenu.h @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/gui/dialogs/context_menu.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace dialogs +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_dialogs_ContextMenu Dialog Context Menu +/// @ingroup cpp_kodi_gui_dialogs +/// @brief @cpp_namespace{ kodi::gui::dialogs::ContextMenu } +/// **Context menu dialog**@n +/// The function listed below permits the call of a dialogue as context menu to +/// select of an entry as a key +/// +/// It has the header @ref ContextMenu.h "#include " +/// be included to enjoy it. +/// +/// +namespace ContextMenu +{ +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_ContextMenu +/// @brief Show a context menu dialog about given parts. +/// +/// @param[in] heading Dialog heading name +/// @param[in] entries String list about entries +/// @return The selected entry, if return -1 was nothing selected or canceled +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// const std::vector entries +/// { +/// "Test 1", +/// "Test 2", +/// "Test 3", +/// "Test 4", +/// "Test 5" +/// }; +/// +/// int selected = kodi::gui::dialogs::ContextMenu::Show("Test selection", entries); +/// if (selected < 0) +/// fprintf(stderr, "Item selection canceled\n"); +/// else +/// fprintf(stderr, "Selected item is: %i\n", selected); +/// ~~~~~~~~~~~~~ +/// +inline int ATTRIBUTE_HIDDEN Show(const std::string& heading, + const std::vector& entries) +{ + using namespace ::kodi::addon; + unsigned int size = static_cast(entries.size()); + const char** cEntries = static_cast(malloc(size * sizeof(const char**))); + for (unsigned int i = 0; i < size; ++i) + { + cEntries[i] = entries[i].c_str(); + } + int ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogContextMenu->open( + CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), cEntries, size); + free(cEntries); + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_ContextMenu +/// @brief Show a context menu dialog about given parts. +/// +/// @param[in] heading Dialog heading name +/// @param[in] entries String list about entries +/// @return The selected entry, if return -1 was nothing selected or canceled +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// const std::vector> entries +/// { +/// { "ID 1", "Test 1" }, +/// { "ID 2", "Test 2" }, +/// { "ID 3", "Test 3" }, +/// { "ID 4", "Test 4" }, +/// { "ID 5", "Test 5" } +/// }; +/// +/// int selected = kodi::gui::dialogs::ContextMenu::Show("Test selection", entries); +/// if (selected < 0) +/// fprintf(stderr, "Item selection canceled\n"); +/// else +/// fprintf(stderr, "Selected item is: %i\n", selected); +/// ~~~~~~~~~~~~~ +/// +inline int ATTRIBUTE_HIDDEN Show(const std::string& heading, + const std::vector>& entries) +{ + using namespace ::kodi::addon; + unsigned int size = static_cast(entries.size()); + const char** cEntries = static_cast(malloc(size * sizeof(const char**))); + for (unsigned int i = 0; i < size; ++i) + { + cEntries[i] = entries[i].second.c_str(); + } + int ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogContextMenu->open( + CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), cEntries, size); + free(cEntries); + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_ContextMenu +/// @brief Show a context menu dialog about given parts. +/// +/// @param[in] heading Dialog heading name +/// @param[in] entries String list about entries +/// @return The selected entry, if return -1 was nothing selected or canceled +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// const std::vector> entries +/// { +/// { 1, "Test 1" }, +/// { 2, "Test 2" }, +/// { 3, "Test 3" }, +/// { 4, "Test 4" }, +/// { 5, "Test 5" } +/// }; +/// +/// int selected = kodi::gui::dialogs::ContextMenu::Show("Test selection", entries); +/// if (selected < 0) +/// fprintf(stderr, "Item selection canceled\n"); +/// else +/// fprintf(stderr, "Selected item is: %i\n", selected); +/// ~~~~~~~~~~~~~ +/// +inline int ATTRIBUTE_HIDDEN Show(const std::string& heading, + const std::vector>& entries) +{ + using namespace ::kodi::addon; + unsigned int size = static_cast(entries.size()); + const char** cEntries = static_cast(malloc(size * sizeof(const char**))); + for (unsigned int i = 0; i < size; ++i) + { + cEntries[i] = entries[i].second.c_str(); + } + int ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogContextMenu->open( + CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), cEntries, size); + free(cEntries); + return ret; +} +//------------------------------------------------------------------------------ +}; // namespace ContextMenu + +} /* namespace dialogs */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/ExtendedProgress.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/ExtendedProgress.h new file mode 100644 index 0000000..c650483 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/ExtendedProgress.h @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/gui/dialogs/extended_progress.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace dialogs +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_dialogs_CExtendedProgress Dialog Extended Progress +/// @ingroup cpp_kodi_gui_dialogs +/// @brief @cpp_class{ kodi::gui::dialogs::ExtendedProgress } +/// **Progress dialog shown for background work** +/// +/// The with @ref ExtendedProgress.h "#include " +/// given class are basically used to create Kodi's extended progress. +/// +/// +/// -------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// kodi::gui::dialogs::CExtendedProgress *ext_progress = new kodi::gui::dialogs::CExtendedProgress("Test Extended progress"); +/// ext_progress->SetText("Test progress"); +/// for (unsigned int i = 0; i < 50; i += 10) +/// { +/// ext_progress->SetProgress(i, 100); +/// sleep(1); +/// } +/// +/// ext_progress->SetTitle("Test Extended progress - Second round"); +/// ext_progress->SetText("Test progress - Step 2"); +/// +/// for (unsigned int i = 50; i < 100; i += 10) +/// { +/// ext_progress->SetProgress(i, 100); +/// sleep(1); +/// } +/// delete ext_progress; +/// ~~~~~~~~~~~~~ +/// +class ATTRIBUTE_HIDDEN CExtendedProgress +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CExtendedProgress + /// Construct a new dialog. + /// + /// @param[in] title [opt] Title string + /// + explicit CExtendedProgress(const std::string& title = "") + { + using namespace ::kodi::addon; + m_DialogHandle = CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->new_dialog( + CAddonBase::m_interface->toKodi->kodiBase, title.c_str()); + if (!m_DialogHandle) + kodi::Log(ADDON_LOG_FATAL, + "kodi::gui::CDialogExtendedProgress can't create window class from Kodi !!!"); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CExtendedProgress + /// Destructor. + /// + ~CExtendedProgress() + { + using namespace ::kodi::addon; + if (m_DialogHandle) + CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->delete_dialog( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CExtendedProgress + /// @brief Get the used title. + /// + /// @return Title string + /// + std::string Title() const + { + using namespace ::kodi::addon; + std::string text; + char* strMsg = CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->get_title( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); + if (strMsg != nullptr) + { + if (std::strlen(strMsg)) + text = strMsg; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + strMsg); + } + return text; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CExtendedProgress + /// @brief To set the title of dialog. + /// + /// @param[in] title Title string + /// + void SetTitle(const std::string& title) + { + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->set_title( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, title.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CExtendedProgress + /// @brief Get the used text information string. + /// + /// @return Text string + /// + std::string Text() const + { + using namespace ::kodi::addon; + std::string text; + char* strMsg = CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->get_text( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); + if (strMsg != nullptr) + { + if (std::strlen(strMsg)) + text = strMsg; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + strMsg); + } + return text; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CExtendedProgress + /// @brief To set the used text information string. + /// + /// @param[in] text Information text to set + /// + void SetText(const std::string& text) + { + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->set_text( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, text.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CExtendedProgress + /// @brief To ask dialog is finished. + /// + /// @return True if on end + /// + bool IsFinished() const + { + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->is_finished( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CExtendedProgress + /// @brief Mark progress finished. + /// + void MarkFinished() + { + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->mark_finished( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CExtendedProgress + /// @brief Get the current progress position as percent. + /// + /// @return Position + /// + float Percentage() const + { + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->get_percentage( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CExtendedProgress + /// @brief To set the current progress position as percent. + /// + /// @param[in] percentage Position to use from 0.0 to 100.0 + /// + void SetPercentage(float percentage) + { + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->set_percentage( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, percentage); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CExtendedProgress + /// @brief To set progress position with predefined places. + /// + /// @param[in] currentItem Place position to use + /// @param[in] itemCount Amount of used places + /// + void SetProgress(int currentItem, int itemCount) + { + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogExtendedProgress->set_progress( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, currentItem, itemCount); + } + //---------------------------------------------------------------------------- + +private: + KODI_GUI_HANDLE m_DialogHandle; +}; + +} /* namespace dialogs */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/FileBrowser.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/FileBrowser.h new file mode 100644 index 0000000..244c76c --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/FileBrowser.h @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/gui/dialogs/filebrowser.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace dialogs +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_dialogs_FileBrowser Dialog File Browser +/// @ingroup cpp_kodi_gui_dialogs +/// @brief @cpp_namespace{ kodi::gui::dialogs::FileBrowser } +/// **File browser dialog**\n +/// The functions listed below of the class "FileBrowser" offer the possibility +/// to select to a file by the user of the add-on. +/// +/// It allows all the options that are possible in Kodi itself and offers all +/// support file types. +/// +/// It has the header @ref FileBrowser.h "#include " +/// be included to enjoy it. +/// +namespace FileBrowser +{ +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_FileBrowser +/// @brief Directory selection dialog. +/// +/// @param[in] shares With Shares becomes the available start folders be set +/// @param[in] heading Dialog header name +/// @param[in,out] path As in the path to start and return value about +/// selected directory +/// @param[in] writeOnly [opt] If set only writeable folders are shown +/// @return False if selection becomes canceled +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// // Example show directory selection dialog with on 'share' (first value) +/// // defined directory types. +/// // +/// // If this becomes leaved empty and 'directory' is empty goes it to the +/// // base path of the hard disk. +/// // +/// // Also can be with path written to 'directory' before the dialog forced +/// // to a start place. +/// std::string directory; +/// bool ret = kodi::gui::dialogs::FileBrowser::ShowAndGetDirectory("local|network|removable", +/// "Test directory selection", +/// directory, +/// false); +/// fprintf(stderr, "Selected directory is : %s and was %s\n", directory.c_str(), ret ? "OK" : "Canceled"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetDirectory(const std::string& shares, + const std::string& heading, + std::string& path, + bool writeOnly = false) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_directory( + CAddonBase::m_interface->toKodi->kodiBase, shares.c_str(), heading.c_str(), path.c_str(), + &retString, writeOnly); + if (retString != nullptr) + { + if (std::strlen(retString)) + path = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_FileBrowser +/// @brief File selection dialog. +/// +/// @param[in] shares With Shares becomes the available start folders be set. +/// @param[in] mask The mask to filter visible files, e.g. ".m3u|.pls|.b4s|.wpl" +/// @param[in] heading Dialog header name +/// @param[in,out] path As in the path to start and Return value about selected +/// file +/// @param[in] useThumbs [opt] If set show thumbs if possible on dialog +/// @param[in] useFileDirectories [opt] If set also packages (e.g. *.zip) are +/// handled as directories. +/// @return False if selection becomes canceled +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetFile(const std::string& shares, + const std::string& mask, + const std::string& heading, + std::string& path, + bool useThumbs = false, + bool useFileDirectories = false) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_file( + CAddonBase::m_interface->toKodi->kodiBase, shares.c_str(), mask.c_str(), heading.c_str(), + path.c_str(), &retString, useThumbs, useFileDirectories); + if (retString != nullptr) + { + if (std::strlen(retString)) + path = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_FileBrowser +/// @brief File selection from a directory. +/// +/// @param[in] directory The directory name where the dialog start, possible are +/// normal names and kodi's special names +/// @param[in] mask The mask to filter visible files, e.g. ".m3u|.pls|.b4s|.wpl" +/// @param[in] heading Dialog header name +/// @param[in,out] path As in the path to start and Return value about selected +/// file +/// @param[in] useThumbs [opt] If set show thumbs if possible on dialog +/// @param[in] useFileDirectories [opt] If set also packages (e.g. *.zip) are +/// handled as directories +/// @param[in] singleList [opt] +/// @return False if selection becomes canceled +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetFileFromDir(const std::string& directory, + const std::string& mask, + const std::string& heading, + std::string& path, + bool useThumbs = false, + bool useFileDirectories = false, + bool singleList = false) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = + CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_file_from_dir( + CAddonBase::m_interface->toKodi->kodiBase, directory.c_str(), mask.c_str(), + heading.c_str(), path.c_str(), &retString, useThumbs, useFileDirectories, singleList); + if (retString != nullptr) + { + if (std::strlen(retString)) + path = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_FileBrowser +/// @brief File selection dialog to get several in to a list. +/// +/// @param[in] shares With Shares becomes the available start folders be set. +/// @param[in] mask The mask to filter visible files, e.g. ".m3u|.pls|.b4s|.wpl" +/// @param[in] heading Dialog header name +/// @param[out] fileList Return value about selected files +/// @param[in] useThumbs [opt] If set show thumbs if possible on dialog. +/// @param[in] useFileDirectories [opt] If set also packages (e.g. *.zip) are +/// handled as directories. +/// @return False if selection becomes canceled. +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetFileList(const std::string& shares, + const std::string& mask, + const std::string& heading, + std::vector& fileList, + bool useThumbs = false, + bool useFileDirectories = false) +{ + using namespace ::kodi::addon; + char** list = nullptr; + unsigned int listSize = 0; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_file_list( + CAddonBase::m_interface->toKodi->kodiBase, shares.c_str(), mask.c_str(), heading.c_str(), + &list, &listSize, useThumbs, useFileDirectories); + if (ret) + { + for (unsigned int i = 0; i < listSize; ++i) + fileList.emplace_back(list[i]); + CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->clear_file_list( + CAddonBase::m_interface->toKodi->kodiBase, &list, listSize); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_FileBrowser +/// @brief Source selection dialog. +/// +/// @param[in,out] path As in the path to start and Return value about selected +/// source +/// @param[in] allowNetworkShares Allow also access to network +/// @param[in] additionalShare [opt] With additionalShare becomes the available +/// start folders be set. +/// @param[in] type [opt] +/// @return False if selection becomes canceled +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetSource(std::string& path, + bool allowNetworkShares, + const std::string& additionalShare = "", + const std::string& type = "") +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_source( + CAddonBase::m_interface->toKodi->kodiBase, path.c_str(), &retString, allowNetworkShares, + additionalShare.c_str(), type.c_str()); + if (retString != nullptr) + { + if (std::strlen(retString)) + path = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_FileBrowser +/// @brief Image selection dialog. +/// +/// @param[in] shares With Shares becomes the available start folders be set +/// @param[in] heading Dialog header name +/// @param[out] path Return value about selected image +/// @return False if selection becomes canceled +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetImage(const std::string& shares, + const std::string& heading, + std::string& path) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_image( + CAddonBase::m_interface->toKodi->kodiBase, shares.c_str(), heading.c_str(), path.c_str(), + &retString); + if (retString != nullptr) + { + if (std::strlen(retString)) + path = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_FileBrowser +/// @brief Image selection dialog to get several in to a list. +/// +/// @param[in] shares With Shares becomes the available start folders be set +/// @param[in] heading Dialog header name +/// @param[out] file_list Return value about selected images +/// @return False if selection becomes canceled +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetImageList(const std::string& shares, + const std::string& heading, + std::vector& file_list) +{ + using namespace ::kodi::addon; + char** list = nullptr; + unsigned int listSize = 0; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_image_list( + CAddonBase::m_interface->toKodi->kodiBase, shares.c_str(), heading.c_str(), &list, &listSize); + if (ret) + { + for (unsigned int i = 0; i < listSize; ++i) + file_list.emplace_back(list[i]); + CAddonBase::m_interface->toKodi->kodi_gui->dialogFileBrowser->clear_file_list( + CAddonBase::m_interface->toKodi->kodiBase, &list, listSize); + } + return ret; +} +//------------------------------------------------------------------------------ +}; // namespace FileBrowser + +} /* namespace dialogs */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Keyboard.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Keyboard.h new file mode 100644 index 0000000..710b7dd --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Keyboard.h @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/gui/dialogs/keyboard.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace dialogs +{ + +//================================================================================ +/// @defgroup cpp_kodi_gui_dialogs_Keyboard Dialog Keyboard +/// @ingroup cpp_kodi_gui_dialogs +/// @brief @cpp_namespace{ kodi::gui::dialogs::Keyboard } +/// **Keyboard dialogs**\n +/// The functions listed below have to be permitted by the user for the +/// representation of a keyboard around an input. +/// +/// The class supports several kinds, from an easy text choice up to the +/// passport Word production and their confirmation for add-on. +/// +/// It has the header @ref Keyboard.h "#include " +/// be included to enjoy it. +/// +namespace Keyboard +{ +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Keyboard +/// @brief Show keyboard with initial value `text` and replace with result +/// string. +/// +/// @param[in,out] text Overwritten with user input if return=true. +/// @param[in] heading String shown on dialog title. +/// @param[in] allowEmptyResult Whether a blank password is valid or not. +/// @param[in] hiddenInput [opt] The inserted input is not shown as text. +/// @param[in] autoCloseMs [opt] To close the dialog after a specified time, in +/// milliseconds, default is 0 which keeps the dialog +/// open indefinitely. +/// @return true if successful display and user input. false if unsuccessful +/// display, no user input, or canceled editing. +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// // The example shows the display of keyboard call dialog at Kodi from the add-on. +/// // Below all values are set, however, can last two (hidden input = false and autoCloseMs = 0) +/// // to be released if not needed. +/// std::string text = "Please change me to them want you want"; // It can be leaved empty or a entry text added +/// bool bRet = ::kodi::gui::dialogs::Keyboard::ShowAndGetInput(text, +/// "Demonstration text entry", +/// true, +/// false, +/// 0); +/// fprintf(stderr, "Written keyboard input is : '%s' and was %s\n", +/// text.c_str(), bRet ? "OK" : "Canceled"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetInput(std::string& text, + const std::string& heading, + bool allowEmptyResult, + bool hiddenInput = false, + unsigned int autoCloseMs = 0) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = + CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_get_input_with_head( + CAddonBase::m_interface->toKodi->kodiBase, text.c_str(), &retString, heading.c_str(), + allowEmptyResult, hiddenInput, autoCloseMs); + if (retString != nullptr) + { + text = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Keyboard +/// @brief The example shows the display of keyboard call dialog at Kodi +/// from the add-on. +/// +/// @param[out] text Overwritten with user input if return=true. +/// @param[in] allowEmptyResult If set to true keyboard can also exited without +/// entered text. +/// @param[in] autoCloseMs [opt] To close the dialog after a specified time, in +/// milliseconds, default is 0 which keeps the dialog +/// open indefinitely. +/// @return true if successful display and user input. false if unsuccessful +/// display, no user input, or canceled editing. +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetInput(std::string& text, + bool allowEmptyResult, + unsigned int autoCloseMs = 0) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_get_input( + CAddonBase::m_interface->toKodi->kodiBase, text.c_str(), &retString, allowEmptyResult, + autoCloseMs); + if (retString != nullptr) + { + text = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Keyboard +/// @brief Shows keyboard and prompts for a password. Differs from +/// `ShowAndVerifyNewPassword()` in that no second verification. +/// +/// @param[in,out] newPassword Overwritten with user input if return=true. +/// @param[in] heading String shown on dialog title. +/// @param[in] allowEmptyResult Whether a blank password is valid or not. +/// @param[in] autoCloseMs [opt] To close the dialog after a specified time, in +/// milliseconds, default is 0 which keeps the dialog +/// open indefinitely. +/// @return true if successful display and user input. false if unsuccessful +/// display, no user input, or canceled editing. +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetNewPassword(std::string& newPassword, + const std::string& heading, + bool allowEmptyResult, + unsigned int autoCloseMs = 0) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard + ->show_and_get_new_password_with_head( + CAddonBase::m_interface->toKodi->kodiBase, newPassword.c_str(), &retString, + heading.c_str(), allowEmptyResult, autoCloseMs); + if (retString != nullptr) + { + newPassword = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Keyboard +/// @brief Shows keyboard and prompts for a password. Differs from +/// `ShowAndVerifyNewPassword()` in that no second verification. +/// +/// @param[in,out] newPassword Overwritten with user input if return=true. +/// @param[in] autoCloseMs [opt] To close the dialog after a specified time, in +/// milliseconds, default is 0 which keeps the dialog +/// open indefinitely. +/// @return true if successful display and user input. false if unsuccessful +/// display, no user input, or canceled editing. +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetNewPassword(std::string& newPassword, + unsigned int autoCloseMs = 0) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_get_new_password( + CAddonBase::m_interface->toKodi->kodiBase, newPassword.c_str(), &retString, autoCloseMs); + if (retString != nullptr) + { + newPassword = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Keyboard +/// @brief Show keyboard twice to get and confirm a user-entered password +/// string. +/// +/// @param[out] newPassword Overwritten with user input if return=true. +/// @param[in] heading String shown on dialog title. +/// @param[in] allowEmptyResult +/// @param[in] autoCloseMs [opt] To close the dialog after a specified time, in +/// milliseconds, default is 0 which keeps the dialog +/// open indefinitely. +/// @return true if successful display and user input. false if unsuccessful +/// display, no user input, or canceled editing. +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// #include +/// +/// // The example below shows the complete use of keyboard dialog for password +/// // check. If only one check from add-on needed can be function with retries +/// // set to '0' called alone. +/// // +/// // The use of MD5 translated password is always required for the check on Kodi! +/// +/// int maxretries = 3; +/// // Password names need to be send as md5 sum to kodi. +/// std::string password; +/// kodi::GetMD5("kodi", password); +/// +/// // To the loop about password checks. +/// int ret; +/// for (unsigned int i = 0; i < maxretries; i++) +/// { +/// // Ask the user about the password. +/// ret = ::kodi::gui::dialogs::Keyboard::ShowAndVerifyPassword(password, "Demo password call for PW 'kodi'", i, 0); +/// if (ret == 0) +/// { +/// fprintf(stderr, "Password successfull confirmed after '%i' tries\n", i+1); +/// break; +/// } +/// else if (ret < 0) +/// { +/// fprintf(stderr, "Canceled editing on try '%i'\n", i+1); +/// break; +/// } +/// else // if (ret > 0) +/// { +/// fprintf(stderr, "Wrong password entered on try '%i'\n", i+1); +/// } +/// } +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN ShowAndVerifyNewPassword(std::string& newPassword, + const std::string& heading, + bool allowEmptyResult, + unsigned int autoCloseMs = 0) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard + ->show_and_verify_new_password_with_head(CAddonBase::m_interface->toKodi->kodiBase, + &retString, heading.c_str(), + allowEmptyResult, autoCloseMs); + if (retString != nullptr) + { + newPassword = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Keyboard +/// @brief Show keyboard twice to get and confirm a user-entered password +/// string. +/// +/// @param[out] newPassword Overwritten with user input if return=true. +/// @param[in] autoCloseMs [opt] To close the dialog after a specified time, in +/// milliseconds, default is 0 which keeps the dialog +/// open indefinitely. +/// @return true if successful display and user input. false if unsuccessful +/// display, no user input, or canceled editing. +/// +inline bool ATTRIBUTE_HIDDEN ShowAndVerifyNewPassword(std::string& newPassword, + unsigned int autoCloseMs = 0) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = + CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_verify_new_password( + CAddonBase::m_interface->toKodi->kodiBase, &retString, autoCloseMs); + if (retString != nullptr) + { + newPassword = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Keyboard +/// @brief Show keyboard and verify user input against `password`. +/// +/// @param[in,out] password Value to compare against user input. +/// @param[in] heading String shown on dialog title. +/// @param[in] retries If greater than 0, shows "Incorrect password, %d retries +/// left" on dialog line 2, else line 2 is blank. +/// @param[in] autoCloseMs [opt] To close the dialog after a specified time, in +/// milliseconds, default is 0 which keeps the dialog +/// open indefinitely. +/// @return 0 if successful display and user input. 1 if unsuccessful input. +/// -1 if no user input or canceled editing. +/// +inline int ATTRIBUTE_HIDDEN ShowAndVerifyPassword(std::string& password, + const std::string& heading, + int retries, + unsigned int autoCloseMs = 0) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + int ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_verify_password( + CAddonBase::m_interface->toKodi->kodiBase, password.c_str(), &retString, heading.c_str(), + retries, autoCloseMs); + if (retString != nullptr) + { + password = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Keyboard +/// @brief Shows a filter related keyboard. +/// +/// @param[in,out] text Overwritten with user input if return=true. +/// @param[in] searching Use dialog for search and send our search message in +/// safe way (only the active window needs it) +/// - header name if true is "Enter search string" +/// - header name if false is "Enter value" +/// @param autoCloseMs [opt] To close the dialog after a specified time, in +/// milliseconds, default is 0 which keeps the dialog open +/// indefinitely. +/// @return true if successful display and user input. false if unsuccessful +/// display, no user input, or canceled editing. +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetFilter(std::string& text, + bool searching, + unsigned int autoCloseMs = 0) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->show_and_get_filter( + CAddonBase::m_interface->toKodi->kodiBase, text.c_str(), &retString, searching, autoCloseMs); + if (retString != nullptr) + { + text = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Keyboard +/// @brief Send a text to a visible keyboard. +/// +/// @param[in] text Overwritten with user input if return=true. +/// @param[in] closeKeyboard [opt] The open dialog is if also closed on 'true'. +/// @return true if successful done, false if unsuccessful or keyboard not +/// present. +/// +inline bool ATTRIBUTE_HIDDEN SendTextToActiveKeyboard(const std::string& text, + bool closeKeyboard = false) +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->send_text_to_active_keyboard( + CAddonBase::m_interface->toKodi->kodiBase, text.c_str(), closeKeyboard); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Keyboard +/// @brief Check for visible keyboard on GUI. +/// +/// @return true if keyboard present, false if not present +/// +inline bool ATTRIBUTE_HIDDEN IsKeyboardActivated() +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->dialogKeyboard->is_keyboard_activated( + CAddonBase::m_interface->toKodi->kodiBase); +} +//------------------------------------------------------------------------------ +}; // namespace Keyboard + +} /* namespace dialogs */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Numeric.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Numeric.h new file mode 100644 index 0000000..835a8d4 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Numeric.h @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/gui/dialogs/numeric.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace dialogs +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_dialogs_Numeric Dialog Numeric +/// @ingroup cpp_kodi_gui_dialogs +/// @{ +/// @brief @cpp_namespace{ kodi::gui::dialogs::Numeric } +/// **Numeric dialogs**\n +/// The functions listed below have to be permitted by the user for the +/// representation of a numeric keyboard around an input. +/// +/// The class supports several kinds, from an easy number choice up to the +/// passport Word production and their confirmation for add-on. +/// +/// It has the header @ref Numeric.h "#include " +/// be included to enjoy it. +/// +namespace Numeric +{ +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Numeric +/// @brief Use dialog to get numeric new password +/// +/// @param[out] newPassword String to preload into the keyboard accumulator. +/// Overwritten with user input if return=true. +/// Returned in MD5 format. +/// @return true if successful display and user input entry/re-entry. false if +/// unsuccessful display, no user input, or canceled editing. +/// +inline bool ATTRIBUTE_HIDDEN ShowAndVerifyNewPassword(std::string& newPassword) +{ + using namespace ::kodi::addon; + char* pw = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_verify_new_password( + CAddonBase::m_interface->toKodi->kodiBase, &pw); + if (pw != nullptr) + { + newPassword = pw; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, pw); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// +/// @ingroup cpp_kodi_gui_dialogs_Numeric +/// @brief Use dialog to verify numeric password. +/// +/// @param[in] password Password to compare with user input, need +/// in MD5 format. +/// @param[in] heading Heading to display +/// @param[in] retries If greater than 0, shows "Incorrect +/// password, %d retries left" on dialog +/// line 2, else line 2 is blank. +/// @return Possible values: +/// - 0 if successful display and user input. +/// - 1 if unsuccessful input. +/// - -1 if no user input or canceled editing. +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include // fprintf +/// #include +/// #include +/// +/// // The example below shows the complete use of keyboard dialog for password +/// // check. If only one check from add-on needed can be function with retries +/// // set to '0' called alone. +/// // +/// // The use of MD5 translated password is always required for the check on Kodi! +/// +/// int maxretries = 3; +/// +/// // Password names need to be send as md5 sum to kodi. +/// std::string password = kodi::GetMD5("1234"); +/// +/// // To the loop about password checks. +/// int ret; +/// for (unsigned int i = 0; i < maxretries; i++) +/// { +/// // Ask the user about the password. +/// ret = kodi::gui::dialogs::Numeric::ShowAndVerifyPassword(password, "Demo numeric password call for PW '1234'", i); +/// if (ret == 0) +/// { +/// fprintf(stderr, "Numeric password successfull confirmed after '%i' tries\n", i+1); +/// break; +/// } +/// else if (ret < 0) +/// { +/// fprintf(stderr, "Canceled editing on try '%i'\n", i+1); +/// break; +/// } +/// else // if (ret > 0) +/// { +/// fprintf(stderr, "Wrong numeric password entered on try '%i'\n", i+1); +/// } +/// } +/// ~~~~~~~~~~~~~ +/// +inline int ATTRIBUTE_HIDDEN ShowAndVerifyPassword(const std::string& password, + const std::string& heading, + int retries) +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_verify_password( + CAddonBase::m_interface->toKodi->kodiBase, password.c_str(), heading.c_str(), retries); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Numeric +/// @brief Use dialog to verify numeric password +/// +/// @param[in,out] toVerify Value to compare against user input. +/// @param[in] heading Heading to display +/// @param[in] verifyInput If set as true we verify the users input versus +/// toVerify. +/// @return true if successful display and user input. false if unsuccessful +/// display, no user input, or canceled editing. +/// +inline bool ATTRIBUTE_HIDDEN ShowAndVerifyInput(std::string& toVerify, + const std::string& heading, + bool verifyInput) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_verify_input( + CAddonBase::m_interface->toKodi->kodiBase, toVerify.c_str(), &retString, heading.c_str(), + verifyInput); + if (retString != nullptr) + { + toVerify = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Numeric +/// @brief Use dialog to get time value. +/// +/// @param[out] time Overwritten with user input if return=true and time +/// inserted. +/// @param[in] heading Heading to display. +/// @return true if successful display and user input. false if unsuccessful +/// display, no user input, or canceled editing. +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include // printf +/// #include // time_t, struct tm, time, localtime, strftime +/// #include +/// +/// time_t rawtime; +/// struct tm * timeinfo; +/// char buffer [10]; +/// +/// time (&rawtime); +/// timeinfo = localtime(&rawtime); +/// bool bRet = kodi::gui::dialogs::Numeric::ShowAndGetTime(*timeinfo, "Selected time test call"); +/// strftime(buffer, sizeof(buffer), "%H:%M.", timeinfo); +/// printf("Selected time it's %s and was on Dialog %s\n", buffer, bRet ? "OK" : "Canceled"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetTime(tm& time, const std::string& heading) +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_get_time( + CAddonBase::m_interface->toKodi->kodiBase, &time, heading.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Numeric +/// @brief Use dialog to get date value. +/// +/// @param[in,out] date Overwritten with user input if return=true and date +/// inserted. +/// @param[in] heading Heading to display +/// @return true if successful display and user input. false if unsuccessful +/// display, no user input, or canceled editing. +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include // printf +/// #include // time_t, struct tm, time, localtime, strftime +/// #include +/// +/// time_t rawtime; +/// struct tm * timeinfo; +/// char buffer [20]; +/// +/// time (&rawtime); +/// timeinfo = localtime(&rawtime); +/// bool bRet = kodi::gui::dialogs::Numeric::ShowAndGetDate(*timeinfo, "Selected date test call"); +/// strftime(buffer, sizeof(buffer), "%Y-%m-%d", timeinfo); +/// printf("Selected date it's %s and was on Dialog %s\n", buffer, bRet ? "OK" : "Canceled"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetDate(tm& date, const std::string& heading) +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_get_date( + CAddonBase::m_interface->toKodi->kodiBase, &date, heading.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Numeric +/// @brief Use dialog to get a IP +/// +/// @param[in,out] ipAddress Overwritten with user input if return=true and +/// IP address inserted. +/// @param[in] heading Heading to display. +/// @return true if successful display and user input. false if unsuccessful +/// display, no user input, or canceled editing. +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetIPAddress(std::string& ipAddress, const std::string& heading) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_get_ip_address( + CAddonBase::m_interface->toKodi->kodiBase, ipAddress.c_str(), &retString, heading.c_str()); + if (retString != nullptr) + { + ipAddress = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Numeric +/// @brief Use dialog to get normal number. +/// +/// @param[in,out] input Overwritten with user input if return=true and time +/// in seconds inserted +/// @param[in] heading Heading to display +/// @param[in] autoCloseTimeoutMs [opt] To close the dialog after a specified +/// time, in milliseconds, default is 0 +/// which keeps the dialog open +/// indefinitely. +/// @return true if successful display and user input. false if unsuccessful +/// display, no user input, or canceled editing. +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include // printf +/// #include // strtoull (C++11) +/// #include +/// +/// std::string number; +/// bool bRet = kodi::gui::dialogs::Numeric::ShowAndGetNumber(number, "Number test call"); +/// printf("Written number input is : %llu and was %s\n", +/// strtoull(number.c_str(), nullptr, 0), bRet ? "OK" : "Canceled"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetNumber(std::string& input, + const std::string& heading, + unsigned int autoCloseTimeoutMs = 0) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_get_number( + CAddonBase::m_interface->toKodi->kodiBase, input.c_str(), &retString, heading.c_str(), + autoCloseTimeoutMs); + if (retString != nullptr) + { + input = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Numeric +/// @brief Show numeric keypad to get seconds. +/// +/// @param[in,out] time Overwritten with user input if return=true and time +/// in seconds inserted. +/// @param[in] heading Heading to display +/// @return true if successful display and user input. false if unsuccessful +/// display, no user input, or canceled editing. +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetSeconds(std::string& time, const std::string& heading) +{ + using namespace ::kodi::addon; + char* retString = nullptr; + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogNumeric->show_and_get_seconds( + CAddonBase::m_interface->toKodi->kodiBase, time.c_str(), &retString, heading.c_str()); + if (retString != nullptr) + { + time = retString; + CAddonBase::m_interface->toKodi->free_string(CAddonBase::m_interface->toKodi->kodiBase, + retString); + } + return ret; +} +//------------------------------------------------------------------------------ +}; // namespace Numeric +/// @} + +} /* namespace dialogs */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/OK.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/OK.h new file mode 100644 index 0000000..747ab9d --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/OK.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/gui/dialogs/ok.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace dialogs +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_dialogs_OK Dialog OK +/// @ingroup cpp_kodi_gui_dialogs +/// @{ +/// @brief @cpp_namespace{ kodi::gui::dialogs::OK } +/// **OK dialog**\n +/// The functions listed below permit the call of a dialogue of information, a +/// confirmation of the user by press from OK required. +/// +/// It has the header @ref OK.h "#include " +/// be included to enjoy it. +/// +namespace OK +{ +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_OK +/// @brief Use dialog to inform user with text and confirmation with OK with +/// continued string. +/// +/// @param[in] heading Dialog heading. +/// @param[in] text Multi-line text. +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// kodi::gui::dialogs::OK::ShowAndGetInput("Test dialog", "Hello World!\nI'm a call from add-on\n :) :D"); +/// ~~~~~~~~~~~~~ +/// +inline void ATTRIBUTE_HIDDEN ShowAndGetInput(const std::string& heading, const std::string& text) +{ + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogOK->show_and_get_input_single_text( + CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), text.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_OK +/// @brief Use dialog to inform user with text and confirmation with OK with +/// strings separated to the lines. +/// +/// @param[in] heading Dialog heading. +/// @param[in] line0 Line #1 text. +/// @param[in] line1 Line #2 text. +/// @param[in] line2 Line #3 text. +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// ... +/// kodi::gui::dialogs::OK::ShowAndGetInput("Test dialog", "Hello World!", "I'm a call from add-on", " :) :D"); +/// ~~~~~~~~~~~~~ +/// +inline void ATTRIBUTE_HIDDEN ShowAndGetInput(const std::string& heading, + const std::string& line0, + const std::string& line1, + const std::string& line2) +{ + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogOK->show_and_get_input_line_text( + CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), line0.c_str(), line1.c_str(), + line2.c_str()); +} +//------------------------------------------------------------------------------ +} // namespace OK +/// @} + +} /* namespace dialogs */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Progress.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Progress.h new file mode 100644 index 0000000..d242a56 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Progress.h @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/gui/dialogs/progress.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace dialogs +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_dialogs_CProgress Dialog Progress +/// @ingroup cpp_kodi_gui_dialogs +/// @brief @cpp_class{ kodi::gui::dialogs::CProgress } +/// **Progress dialog shown in center**\n +/// The with @ref Progress.h "#include " +/// given class are basically used to create Kodi's progress dialog with named +/// text fields. +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// kodi::gui::dialogs::CProgress *progress = new kodi::gui::dialogs::CProgress; +/// progress->SetHeading("Test progress"); +/// progress->SetLine(1, "line 1"); +/// progress->SetLine(2, "line 2"); +/// progress->SetLine(3, "line 3"); +/// progress->SetCanCancel(true); +/// progress->ShowProgressBar(true); +/// progress->Open(); +/// for (unsigned int i = 0; i < 100; i += 10) +/// { +/// progress->SetPercentage(i); +/// sleep(1); +/// } +/// delete progress; +/// ~~~~~~~~~~~~~ +/// +class ATTRIBUTE_HIDDEN CProgress +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CProgress + /// @brief Construct a new dialog + /// + CProgress() + { + using namespace ::kodi::addon; + m_DialogHandle = CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->new_dialog( + CAddonBase::m_interface->toKodi->kodiBase); + if (!m_DialogHandle) + kodi::Log(ADDON_LOG_FATAL, + "kodi::gui::dialogs::CProgress can't create window class from Kodi !!!"); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CProgress + /// @brief Destructor + /// + ~CProgress() + { + using namespace ::kodi::addon; + if (m_DialogHandle) + CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->delete_dialog( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CProgress + /// @brief To open the dialog + /// + void Open() + { + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->open( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CProgress + /// @brief Set the heading title of dialog + /// + /// @param[in] heading Title string to use + /// + void SetHeading(const std::string& heading) + { + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->set_heading( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, heading.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CProgress + /// @brief To set the line text field on dialog from 0 - 2 + /// + /// @param[in] iLine Line number + /// @param[in] line Text string + /// + void SetLine(unsigned int iLine, const std::string& line) + { + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->set_line( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, iLine, line.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CProgress + /// @brief To enable and show cancel button on dialog + /// + /// @param[in] canCancel if true becomes it shown + /// + void SetCanCancel(bool canCancel) + { + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->set_can_cancel( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, canCancel); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CProgress + /// @brief To check dialog for clicked cancel button + /// + /// @return True if canceled + /// + bool IsCanceled() const + { + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->is_canceled( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CProgress + /// @brief Get the current progress position as percent + /// + /// @param[in] percentage Position to use from 0 to 100 + /// + void SetPercentage(int percentage) + { + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->set_percentage( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, percentage); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CProgress + /// @brief To set the current progress position as percent + /// + /// @return Current Position used from 0 to 100 + /// + int GetPercentage() const + { + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->get_percentage( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CProgress + /// @brief To show or hide progress bar dialog + /// + /// @param[in] onOff If true becomes it shown + /// + void ShowProgressBar(bool onOff) + { + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->show_progress_bar( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, onOff); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CProgress + /// @brief Set the maximum position of progress, needed if `SetProgressAdvance(...)` is used + /// + /// @param[in] max Biggest usable position to use + /// + void SetProgressMax(int max) + { + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->set_progress_max( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, max); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CProgress + /// @brief To increase progress bar by defined step size until reach of maximum position + /// + /// @param[in] steps Step size to increase, default is 1 + /// + void SetProgressAdvance(int steps = 1) + { + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->set_progress_advance( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle, steps); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_gui_dialogs_CProgress + /// @brief To check progress was canceled on work + /// + /// @return True if aborted + /// + bool Abort() + { + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->dialogProgress->abort( + CAddonBase::m_interface->toKodi->kodiBase, m_DialogHandle); + } + //---------------------------------------------------------------------------- + +private: + KODI_GUI_HANDLE m_DialogHandle; +}; + +} /* namespace dialogs */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Select.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Select.h new file mode 100644 index 0000000..9b1923e --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/Select.h @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/gui/dialogs/select.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace dialogs +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_dialogs_Select_Defs Definitions, structures and enumerators +/// @ingroup cpp_kodi_gui_dialogs_Select +/// @brief **Dialog Select definition values**\n +/// Data structures associated with this dialog. +/// +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Select_Defs +/// @brief **Selection entry structure**\n +/// Used to provide the necessary data for the selection dialog and to declare +/// the selected position in it. +/// +typedef struct SSelectionEntry +{ + /*! \cond PRIVATE */ + SSelectionEntry() = default; + /*! \endcond */ + + /// Entry identfication string + std::string id; + + /// Entry name to show on GUI dialog + std::string name; + + /// Place where entry can be preselected and after return the from user + /// selected is set. + bool selected = false; +} SSelectionEntry; +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_gui_dialogs_Select Dialog Select +/// @ingroup cpp_kodi_gui_dialogs +/// @{ +/// @brief @cpp_namespace{ kodi::gui::dialogs::Select } +/// **Selection dialog**\n +/// The function listed below permits the call of a dialogue to select of an +/// entry as a key +/// +/// It has the header @ref Select.h "#include " +/// be included to enjoy it. +/// +/// +namespace Select +{ +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Select +/// @brief Show a selection dialog about given parts. +/// +/// @param[in] heading Dialog heading name +/// @param[in] entries String list about entries +/// @param[in] selected [opt] Predefined selection (default is -1 for +/// the first) +/// @param[in] autoclose [opt] To close dialog automatic after the given time +/// in ms. As '0' it stays open. +/// @return The selected entry, if return -1 was nothing selected or +/// canceled +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// const std::vector entries +/// { +/// "Test 1", +/// "Test 2", +/// "Test 3", +/// "Test 4", +/// "Test 5" +/// }; +/// +/// int selected = kodi::gui::dialogs::Select::Show("Test selection", entries, -1); +/// if (selected < 0) +/// fprintf(stderr, "Item selection canceled\n"); +/// else +/// fprintf(stderr, "Selected item is: %i\n", selected); +/// ~~~~~~~~~~~~~ +/// +inline int ATTRIBUTE_HIDDEN Show(const std::string& heading, + const std::vector& entries, + int selected = -1, + unsigned int autoclose = 0) +{ + using namespace ::kodi::addon; + unsigned int size = static_cast(entries.size()); + const char** cEntries = (const char**)malloc(size * sizeof(const char**)); + for (unsigned int i = 0; i < size; ++i) + { + cEntries[i] = entries[i].c_str(); + } + int ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogSelect->open( + CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), cEntries, size, selected, + autoclose); + free(cEntries); + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Select +/// @brief Show a selection dialog about given parts. +/// +/// This function is mostly equal to the other, only becomes the string list +/// here done by a @ref SSelectionEntry, where a ID string can be defined. +/// +/// @param[in] heading Dialog heading name +/// @param[in] entries @ref SSelectionEntry list about entries +/// @param[in] selected [opt] Predefined selection (default is -1 for +/// the first) +/// @param[in] autoclose [opt] To close dialog automatic after the given time +/// in ms. As '0' it stays open. +/// @return The selected entry, if return -1 was nothing selected +/// or canceled +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// std::vector entries +/// { +/// { "ID 1", "Test 1", false }, +/// { "ID 2", "Test 2", false }, +/// { "ID 3", "Test 3", false }, +/// { "ID 4", "Test 4", false }, +/// { "ID 5", "Test 5", false } +/// }; +/// +/// int selected = kodi::gui::dialogs::Select::Show("Test selection", entries, -1); +/// if (selected < 0) +/// fprintf(stderr, "Item selection canceled\n"); +/// else +/// fprintf(stderr, "Selected item is: %i\n", selected); +/// ~~~~~~~~~~~~~ +/// +inline int ATTRIBUTE_HIDDEN Show(const std::string& heading, + std::vector& entries, + int selected = -1, + unsigned int autoclose = 0) +{ + using namespace ::kodi::addon; + unsigned int size = static_cast(entries.size()); + const char** cEntries = static_cast(malloc(size * sizeof(const char*))); + for (unsigned int i = 0; i < size; ++i) + { + cEntries[i] = entries[i].name.c_str(); + if (selected == -1 && entries[i].selected) + selected = i; + } + int ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogSelect->open( + CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), cEntries, size, selected, + autoclose); + if (ret >= 0) + { + entries[ret].selected = true; + } + free(cEntries); + return ret; +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_Select +/// @brief Show a multiple selection dialog about given parts. +/// +/// @param[in] heading Dialog heading name +/// @param[in] entries @ref SSelectionEntry list about entries +/// @param[in] autoclose [opt] To close dialog automatic after the given time in +/// ms. As '0' it stays open. +/// @return The selected entries, if return empty was nothing selected +/// or canceled +/// +/// With selected on @ref SSelectionEntry can be a pre selection defined. +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// std::vector entries +/// { +/// { "ID 1", "Test 1", false }, +/// { "ID 2", "Test 2", false }, +/// { "ID 3", "Test 3", false }, +/// { "ID 4", "Test 4", false }, +/// { "ID 5", "Test 5", false } +/// }; +/// +/// bool ret = kodi::gui::dialogs::Select::ShowMultiSelect("Test selection", entries); +/// if (!ret) +/// fprintf(stderr, "Selection canceled\n"); +/// else +/// { +/// fprintf(stderr, "Selected items:\n"); +/// for (const auto& entry : entries) +/// { +/// if (entry.selected) +/// fprintf(stderr, " - %s\n", entry.selected.id.c_str()); +/// } +/// } +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN ShowMultiSelect(const std::string& heading, + std::vector& entries, + int autoclose = 0) +{ + using namespace ::kodi::addon; + unsigned int size = static_cast(entries.size()); + const char** cEntryIDs = static_cast(malloc(size * sizeof(const char*))); + const char** cEntryNames = static_cast(malloc(size * sizeof(const char*))); + bool* cEntriesSelected = static_cast(malloc(size * sizeof(bool))); + for (unsigned int i = 0; i < size; ++i) + { + cEntryIDs[i] = entries[i].id.c_str(); + cEntryNames[i] = entries[i].name.c_str(); + cEntriesSelected[i] = entries[i].selected; + } + bool ret = CAddonBase::m_interface->toKodi->kodi_gui->dialogSelect->open_multi_select( + CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), cEntryIDs, cEntryNames, + cEntriesSelected, size, autoclose); + if (ret) + { + for (unsigned int i = 0; i < size; ++i) + entries[i].selected = cEntriesSelected[i]; + } + free(cEntryNames); + free(cEntryIDs); + free(cEntriesSelected); + return ret; +} +//------------------------------------------------------------------------------ +}; // namespace Select +/// @} + +} /* namespace dialogs */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/TextViewer.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/TextViewer.h new file mode 100644 index 0000000..42a86f3 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/TextViewer.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/gui/dialogs/text_viewer.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace dialogs +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_dialogs_TextViewer Dialog Text Viewer +/// @ingroup cpp_kodi_gui_dialogs +/// @{ +/// @brief @cpp_namespace{ kodi::gui::dialogs::TextViewer } +/// **Text viewer dialog**\n +/// The text viewer dialog can be used to display descriptions, help texts or +/// other larger texts. +/// +/// In order to achieve a line break is a \\n directly in the text or +/// in the "./resources/language/resource.language.??_??/strings.po" +/// to call with std::string kodi::general::GetLocalizedString(...);. +/// +/// It has the header \ref TextViewer.h "#include " +/// be included to enjoy it. +/// +namespace TextViewer +{ +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_TextViewer +/// @brief Show info text dialog +/// +/// @param[in] heading mall heading text +/// @param[in] text Showed text on dialog +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// kodi::gui::dialogs::TextViewer::Show("The Wizard of Oz (1939 film)", +/// "The Wizard of Oz is a 1939 American musical comedy-drama fantasy film " +/// "produced by Metro-Goldwyn-Mayer, and the most well-known and commercially " +/// "successful adaptation based on the 1900 novel The Wonderful Wizard of Oz " +/// "by L. Frank Baum. The film stars Judy Garland as Dorothy Gale. The film" +/// "co-stars Terry the dog, billed as Toto; Ray Bolger, Jack Haley, Bert Lahr, " +/// "Frank Morgan, Billie Burke, Margaret Hamilton, with Charley Grapewin and " +/// "Clara Blandick, and the Singer Midgets as the Munchkins.\n" +/// "\n" +/// "Notable for its use of Technicolor, fantasy storytelling, musical score and " +/// "unusual characters, over the years it has become an icon of American popular " +/// "culture. It was nominated for six Academy Awards, including Best Picture but " +/// "lost to Gone with the Wind. It did win in two other categories including Best " +/// "Original Song for \"Over the Rainbow\". However, the film was a box office " +/// "disappointment on its initial release, earning only $3,017,000 on a $2,777,000 " +/// "budget, despite receiving largely positive reviews. It was MGM's most " +/// "expensive production at that time, and did not completely recoup the studio's " +/// "investment and turn a profit until theatrical re-releases starting in 1949.\n" +/// "\n" +/// "The 1956 broadcast television premiere of the film on CBS re-introduced the " +/// "film to the wider public and eventually made the presentation an annual " +/// "tradition, making it one of the most known films in cinema history. The " +/// "film was named the most-viewed motion picture on television syndication by " +/// "the Library of Congress who also included the film in its National Film " +/// "Registry in its inaugural year in 1989. Designation on the registry calls " +/// "for efforts to preserve it for being \"culturally, historically, and " +/// "aesthetically significant\". It is also one of the few films on UNESCO's " +/// "Memory of the World Register.\n" +/// "\n" +/// "The Wizard of Oz is often ranked on best-movie lists in critics' and public " +/// "polls. It is the source of many quotes referenced in modern popular culture. " +/// "It was directed primarily by Victor Fleming (who left production to take " +/// "over direction on the troubled Gone with the Wind production). Noel Langley, " +/// "Florence Ryerson and Edgar Allan Woolf received credit for the screenplay, " +/// "but there were uncredited contributions by others. The songs were written " +/// "by Edgar \"Yip\" Harburg (lyrics) and Harold Arlen (music). The incidental " +/// "music, based largely on the songs, was composed by Herbert Stothart, with " +/// "interspersed renderings from classical composers.\n"); +/// ~~~~~~~~~~~~~ +/// +inline void ATTRIBUTE_HIDDEN Show(const std::string& heading, const std::string& text) +{ + using namespace ::kodi::addon; + CAddonBase::m_interface->toKodi->kodi_gui->dialogTextViewer->open( + CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), text.c_str()); +} +//------------------------------------------------------------------------------ +}; // namespace TextViewer +/// @} + +} /* namespace dialogs */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/YesNo.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/YesNo.h new file mode 100644 index 0000000..6e6e069 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/dialogs/YesNo.h @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/gui/dialogs/yes_no.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +namespace dialogs +{ + +//============================================================================== +/// @defgroup cpp_kodi_gui_dialogs_YesNo Dialog Yes/No +/// @ingroup cpp_kodi_gui_dialogs +/// @{ +/// @brief @cpp_namespace{ kodi::gui::dialogs::YesNo } +/// **Yes / No dialog**\n +/// The Yes / No dialog can be used to inform the user about questions and get +/// the answer. +/// +/// In order to achieve a line break is a \\n directly in the text or +/// in the "./resources/language/resource.language.??_??/strings.po" +/// to call with std::string kodi::general::GetLocalizedString(...);. +/// +/// It has the header @ref YesNo.h "#include " +/// be included to enjoy it. +/// +namespace YesNo +{ +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_YesNo +/// @brief Use dialog to get numeric new password with one text string shown +/// everywhere and cancel return field. +/// +/// @param[in] heading Dialog heading +/// @param[in] text Multi-line text +/// @param[out] canceled Return value about cancel button +/// @param[in] noLabel [opt] label to put on the no button +/// @param[in] yesLabel [opt] label to put on the yes button +/// @return Returns True if 'Yes' was pressed, else False +/// +/// @note It is preferred to only use this as it is actually a multi-line text. +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// bool canceled = false; +/// bool ret = kodi::gui::dialogs::YesNo::ShowAndGetInput( +/// "Yes / No test call", // The Header +/// "You has opened Yes / No dialog for test\n\nIs this OK for you?", +/// canceled, // return value about cancel button +/// "Not really", // No label, is optional and if empty "No" +/// "Ohhh yes"); // Yes label, also optional and if empty "Yes" +/// fprintf(stderr, "You has called Yes/No, returned '%s' and was %s\n", +/// ret ? "yes" : "no", +/// canceled ? "canceled" : "not canceled"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetInput(const std::string& heading, + const std::string& text, + bool& canceled, + const std::string& noLabel = "", + const std::string& yesLabel = "") +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->dialogYesNo->show_and_get_input_single_text( + CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), text.c_str(), &canceled, + noLabel.c_str(), yesLabel.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_YesNo +/// @brief Use dialog to get numeric new password with separated line strings. +/// +/// @param[in] heading Dialog heading +/// @param[in] line0 Line #0 text +/// @param[in] line1 Line #1 text +/// @param[in] line2 Line #2 text +/// @param[in] noLabel [opt] label to put on the no button +/// @param[in] yesLabel [opt] label to put on the yes button +/// @return Returns True if 'Yes' was pressed, else False +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// bool ret = kodi::gui::dialogs::YesNo::ShowAndGetInput( +/// "Yes / No test call", // The Header +/// "You has opened Yes / No dialog for test", +/// "", +/// "Is this OK for you?", +/// "Not really", // No label, is optional and if empty "No" +/// "Ohhh yes"); // Yes label, also optional and if empty "Yes" +/// fprintf(stderr, "You has called Yes/No, returned '%s'\n", +/// ret ? "yes" : "no"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetInput(const std::string& heading, + const std::string& line0, + const std::string& line1, + const std::string& line2, + const std::string& noLabel = "", + const std::string& yesLabel = "") +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->dialogYesNo->show_and_get_input_line_text( + CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), line0.c_str(), line1.c_str(), + line2.c_str(), noLabel.c_str(), yesLabel.c_str()); +} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @ingroup cpp_kodi_gui_dialogs_YesNo +/// @brief Use dialog to get numeric new password with separated line strings +/// and cancel return field. +/// +/// @param[in] heading Dialog heading +/// @param[in] line0 Line #0 text +/// @param[in] line1 Line #1 text +/// @param[in] line2 Line #2 text +/// @param[out] canceled Return value about cancel button +/// @param[in] noLabel [opt] label to put on the no button +/// @param[in] yesLabel [opt] label to put on the yes button +/// @return Returns True if 'Yes' was pressed, else False +/// +/// +///------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// bool canceled = false; +/// bool ret = kodi::gui::dialogs::YesNo::ShowAndGetInput( +/// "Yes / No test call", // The Header +/// "You has opened Yes / No dialog for test", +/// "", +/// "Is this OK for you?", +/// canceled, // return value about cancel button +/// "Not really", // No label, is optional and if empty "No" +/// "Ohhh yes"); // Yes label, also optional and if empty "Yes" +/// fprintf(stderr, "You has called Yes/No, returned '%s' and was %s\n", +/// ret ? "yes" : "no", +/// canceled ? "canceled" : "not canceled"); +/// ~~~~~~~~~~~~~ +/// +inline bool ATTRIBUTE_HIDDEN ShowAndGetInput(const std::string& heading, + const std::string& line0, + const std::string& line1, + const std::string& line2, + bool& canceled, + const std::string& noLabel = "", + const std::string& yesLabel = "") +{ + using namespace ::kodi::addon; + return CAddonBase::m_interface->toKodi->kodi_gui->dialogYesNo + ->show_and_get_input_line_button_text( + CAddonBase::m_interface->toKodi->kodiBase, heading.c_str(), line0.c_str(), line1.c_str(), + line2.c_str(), &canceled, noLabel.c_str(), yesLabel.c_str()); +} +//------------------------------------------------------------------------------ +}; // namespace YesNo +/// @} + +} /* namespace dialogs */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/CMakeLists.txt new file mode 100644 index 0000000..844902d --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/CMakeLists.txt @@ -0,0 +1,7 @@ +set(HEADERS GL.h + GLonDX.h + Shader.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_gui_gl) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GL.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GL.h new file mode 100644 index 0000000..16d43e3 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GL.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2005-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifdef __cplusplus + +//============================================================================== +/// @defgroup cpp_kodi_gui_helpers_gl OpenGL helpers +/// @ingroup cpp_kodi_gui_helpers +/// @brief **Auxiliary functions for Open GL**\n +/// This group includes help for definitions, functions, and classes for +/// OpenGL. +/// +/// To use OpenGL for your system, add the @ref GL.h "#include ". +/// +/// The @ref HAS_GL is declared if Open GL is required and @ref HAS_GLES if Open GL +/// Embedded Systems (ES) is required, with ES the version is additionally given +/// in the definition, this can be "2" or "3". +/// +/// +///----------------------------------------------------------------------------- +/// +/// Following @ref GL_TYPE_STRING define can be used, for example, to manage +/// different folders for GL and GLES and make the selection easier. +/// This are on OpenGL "GL" and on Open GL|ES "GLES". +/// +/// **Example:** +/// ~~~~~~~~~~~~~~~~~{.cpp} +/// kodi::GetAddonPath("resources/shaders/" GL_TYPE_STRING "/frag.glsl"); +/// ~~~~~~~~~~~~~~~~~ +/// +/// +///---------------------------------------------------------------------------- +/// +/// In addition, @ref BUFFER_OFFSET is declared in it which can be used to give an +/// offset on the array to GL. +/// +/// **Example:** +/// ~~~~~~~~~~~~~~~~~{.cpp} +/// const struct PackedVertex { +/// float position[3]; // Position x, y, z +/// float color[4]; // Color r, g, b, a +/// } vertices[3] = { +/// { { -0.5f, -0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } }, +/// { { 0.5f, -0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } }, +/// { { 0.0f, 0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } } +/// }; +/// +/// glVertexAttribPointer(m_aPosition, 3, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), BUFFER_OFFSET(offsetof(PackedVertex, position))); +/// glEnableVertexAttribArray(m_aPosition); +/// +/// glVertexAttribPointer(m_aColor, 4, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), BUFFER_OFFSET(offsetof(PackedVertex, color))); +/// glEnableVertexAttribArray(m_aColor); +/// ~~~~~~~~~~~~~~~~~ + +#if HAS_GL +#define GL_TYPE_STRING "GL" +// always define GL_GLEXT_PROTOTYPES before include gl headers +#if !defined(GL_GLEXT_PROTOTYPES) +#define GL_GLEXT_PROTOTYPES +#endif +#if defined(TARGET_LINUX) +#include +#include +#elif defined(TARGET_FREEBSD) +#include +#elif defined(TARGET_DARWIN) +#include +#include +#elif defined(WIN32) +#error Use of GL under Windows is not possible +#endif +#elif HAS_GLES >= 2 +#define GL_TYPE_STRING "GLES" +#if defined(WIN32) +#if defined(HAS_ANGLE) +#include +#else +#error Use of GLES only be available under Windows by the use of angle +#endif +#elif defined(TARGET_DARWIN) +#if HAS_GLES == 3 +#include +#include +#else +#include +#include +#endif +#else +#if HAS_GLES == 3 +#include +#include +#else +#include +#include +#endif +#endif +#endif + +#ifndef BUFFER_OFFSET +/// @ingroup cpp_kodi_gui_helpers_gl +/// @brief To give a offset number as pointer value. +#define BUFFER_OFFSET(i) ((char*)nullptr + (i)) +#endif + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GLonDX.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GLonDX.h new file mode 100644 index 0000000..4dd97af --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GLonDX.h @@ -0,0 +1,389 @@ +/* + * Copyright (C) 2005-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifdef __cplusplus + +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma comment(lib, "d3dcompiler.lib") +#ifndef GL_CLIENT_VERSION +#define GL_CLIENT_VERSION 3 +#endif + +namespace kodi +{ +namespace gui +{ +namespace gl +{ + +class ATTRIBUTE_HIDDEN CGLonDX : public kodi::gui::IRenderHelper +{ +public: + explicit CGLonDX() : m_pContext(reinterpret_cast(kodi::gui::GetHWContext())) + { + } + ~CGLonDX() override { destruct(); } + + bool Init() override + { + EGLint egl_display_attrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, + EGL_DONT_CARE, + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, + EGL_DONT_CARE, + EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE, + EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE, + EGL_NONE}; + EGLint egl_config_attrs[] = {EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_ALPHA_SIZE, + 8, + EGL_BIND_TO_TEXTURE_RGBA, + EGL_TRUE, + EGL_RENDERABLE_TYPE, + GL_CLIENT_VERSION == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, + EGL_PBUFFER_BIT, + EGL_NONE}; + EGLint egl_context_attrs[] = {EGL_CONTEXT_CLIENT_VERSION, GL_CLIENT_VERSION, EGL_NONE}; + + m_eglDisplay = + eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, egl_display_attrs); + if (m_eglDisplay == EGL_NO_DISPLAY) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to get EGL display (%s)", eglGetErrorString()); + return false; + } + + if (eglInitialize(m_eglDisplay, nullptr, nullptr) != EGL_TRUE) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to init EGL display (%s)", eglGetErrorString()); + return false; + } + + EGLint numConfigs = 0; + if (eglChooseConfig(m_eglDisplay, egl_config_attrs, &m_eglConfig, 1, &numConfigs) != EGL_TRUE || + numConfigs == 0) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to get EGL config (%s)", eglGetErrorString()); + return false; + } + + m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, nullptr, egl_context_attrs); + if (m_eglContext == EGL_NO_CONTEXT) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create EGL context (%s)", eglGetErrorString()); + return false; + } + + if (!createD3DResources()) + return false; + + if (eglMakeCurrent(m_eglDisplay, m_eglBuffer, m_eglBuffer, m_eglContext) != EGL_TRUE) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to make current EGL (%s)", eglGetErrorString()); + return false; + } + return true; + } + + void CheckGL(ID3D11DeviceContext* device) + { + if (m_pContext != device) + { + m_pSRView = nullptr; + m_pVShader = nullptr; + m_pPShader = nullptr; + m_pContext = device; + + if (m_eglBuffer != EGL_NO_SURFACE) + { + eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(m_eglDisplay, m_eglBuffer); + m_eglBuffer = EGL_NO_SURFACE; + } + + // create new resources + if (!createD3DResources()) + return; + + eglMakeCurrent(m_eglDisplay, m_eglBuffer, m_eglBuffer, m_eglContext); + } + } + + void Begin() override + { + // confirm on begin D3D context is correct + CheckGL(reinterpret_cast(kodi::gui::GetHWContext())); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + } + + void End() override + { + glFlush(); + + // set our primitive shaders + m_pContext->VSSetShader(m_pVShader.Get(), nullptr, 0); + m_pContext->PSSetShader(m_pPShader.Get(), nullptr, 0); + m_pContext->PSSetShaderResources(0, 1, m_pSRView.GetAddressOf()); + // draw texture + m_pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + m_pContext->IASetVertexBuffers(0, 0, nullptr, nullptr, nullptr); + m_pContext->IASetInputLayout(nullptr); + m_pContext->Draw(4, 0); + // unset shaders + m_pContext->PSSetShader(nullptr, nullptr, 0); + m_pContext->VSSetShader(nullptr, nullptr, 0); + // unbind our view + ID3D11ShaderResourceView* views[1] = {}; + m_pContext->PSSetShaderResources(0, 1, views); + } + +private: + enum ShaderType + { + VERTEX_SHADER, + PIXEL_SHADER + }; + + bool createD3DResources() + { + HANDLE sharedHandle; + Microsoft::WRL::ComPtr pDevice; + Microsoft::WRL::ComPtr pRTView; + Microsoft::WRL::ComPtr pRTResource; + Microsoft::WRL::ComPtr pRTTexture; + Microsoft::WRL::ComPtr pOffScreenTexture; + Microsoft::WRL::ComPtr dxgiResource; + + m_pContext->GetDevice(&pDevice); + m_pContext->OMGetRenderTargets(1, &pRTView, nullptr); + if (!pRTView) + return false; + + pRTView->GetResource(&pRTResource); + if (FAILED(pRTResource.As(&pRTTexture))) + return false; + + D3D11_TEXTURE2D_DESC texDesc; + pRTTexture->GetDesc(&texDesc); + texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; + if (FAILED(pDevice->CreateTexture2D(&texDesc, nullptr, &pOffScreenTexture))) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create intermediate texture"); + return false; + } + + CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(pOffScreenTexture.Get(), + D3D11_SRV_DIMENSION_TEXTURE2D); + if (FAILED(pDevice->CreateShaderResourceView(pOffScreenTexture.Get(), &srvDesc, &m_pSRView))) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create shader view"); + return false; + } + + if (FAILED(pOffScreenTexture.As(&dxgiResource)) || + FAILED(dxgiResource->GetSharedHandle(&sharedHandle))) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable get shared handle for texture"); + return false; + } + + // initiate simple shaders + if (FAILED(d3dCreateShader(VERTEX_SHADER, vs_out_shader_text, &m_pVShader))) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create vertex shader view"); + return false; + } + + if (FAILED(d3dCreateShader(PIXEL_SHADER, ps_out_shader_text, &m_pPShader))) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create pixel shader view"); + return false; + } + + // create EGL buffer from D3D shared texture + EGLint egl_buffer_attrs[] = {EGL_WIDTH, + static_cast(texDesc.Width), + EGL_HEIGHT, + static_cast(texDesc.Height), + EGL_TEXTURE_TARGET, + EGL_TEXTURE_2D, + EGL_TEXTURE_FORMAT, + EGL_TEXTURE_RGBA, + EGL_NONE}; + + m_eglBuffer = + eglCreatePbufferFromClientBuffer(m_eglDisplay, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, + sharedHandle, m_eglConfig, egl_buffer_attrs); + + if (m_eglBuffer == EGL_NO_SURFACE) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create EGL buffer (%s)", eglGetErrorString()); + return false; + } + return true; + } + + HRESULT d3dCreateShader(ShaderType shaderType, + const std::string& source, + IUnknown** ppShader) const + { + Microsoft::WRL::ComPtr pBlob; + Microsoft::WRL::ComPtr pErrors; + + auto hr = D3DCompile(source.c_str(), source.length(), nullptr, nullptr, nullptr, "main", + shaderType == PIXEL_SHADER ? "ps_4_0" : "vs_4_0", 0, 0, &pBlob, &pErrors); + + if (SUCCEEDED(hr)) + { + Microsoft::WRL::ComPtr pDevice; + m_pContext->GetDevice(&pDevice); + + if (shaderType == PIXEL_SHADER) + { + hr = pDevice->CreatePixelShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, + reinterpret_cast(ppShader)); + } + else + { + hr = pDevice->CreateVertexShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, + reinterpret_cast(ppShader)); + } + + if (FAILED(hr)) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create %s shader", + shaderType == PIXEL_SHADER ? "pixel" : "vertex"); + } + } + else + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to compile shader (%s)", pErrors->GetBufferPointer()); + } + return hr; + } + + static const char* eglGetErrorString() + { +#define CASE_STR(value) \ + case value: \ + return #value + switch (eglGetError()) + { + CASE_STR(EGL_SUCCESS); + CASE_STR(EGL_NOT_INITIALIZED); + CASE_STR(EGL_BAD_ACCESS); + CASE_STR(EGL_BAD_ALLOC); + CASE_STR(EGL_BAD_ATTRIBUTE); + CASE_STR(EGL_BAD_CONTEXT); + CASE_STR(EGL_BAD_CONFIG); + CASE_STR(EGL_BAD_CURRENT_SURFACE); + CASE_STR(EGL_BAD_DISPLAY); + CASE_STR(EGL_BAD_SURFACE); + CASE_STR(EGL_BAD_MATCH); + CASE_STR(EGL_BAD_PARAMETER); + CASE_STR(EGL_BAD_NATIVE_PIXMAP); + CASE_STR(EGL_BAD_NATIVE_WINDOW); + CASE_STR(EGL_CONTEXT_LOST); + default: + return "Unknown"; + } +#undef CASE_STR + } + + void destruct() + { + if (m_eglDisplay != EGL_NO_DISPLAY) + { + eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + if (m_eglBuffer != EGL_NO_SURFACE) + { + eglDestroySurface(m_eglDisplay, m_eglBuffer); + m_eglBuffer = EGL_NO_SURFACE; + } + + if (m_eglContext != EGL_NO_CONTEXT) + { + eglDestroyContext(m_eglDisplay, m_eglContext); + m_eglContext = EGL_NO_CONTEXT; + } + + eglTerminate(m_eglDisplay); + m_eglDisplay = EGL_NO_DISPLAY; + } + + m_pSRView = nullptr; + m_pVShader = nullptr; + m_pPShader = nullptr; + m_pContext = nullptr; + } + + EGLConfig m_eglConfig = EGL_NO_CONFIG_KHR; + EGLDisplay m_eglDisplay = EGL_NO_DISPLAY; + EGLContext m_eglContext = EGL_NO_CONTEXT; + EGLSurface m_eglBuffer = EGL_NO_SURFACE; + + ID3D11DeviceContext* m_pContext = nullptr; // don't hold context + Microsoft::WRL::ComPtr m_pSRView = nullptr; + Microsoft::WRL::ComPtr m_pVShader = nullptr; + Microsoft::WRL::ComPtr m_pPShader = nullptr; + +#define TO_STRING(...) #__VA_ARGS__ + std::string vs_out_shader_text = TO_STRING(void main(uint id + : SV_VertexId, out float2 tex + : TEXCOORD0, out float4 pos + : SV_POSITION) { + tex = float2(id % 2, (id % 4) >> 1); + pos = float4((tex.x - 0.5f) * 2, -(tex.y - 0.5f) * 2, 0, 1); + }); + + std::string ps_out_shader_text = TO_STRING( + Texture2D texMain : register(t0); + SamplerState Sampler + { + Filter = MIN_MAG_MIP_LINEAR; + AddressU = CLAMP; + AddressV = CLAMP; + Comparison = NEVER; + }; + + float4 main(in float2 tex : TEXCOORD0) : SV_TARGET + { + return texMain.Sample(Sampler, tex); + }); +#undef TO_STRING +}; /* class CGLonDX */ + +} /* namespace gl */ + +using CRenderHelper = gl::CGLonDX; +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/Shader.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/Shader.h new file mode 100644 index 0000000..bf6d48c --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/Shader.h @@ -0,0 +1,571 @@ +/* + * Copyright (C) 2005-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "GL.h" + +#ifdef __cplusplus + +#include +#include +#include + +#include +#include + +#define LOG_SIZE 1024 +#define GLchar char + +namespace kodi +{ +namespace gui +{ +namespace gl +{ + +//======================================================================== +/// CShader - base class +class ATTRIBUTE_HIDDEN CShader +{ +public: + CShader() = default; + virtual ~CShader() = default; + virtual bool Compile(const std::string& extraBegin = "", const std::string& extraEnd = "") = 0; + virtual void Free() = 0; + virtual GLuint Handle() = 0; + + bool LoadSource(const std::string& file) + { + char buffer[16384]; + + kodi::vfs::CFile source; + if (!source.OpenFile(file)) + { + kodi::Log(ADDON_LOG_ERROR, "CShader::%s: Failed to open file '%s'", __FUNCTION__, + file.c_str()); + return false; + } + size_t len = source.Read(buffer, sizeof(buffer)); + m_source.assign(buffer); + m_source[len] = 0; + source.Close(); + return true; + } + + bool OK() const { return m_compiled; } + +protected: + std::string m_source; + std::string m_lastLog; + bool m_compiled = false; +}; +//------------------------------------------------------------------------ + +//======================================================================== +/// CVertexShader +class ATTRIBUTE_HIDDEN CVertexShader : public CShader +{ +public: + CVertexShader() = default; + ~CVertexShader() override { Free(); } + + void Free() override + { + if (m_vertexShader) + glDeleteShader(m_vertexShader); + m_vertexShader = 0; + } + + bool Compile(const std::string& extraBegin = "", const std::string& extraEnd = "") override + { + GLint params[4]; + + Free(); + + m_vertexShader = glCreateShader(GL_VERTEX_SHADER); + + GLsizei count = 0; + const char* sources[3]; + if (!extraBegin.empty()) + sources[count++] = extraBegin.c_str(); + if (!m_source.empty()) + sources[count++] = m_source.c_str(); + if (!extraEnd.empty()) + sources[count++] = extraEnd.c_str(); + + glShaderSource(m_vertexShader, count, sources, nullptr); + glCompileShader(m_vertexShader); + glGetShaderiv(m_vertexShader, GL_COMPILE_STATUS, params); + if (params[0] != GL_TRUE) + { + GLchar log[LOG_SIZE]; + glGetShaderInfoLog(m_vertexShader, LOG_SIZE, nullptr, log); + kodi::Log(ADDON_LOG_ERROR, "CVertexShader::%s: %s", __FUNCTION__, log); + fprintf(stderr, "CVertexShader::%s: %s\n", __FUNCTION__, log); + m_lastLog = log; + m_compiled = false; + } + else + { + GLchar log[LOG_SIZE]; + glGetShaderInfoLog(m_vertexShader, LOG_SIZE, nullptr, log); + m_lastLog = log; + m_compiled = true; + } + return m_compiled; + } + + GLuint Handle() override { return m_vertexShader; } + +protected: + GLuint m_vertexShader = 0; +}; +//------------------------------------------------------------------------ + +//======================================================================== +/// CPixelShader +class ATTRIBUTE_HIDDEN CPixelShader : public CShader +{ +public: + CPixelShader() = default; + ~CPixelShader() { Free(); } + void Free() override + { + if (m_pixelShader) + glDeleteShader(m_pixelShader); + m_pixelShader = 0; + } + + bool Compile(const std::string& extraBegin = "", const std::string& extraEnd = "") override + { + GLint params[4]; + + Free(); + + m_pixelShader = glCreateShader(GL_FRAGMENT_SHADER); + + GLsizei count = 0; + const char* sources[3]; + if (!extraBegin.empty()) + sources[count++] = extraBegin.c_str(); + if (!m_source.empty()) + sources[count++] = m_source.c_str(); + if (!extraEnd.empty()) + sources[count++] = extraEnd.c_str(); + + glShaderSource(m_pixelShader, count, sources, 0); + glCompileShader(m_pixelShader); + glGetShaderiv(m_pixelShader, GL_COMPILE_STATUS, params); + if (params[0] != GL_TRUE) + { + GLchar log[LOG_SIZE]; + glGetShaderInfoLog(m_pixelShader, LOG_SIZE, nullptr, log); + kodi::Log(ADDON_LOG_ERROR, "CPixelShader::%s: %s", __FUNCTION__, log); + fprintf(stderr, "CPixelShader::%s: %s\n", __FUNCTION__, log); + m_lastLog = log; + m_compiled = false; + } + else + { + GLchar log[LOG_SIZE]; + glGetShaderInfoLog(m_pixelShader, LOG_SIZE, nullptr, log); + m_lastLog = log; + m_compiled = true; + } + return m_compiled; + } + + GLuint Handle() override { return m_pixelShader; } + +protected: + GLuint m_pixelShader = 0; +}; +//------------------------------------------------------------------------ + +//============================================================================ +/// @defgroup cpp_kodi_gui_helpers_gl_CShaderProgram GL Shader Program +/// @ingroup cpp_kodi_gui_helpers_gl +/// @brief @cpp_class{ kodi::gui::gl::CShaderProgram } +/// **Class to manage an OpenGL shader program**\n +/// With this class the used GL shader code can be defined on the GPU and +/// its variables can be managed between CPU and GPU. +/// +/// It has the header @ref Shader.h "#include " +/// be included to enjoy it. +/// +/// ---------------------------------------------------------------------------- +/// +/// Example: +/// +/// ~~~~~~~~~~~~~{.cpp} +/// +/// #include +/// ... +/// +/// class ATTRIBUTE_HIDDEN CExample +/// : ..., +/// public kodi::gui::gl::CShaderProgram +/// { +/// public: +/// CExample() = default; +/// +/// bool Start(); +/// void Render(); +/// +/// // override functions for kodi::gui::gl::CShaderProgram +/// void OnCompiledAndLinked() override; +/// bool OnEnabled() override; +/// +/// private: +/// ... +/// GLint m_aPosition = -1; +/// GLint m_aColor = -1; +/// }; +/// +/// bool CExample::Start() +/// { +/// // Define shaders and load +/// std::string fraqShader = kodi::GetAddonPath("resources/shaders/" GL_TYPE_STRING "/glsl.frag"); +/// std::string vertShader = kodi::GetAddonPath("resources/shaders/" GL_TYPE_STRING "/glsl.vert"); +/// if (!LoadShaderFiles(vertShader, fraqShader) || !CompileAndLink()) +/// return false; +/// +/// ... +/// return true; +/// } +/// +/// ... +/// +/// void CExample::Render() +/// { +/// ... +/// +/// EnableShader(); +/// ... +/// DO WORK +/// ... +/// DisableShader(); +/// } +/// +/// void CExample::OnCompiledAndLinked() +/// { +/// ... +/// DO YOUR WORK HERE FOR WHAT IS ONE TIME REQUIRED DURING COMPILE OF SHADER, E.G.: +/// +/// m_aPosition = glGetAttribLocation(ProgramHandle(), "a_position"); +/// m_aColor = glGetAttribLocation(ProgramHandle(), "a_color"); +/// } +/// +/// bool OnEnabled() override +/// { +/// ... +/// DO YOUR WORK HERE FOR WHAT REQUIRED DURING ENABLE OF SHADER +/// ... +/// return true; +/// } +/// +/// ADDONCREATOR(CExample); +/// ~~~~~~~~~~~~~ +/// +class ATTRIBUTE_HIDDEN CShaderProgram +{ +public: + //========================================================================== + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram + /// @brief Construct a new shader. + /// + /// Load must be done later with @ref LoadShaderFiles. + /// + CShaderProgram() = default; + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram + /// @brief Construct a new shader and load defined shader files. + /// + /// @param[in] vert Path to used GL vertext shader + /// @param[in] frag Path to used GL fragment shader + /// + CShaderProgram(const std::string& vert, const std::string& frag) { LoadShaderFiles(vert, frag); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram + /// @brief Destructor. + /// + virtual ~CShaderProgram() { ShaderFree(); } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram + /// @brief To load manually the needed shader files. + /// + /// @param[in] vert Path to used GL vertext shader + /// @param[in] frag Path to used GL fragment shader + /// + /// + /// @note The use of the files is optional, but it must either be passed over + /// here or via @ref CompileAndLink, or both of the source code. + /// + bool LoadShaderFiles(const std::string& vert, const std::string& frag) + { + if (!kodi::vfs::FileExists(vert) || !m_pVP.LoadSource(vert)) + { + kodi::Log(ADDON_LOG_ERROR, "%s: Failed to load '%s'", __func__, vert.c_str()); + return false; + } + + if (!kodi::vfs::FileExists(frag) || !m_pFP.LoadSource(frag)) + { + kodi::Log(ADDON_LOG_ERROR, "%s: Failed to load '%s'", __func__, frag.c_str()); + return false; + } + + return true; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram + /// @brief To compile and link the shader to the GL interface. + /// + /// Optionally, additional source code can be transferred here, or it can be + /// used independently without any files + /// + /// @param[in] vertexExtraBegin [opt] To additionally add vextex source + /// code to the beginning of the loaded file + /// source code + /// @param[in] vertexExtraEnd [opt] To additionally add vextex source + /// code to the end of the loaded file + /// source code + /// @param[in] fragmentExtraBegin [opt] To additionally add fragment source + /// code to the beginning of the loaded file + /// source code + /// @param[in] fragmentExtraEnd [opt] To additionally add fragment source + /// code to the end of the loaded file + /// source code + /// @return true if compile was successed + /// + /// + /// @note In the case of a compile error, it will be written once into the Kodi + /// log and in addition to the console output to quickly detect the errors when + /// writing the damage. + /// + /// + bool CompileAndLink(const std::string& vertexExtraBegin = "", + const std::string& vertexExtraEnd = "", + const std::string& fragmentExtraBegin = "", + const std::string& fragmentExtraEnd = "") + { + GLint params[4]; + + // free resources + ShaderFree(); + m_ok = false; + + // compiled vertex shader + if (!m_pVP.Compile(vertexExtraBegin, vertexExtraEnd)) + { + kodi::Log(ADDON_LOG_ERROR, "GL: Error compiling vertex shader"); + return false; + } + + // compile pixel shader + if (!m_pFP.Compile(fragmentExtraBegin, fragmentExtraEnd)) + { + m_pVP.Free(); + kodi::Log(ADDON_LOG_ERROR, "GL: Error compiling fragment shader"); + return false; + } + + // create program object + m_shaderProgram = glCreateProgram(); + if (!m_shaderProgram) + { + kodi::Log(ADDON_LOG_ERROR, "CShaderProgram::%s: Failed to create GL program", __FUNCTION__); + ShaderFree(); + return false; + } + + // attach the vertex shader + glAttachShader(m_shaderProgram, m_pVP.Handle()); + glAttachShader(m_shaderProgram, m_pFP.Handle()); + + // link the program + glLinkProgram(m_shaderProgram); + glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, params); + if (params[0] != GL_TRUE) + { + GLchar log[LOG_SIZE]; + glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, nullptr, log); + kodi::Log(ADDON_LOG_ERROR, "CShaderProgram::%s: %s", __FUNCTION__, log); + fprintf(stderr, "CShaderProgram::%s: %s@n", __FUNCTION__, log); + ShaderFree(); + return false; + } + + m_validated = false; + m_ok = true; + OnCompiledAndLinked(); + return true; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram + /// @brief To activate the shader and use it on the GPU. + /// + /// @return true if enable was successfull done + /// + /// + /// @note During this call, the @ref OnEnabled stored in the child is also + /// called + /// + bool EnableShader() + { + if (ShaderOK()) + { + glUseProgram(m_shaderProgram); + if (OnEnabled()) + { + if (!m_validated) + { + // validate the program + GLint params[4]; + glValidateProgram(m_shaderProgram); + glGetProgramiv(m_shaderProgram, GL_VALIDATE_STATUS, params); + if (params[0] != GL_TRUE) + { + GLchar log[LOG_SIZE]; + glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, nullptr, log); + kodi::Log(ADDON_LOG_ERROR, "CShaderProgram::%s: %s", __FUNCTION__, log); + fprintf(stderr, "CShaderProgram::%s: %s\n", __FUNCTION__, log); + } + m_validated = true; + } + return true; + } + else + { + glUseProgram(0); + return false; + } + return true; + } + return false; + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram + /// @brief To deactivate the shader use on the GPU. + /// + void DisableShader() + { + if (ShaderOK()) + { + glUseProgram(0); + OnDisabled(); + } + } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram + /// @brief Used to check if shader has been loaded before. + /// + /// @return true if enable was successfull done + /// + /// @note The CompileAndLink call sets these values + /// + ATTRIBUTE_FORCEINLINE bool ShaderOK() const { return m_ok; } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram + /// @brief To get the vertex shader class used by Kodi at the addon. + /// + /// @return pointer to vertex shader class + /// + ATTRIBUTE_FORCEINLINE CVertexShader& VertexShader() { return m_pVP; } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram + /// @brief To get the fragment shader class used by Kodi at the addon. + /// + /// @return pointer to fragment shader class + /// + ATTRIBUTE_FORCEINLINE CPixelShader& PixelShader() { return m_pFP; } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram + /// @brief Used to get the definition created in the OpenGL itself. + /// + /// @return GLuint of GL shader program handler + /// + ATTRIBUTE_FORCEINLINE GLuint ProgramHandle() { return m_shaderProgram; } + //-------------------------------------------------------------------------- + + //========================================================================== + /// @defgroup cpp_kodi_gui_helpers_gl_CShaderProgram_child Child Functions + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram + /// @brief @cpp_class{ kodi::gui::gl::CShaderProgram child functions } + /// + /// Functions that are added by parent in the child + /// @{ + //========================================================================== + /// + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram_child + /// @brief Mandatory child function to set the necessary CPU to GPU data + /// + virtual void OnCompiledAndLinked(){}; + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram_child + /// @brief Optional function to exchange data between CPU and GPU while + /// activating the shader + /// + /// @return true if enable was successfull done + /// + virtual bool OnEnabled() { return true; }; + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram_child + /// @brief Optional child function that may have to be performed when + /// switching off the shader + virtual void OnDisabled(){}; + //-------------------------------------------------------------------------- + /// @} + +private: + void ShaderFree() + { + if (m_shaderProgram) + glDeleteProgram(m_shaderProgram); + m_shaderProgram = 0; + m_ok = false; + } + + CVertexShader m_pVP; + CPixelShader m_pFP; + GLuint m_shaderProgram = 0; + bool m_ok = false; + bool m_validated = false; +}; +//------------------------------------------------------------------------ + +} /* namespace gl */ +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/input/ActionIDs.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/input/ActionIDs.h new file mode 100644 index 0000000..4c816a4 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/input/ActionIDs.h @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../c-api/gui/input/action_ids.h" diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/input/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/gui/input/CMakeLists.txt new file mode 100644 index 0000000..d576974 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/input/CMakeLists.txt @@ -0,0 +1,5 @@ +set(HEADERS ActionIDs.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_gui_input) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/renderHelper.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/renderHelper.h new file mode 100644 index 0000000..dabe101 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/renderHelper.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2005-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../AddonBase.h" + +#ifdef __cplusplus + +namespace kodi +{ +namespace gui +{ +struct ATTRIBUTE_HIDDEN IRenderHelper +{ + virtual ~IRenderHelper() = default; + virtual bool Init() = 0; + virtual void Begin() = 0; + virtual void End() = 0; +}; /* class IRenderHelper */ +} /* namespace gui */ +} /* namespace kodi */ + +#if defined(WIN32) && defined(HAS_ANGLE) +#include "gl/GLonDX.h" +#else +/* + * Default background GUI render helper class + */ +namespace kodi +{ +namespace gui +{ +struct ATTRIBUTE_HIDDEN CRenderHelperStub : public IRenderHelper +{ + bool Init() override { return true; } + void Begin() override {} + void End() override {} +}; /* class CRenderHelperStub */ + +using CRenderHelper = CRenderHelperStub; +} /* namespace gui */ +} /* namespace kodi */ +#endif + +namespace kodi +{ +namespace gui +{ + +/* + * Create render background handler, e.g. becomes on "Windows" Angle used + * to emulate GL. + * + * This only be used internal and not from addon's direct. + * + * Function defines here and not in CAddonBase because of a hen and egg problem. + */ +inline std::shared_ptr ATTRIBUTE_HIDDEN GetRenderHelper() +{ + using namespace ::kodi::addon; + if (static_cast(CAddonBase::m_interface->addonBase)->m_renderHelper) + return static_cast(CAddonBase::m_interface->addonBase)->m_renderHelper; + + const std::shared_ptr renderHelper(new CRenderHelper()); + if (!renderHelper->Init()) + return nullptr; + + static_cast(CAddonBase::m_interface->addonBase)->m_renderHelper = + renderHelper; // Hold on base for other types + return renderHelper; +} + +} /* namespace gui */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/platform/android/System.h b/xbmc/addons/kodi-dev-kit/include/kodi/platform/android/System.h new file mode 100644 index 0000000..245abd6 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/platform/android/System.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "../../AddonBase.h" +#include "../../c-api/platform/android/system.h" + +#ifdef __cplusplus +namespace kodi +{ +namespace platform +{ + +//============================================================================== +/// @defgroup cpp_kodi_platform_CInterfaceAndroidSystem class CInterfaceAndroidSystem +/// @ingroup cpp_kodi_platform +/// @brief **Android platform specific functions**\n +/// C++ class to query Android specific things in Kodi. +/// +/// It has the header is @ref System.h "#include ". +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// #if defined(ANDROID) +/// kodi::platform::CInterfaceAndroidSystem system; +/// if (system.GetSDKVersion() >= 23) +/// { +/// ... +/// } +/// #endif +/// ~~~~~~~~~~~~~ +/// +class ATTRIBUTE_HIDDEN CInterfaceAndroidSystem +{ +public: + CInterfaceAndroidSystem() + : m_interface(static_cast( + GetInterface(INTERFACE_ANDROID_SYSTEM_NAME, INTERFACE_ANDROID_SYSTEM_VERSION))){}; + + //============================================================================ + /// @ingroup cpp_kodi_platform_CInterfaceAndroidSystem + /// @brief Request an JNI env pointer for the calling thread. + /// + /// JNI env has to be controlled by kodi because of the underlying + /// threading concep. + /// + /// @return JNI env pointer for the calling thread + /// + inline void* GetJNIEnv() + { + if (m_interface) + return m_interface->get_jni_env(); + + return nullptr; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_platform_CInterfaceAndroidSystem + /// @brief Request the android sdk version to e.g. initialize `JNIBase`. + /// + /// @return Android SDK version + /// + inline int GetSDKVersion() + { + if (m_interface) + return m_interface->get_sdk_version(); + + return 0; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_platform_CInterfaceAndroidSystem + /// @brief Request the android main class name e.g. `org.xbmc.kodi`. + /// + /// @return package class name + /// + inline std::string GetClassName() + { + if (m_interface) + return m_interface->get_class_name(); + + return std::string(); + } + //---------------------------------------------------------------------------- + +private: + AddonToKodiFuncTable_android_system* m_interface; +}; +//------------------------------------------------------------------------------ + +} /* namespace platform */ +} /* namespace kodi */ +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/tools/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/tools/CMakeLists.txt new file mode 100644 index 0000000..16b83cb --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/tools/CMakeLists.txt @@ -0,0 +1,9 @@ +set(HEADERS DllHelper.h + EndTime.h + StringUtils.h + Thread.h + Timer.h) + +if(NOT ENABLE_STATIC_LIBS) + core_add_library(addons_kodi-dev-kit_include_kodi_tools) +endif() diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/tools/DllHelper.h b/xbmc/addons/kodi-dev-kit/include/kodi/tools/DllHelper.h new file mode 100644 index 0000000..3cc9eea --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/tools/DllHelper.h @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifdef __cplusplus + +#include + +#include +#include +#include + +//============================================================================== +/// @ingroup cpp_kodi_tools_CDllHelper +/// @brief Macro to translate the given pointer value name of functions to +/// requested function name. +/// +/// @note This should always be used and does the work of +/// @ref kodi::tools::CDllHelper::RegisterSymbol(). +/// +#define REGISTER_DLL_SYMBOL(functionPtr) \ + kodi::tools::CDllHelper::RegisterSymbol(functionPtr, #functionPtr) +//------------------------------------------------------------------------------ + +namespace kodi +{ +namespace tools +{ + +//============================================================================== +/// @defgroup cpp_kodi_tools_CDllHelper class CDllHelper +/// @ingroup cpp_kodi_tools +/// @brief **Class to help with load of shared library functions**\n +/// You can add them as parent to your class and to help with load of shared +/// library functions. +/// +/// @note To use on Windows must you also include [dlfcn-win32](https://github.com/dlfcn-win32/dlfcn-win32) +/// on your addon!\n\n +/// Furthermore, this allows the use of Android where the required library is +/// copied to an EXE useable folder. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// +/// #include +/// +/// ... +/// class CMyInstance : public kodi::addon::CInstanceAudioDecoder, +/// private kodi::tools::CDllHelper +/// { +/// public: +/// CMyInstance(KODI_HANDLE instance, const std::string& kodiVersion); +/// bool Start(); +/// +/// ... +/// +/// // The pointers for on shared library exported functions +/// int (*Init)(); +/// void (*Cleanup)(); +/// int (*GetLength)(); +/// }; +/// +/// CMyInstance::CMyInstance(KODI_HANDLE instance, const std::string& kodiVersion) +/// : CInstanceAudioDecoder(instance, kodiVersion) +/// { +/// } +/// +/// bool CMyInstance::Start() +/// { +/// std::string lib = kodi::GetAddonPath("myLib.so"); +/// if (!LoadDll(lib)) return false; +/// if (!REGISTER_DLL_SYMBOL(Init)) return false; +/// if (!REGISTER_DLL_SYMBOL(Cleanup)) return false; +/// if (!REGISTER_DLL_SYMBOL(GetLength)) return false; +/// +/// Init(); +/// return true; +/// } +/// ... +/// ~~~~~~~~~~~~~ +/// +///@{ +class ATTRIBUTE_HIDDEN CDllHelper +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_tools_CDllHelper + /// @brief Class constructor. + /// + CDllHelper() = default; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CDllHelper + /// @brief Class destructor. + /// + virtual ~CDllHelper() + { + if (m_dll) + dlclose(m_dll); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CDllHelper + /// @brief Function to load requested library. + /// + /// @param[in] path The path with filename of shared library to load + /// @return true if load was successful done + /// + bool LoadDll(std::string path) + { +#if defined(TARGET_ANDROID) + if (kodi::vfs::FileExists(path)) + { + // Check already defined for "xbmcaltbinaddons", if yes no copy necassary. + std::string xbmcaltbinaddons = + kodi::vfs::TranslateSpecialProtocol("special://xbmcaltbinaddons/"); + if (path.compare(0, xbmcaltbinaddons.length(), xbmcaltbinaddons) != 0) + { + bool doCopy = true; + std::string dstfile = xbmcaltbinaddons + kodi::vfs::GetFileName(path); + + kodi::vfs::FileStatus dstFileStat; + if (kodi::vfs::StatFile(dstfile, dstFileStat)) + { + kodi::vfs::FileStatus srcFileStat; + if (kodi::vfs::StatFile(path, srcFileStat)) + { + if (dstFileStat.GetSize() == srcFileStat.GetSize() && + dstFileStat.GetModificationTime() > srcFileStat.GetModificationTime()) + doCopy = false; + } + } + + if (doCopy) + { + kodi::Log(ADDON_LOG_DEBUG, "Caching '%s' to '%s'", path.c_str(), dstfile.c_str()); + if (!kodi::vfs::CopyFile(path, dstfile)) + { + kodi::Log(ADDON_LOG_ERROR, "Failed to cache '%s' to '%s'", path.c_str(), + dstfile.c_str()); + return false; + } + } + + path = dstfile; + } + } + else + { + return false; + } +#endif + + m_dll = dlopen(path.c_str(), RTLD_LAZY); + if (m_dll == nullptr) + { + kodi::Log(ADDON_LOG_ERROR, "Unable to load %s", dlerror()); + return false; + } + return true; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CDllHelper + /// @brief Function to register requested library symbol. + /// + /// @warning This function should not be used, use instead the macro + /// @ref REGISTER_DLL_SYMBOL to register the symbol pointer. + /// + /// + /// Use this always via Macro, e.g.: + /// ~~~~~~~~~~~~~{.cpp} + /// if (!REGISTER_DLL_SYMBOL(Init)) + /// return false; + /// ~~~~~~~~~~~~~ + /// + template + bool RegisterSymbol(T& functionPtr, const char* strFunctionPtr) + { + functionPtr = reinterpret_cast(dlsym(m_dll, strFunctionPtr)); + if (functionPtr == nullptr) + { + kodi::Log(ADDON_LOG_ERROR, "Unable to assign function %s", dlerror()); + return false; + } + return true; + } + //---------------------------------------------------------------------------- + +private: + void* m_dll = nullptr; +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace tools */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/tools/EndTime.h b/xbmc/addons/kodi-dev-kit/include/kodi/tools/EndTime.h new file mode 100644 index 0000000..14983fa --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/tools/EndTime.h @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. + */ + +#pragma once + +#ifdef __cplusplus + +#include + +namespace kodi +{ +namespace tools +{ + +//============================================================================== +/// @defgroup cpp_kodi_tools_CEndTime class CEndTime +/// @ingroup cpp_kodi_tools +/// @brief **Timeout check**\n +/// Class which makes it easy to check if a specified amount of time has passed. +/// +/// This code uses the support of platform-independent chrono system introduced +/// with C++11. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class ATTRIBUTE_HIDDEN CExample +/// { +/// public: +/// CExample() +/// { +/// TimerCall(); +/// } +/// +/// void TimerCall() +/// { +/// fprintf(stderr, "Hello World\n"); +/// CEndTime timer(1000); +/// +/// while (timer.MillisLeft()) +/// { +/// if (timer.IsTimePast()) +/// { +/// fprintf(stderr, "We timed out!\n"); +/// } +/// std::this_thread::sleep_for(std::chrono::milliseconds(10)); +/// } +/// } +/// +/// }; +/// ~~~~~~~~~~~~~ +/// +///@{ +class CEndTime +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_tools_CEndTime + /// @brief Class constructor with no time to expiry set + /// + inline CEndTime() = default; + //============================================================================ + /// @ingroup cpp_kodi_tools_CEndTime + /// @brief Class constructor to set future time when timer has expired + /// + /// @param[in] millisecondsIntoTheFuture the time in the future we cosider this timer as expired + /// + inline explicit CEndTime(unsigned int millisecondsIntoTheFuture) + : m_startTime(std::chrono::system_clock::now().time_since_epoch()), + m_totalWaitTime(std::chrono::milliseconds(millisecondsIntoTheFuture)) + { + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CEndTime + /// @brief Set the time in the future we cosider this timer as expired + /// + /// @param[in] millisecondsIntoTheFuture the time in the future we cosider this timer as expired + /// + inline void Set(unsigned int millisecondsIntoTheFuture) + { + using namespace std::chrono; + + m_startTime = system_clock::now().time_since_epoch(); + m_totalWaitTime = milliseconds(millisecondsIntoTheFuture); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CEndTime + /// @brief Check if the expiry time has been reached + /// + /// @return True if the expiry amount of time has past, false otherwise + /// + inline bool IsTimePast() const + { + using namespace std::chrono; + + // timer is infinite + if (m_totalWaitTime.count() == std::numeric_limits::max()) + return false; + + if (m_totalWaitTime.count() == 0) + return true; + else + return (system_clock::now().time_since_epoch() - m_startTime) >= m_totalWaitTime; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CEndTime + /// @brief The amount of time left till this timer expires + /// + /// @return 0 if the expiry amount of time has past, the numbe rof milliseconds remaining otherwise + /// + inline unsigned int MillisLeft() const + { + using namespace std::chrono; + + // timer is infinite + if (m_totalWaitTime.count() == std::numeric_limits::max()) + return std::numeric_limits::max(); + + if (m_totalWaitTime.count() == 0) + return 0; + + auto elapsed = system_clock::now().time_since_epoch() - m_startTime; + + auto timeWaitedAlready = duration_cast(elapsed).count(); + + if (timeWaitedAlready >= m_totalWaitTime.count()) + return 0; + + return static_cast(m_totalWaitTime.count() - timeWaitedAlready); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CEndTime + /// @brief Consider this timer expired + /// + inline void SetExpired() + { + using namespace std::chrono; + m_totalWaitTime = milliseconds(0); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CEndTime + /// @brief Set this timer as never expiring + /// + inline void SetInfinite() + { + using namespace std::chrono; + m_totalWaitTime = milliseconds(std::numeric_limits::max()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CEndTime + /// @brief Check if the timer has been set to infinite expiry + /// + /// @return True if the expiry has been set as infinite, false otherwise + /// + inline bool IsInfinite(void) const + { + return (m_totalWaitTime.count() == std::numeric_limits::max()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CEndTime + /// @brief Get the initial timeout value this timer had + /// + /// @return The initial expiry amount of time this timer had in milliseconds + /// + inline unsigned int GetInitialTimeoutValue(void) const + { + auto value = std::chrono::duration_cast(m_totalWaitTime); + return static_cast(value.count()); + } + + //============================================================================ + /// @ingroup cpp_kodi_tools_CEndTime + /// @brief Get the time this timer started + /// + /// @return The time this timer started in milliseconds since epoch + /// + inline uint64_t GetStartTime(void) const + { + auto value = std::chrono::duration_cast(m_startTime); + return value.count(); + } + //---------------------------------------------------------------------------- + +private: + std::chrono::system_clock::duration m_startTime; + std::chrono::system_clock::duration m_totalWaitTime; +}; + +} /* namespace tools */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/tools/StringUtils.h b/xbmc/addons/kodi-dev-kit/include/kodi/tools/StringUtils.h new file mode 100644 index 0000000..977c0e5 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/tools/StringUtils.h @@ -0,0 +1,3086 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifdef __cplusplus + +#if !defined(NOMINMAX) +#define NOMINMAX +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// # of bytes for initial allocation for printf +#define FORMAT_BLOCK_SIZE 512 + +// macros for gcc, clang & others +#ifndef PARAM1_PRINTF_FORMAT +#ifdef __GNUC__ +// for use in functions that take printf format string as first parameter and additional printf parameters as second parameter +// for example: int myprintf(const char* format, ...) PARAM1_PRINTF_FORMAT; +#define PARAM1_PRINTF_FORMAT __attribute__((format(printf, 1, 2))) + +// for use in functions that take printf format string as second parameter and additional printf parameters as third parameter +// for example: bool log_string(int logLevel, const char* format, ...) PARAM2_PRINTF_FORMAT; +// note: all non-static class member functions take pointer to class object as hidden first parameter +#define PARAM2_PRINTF_FORMAT __attribute__((format(printf, 2, 3))) + +// for use in functions that take printf format string as third parameter and additional printf parameters as fourth parameter +// note: all non-static class member functions take pointer to class object as hidden first parameter +// for example: class A { bool log_string(int logLevel, const char* functionName, const char* format, ...) PARAM3_PRINTF_FORMAT; }; +#define PARAM3_PRINTF_FORMAT __attribute__((format(printf, 3, 4))) + +// for use in functions that take printf format string as fourth parameter and additional printf parameters as fith parameter +// note: all non-static class member functions take pointer to class object as hidden first parameter +// for example: class A { bool log_string(int logLevel, const char* functionName, int component, const char* format, ...) PARAM4_PRINTF_FORMAT; }; +#define PARAM4_PRINTF_FORMAT __attribute__((format(printf, 4, 5))) +#else // ! __GNUC__ +#define PARAM1_PRINTF_FORMAT +#define PARAM2_PRINTF_FORMAT +#define PARAM3_PRINTF_FORMAT +#define PARAM4_PRINTF_FORMAT +#endif // ! __GNUC__ +#endif // PARAM1_PRINTF_FORMAT + +// macros for VC +// VC check parameters only when "Code Analysis" is called +#ifndef PRINTF_FORMAT_STRING +#ifdef _MSC_VER +#include + +// for use in any function that take printf format string and parameters +// for example: bool log_string(int logLevel, PRINTF_FORMAT_STRING const char* format, ...); +#define PRINTF_FORMAT_STRING _In_z_ _Printf_format_string_ + +// specify that parameter must be zero-terminated string +// for example: void SetName(IN_STRING const char* newName); +#define IN_STRING _In_z_ + +// specify that parameter must be zero-terminated string or NULL +// for example: bool SetAdditionalName(IN_OPT_STRING const char* addName); +#define IN_OPT_STRING _In_opt_z_ +#else // ! _MSC_VER +#define PRINTF_FORMAT_STRING +#define IN_STRING +#define IN_OPT_STRING +#endif // ! _MSC_VER +#endif // PRINTF_FORMAT_STRING + +static constexpr wchar_t unicode_lowers[] = { + (wchar_t)0x0061, (wchar_t)0x0062, (wchar_t)0x0063, (wchar_t)0x0064, (wchar_t)0x0065, + (wchar_t)0x0066, (wchar_t)0x0067, (wchar_t)0x0068, (wchar_t)0x0069, (wchar_t)0x006A, + (wchar_t)0x006B, (wchar_t)0x006C, (wchar_t)0x006D, (wchar_t)0x006E, (wchar_t)0x006F, + (wchar_t)0x0070, (wchar_t)0x0071, (wchar_t)0x0072, (wchar_t)0x0073, (wchar_t)0x0074, + (wchar_t)0x0075, (wchar_t)0x0076, (wchar_t)0x0077, (wchar_t)0x0078, (wchar_t)0x0079, + (wchar_t)0x007A, (wchar_t)0x00E0, (wchar_t)0x00E1, (wchar_t)0x00E2, (wchar_t)0x00E3, + (wchar_t)0x00E4, (wchar_t)0x00E5, (wchar_t)0x00E6, (wchar_t)0x00E7, (wchar_t)0x00E8, + (wchar_t)0x00E9, (wchar_t)0x00EA, (wchar_t)0x00EB, (wchar_t)0x00EC, (wchar_t)0x00ED, + (wchar_t)0x00EE, (wchar_t)0x00EF, (wchar_t)0x00F0, (wchar_t)0x00F1, (wchar_t)0x00F2, + (wchar_t)0x00F3, (wchar_t)0x00F4, (wchar_t)0x00F5, (wchar_t)0x00F6, (wchar_t)0x00F8, + (wchar_t)0x00F9, (wchar_t)0x00FA, (wchar_t)0x00FB, (wchar_t)0x00FC, (wchar_t)0x00FD, + (wchar_t)0x00FE, (wchar_t)0x00FF, (wchar_t)0x0101, (wchar_t)0x0103, (wchar_t)0x0105, + (wchar_t)0x0107, (wchar_t)0x0109, (wchar_t)0x010B, (wchar_t)0x010D, (wchar_t)0x010F, + (wchar_t)0x0111, (wchar_t)0x0113, (wchar_t)0x0115, (wchar_t)0x0117, (wchar_t)0x0119, + (wchar_t)0x011B, (wchar_t)0x011D, (wchar_t)0x011F, (wchar_t)0x0121, (wchar_t)0x0123, + (wchar_t)0x0125, (wchar_t)0x0127, (wchar_t)0x0129, (wchar_t)0x012B, (wchar_t)0x012D, + (wchar_t)0x012F, (wchar_t)0x0131, (wchar_t)0x0133, (wchar_t)0x0135, (wchar_t)0x0137, + (wchar_t)0x013A, (wchar_t)0x013C, (wchar_t)0x013E, (wchar_t)0x0140, (wchar_t)0x0142, + (wchar_t)0x0144, (wchar_t)0x0146, (wchar_t)0x0148, (wchar_t)0x014B, (wchar_t)0x014D, + (wchar_t)0x014F, (wchar_t)0x0151, (wchar_t)0x0153, (wchar_t)0x0155, (wchar_t)0x0157, + (wchar_t)0x0159, (wchar_t)0x015B, (wchar_t)0x015D, (wchar_t)0x015F, (wchar_t)0x0161, + (wchar_t)0x0163, (wchar_t)0x0165, (wchar_t)0x0167, (wchar_t)0x0169, (wchar_t)0x016B, + (wchar_t)0x016D, (wchar_t)0x016F, (wchar_t)0x0171, (wchar_t)0x0173, (wchar_t)0x0175, + (wchar_t)0x0177, (wchar_t)0x017A, (wchar_t)0x017C, (wchar_t)0x017E, (wchar_t)0x0183, + (wchar_t)0x0185, (wchar_t)0x0188, (wchar_t)0x018C, (wchar_t)0x0192, (wchar_t)0x0199, + (wchar_t)0x01A1, (wchar_t)0x01A3, (wchar_t)0x01A5, (wchar_t)0x01A8, (wchar_t)0x01AD, + (wchar_t)0x01B0, (wchar_t)0x01B4, (wchar_t)0x01B6, (wchar_t)0x01B9, (wchar_t)0x01BD, + (wchar_t)0x01C6, (wchar_t)0x01C9, (wchar_t)0x01CC, (wchar_t)0x01CE, (wchar_t)0x01D0, + (wchar_t)0x01D2, (wchar_t)0x01D4, (wchar_t)0x01D6, (wchar_t)0x01D8, (wchar_t)0x01DA, + (wchar_t)0x01DC, (wchar_t)0x01DF, (wchar_t)0x01E1, (wchar_t)0x01E3, (wchar_t)0x01E5, + (wchar_t)0x01E7, (wchar_t)0x01E9, (wchar_t)0x01EB, (wchar_t)0x01ED, (wchar_t)0x01EF, + (wchar_t)0x01F3, (wchar_t)0x01F5, (wchar_t)0x01FB, (wchar_t)0x01FD, (wchar_t)0x01FF, + (wchar_t)0x0201, (wchar_t)0x0203, (wchar_t)0x0205, (wchar_t)0x0207, (wchar_t)0x0209, + (wchar_t)0x020B, (wchar_t)0x020D, (wchar_t)0x020F, (wchar_t)0x0211, (wchar_t)0x0213, + (wchar_t)0x0215, (wchar_t)0x0217, (wchar_t)0x0253, (wchar_t)0x0254, (wchar_t)0x0257, + (wchar_t)0x0258, (wchar_t)0x0259, (wchar_t)0x025B, (wchar_t)0x0260, (wchar_t)0x0263, + (wchar_t)0x0268, (wchar_t)0x0269, (wchar_t)0x026F, (wchar_t)0x0272, (wchar_t)0x0275, + (wchar_t)0x0283, (wchar_t)0x0288, (wchar_t)0x028A, (wchar_t)0x028B, (wchar_t)0x0292, + (wchar_t)0x03AC, (wchar_t)0x03AD, (wchar_t)0x03AE, (wchar_t)0x03AF, (wchar_t)0x03B1, + (wchar_t)0x03B2, (wchar_t)0x03B3, (wchar_t)0x03B4, (wchar_t)0x03B5, (wchar_t)0x03B6, + (wchar_t)0x03B7, (wchar_t)0x03B8, (wchar_t)0x03B9, (wchar_t)0x03BA, (wchar_t)0x03BB, + (wchar_t)0x03BC, (wchar_t)0x03BD, (wchar_t)0x03BE, (wchar_t)0x03BF, (wchar_t)0x03C0, + (wchar_t)0x03C1, (wchar_t)0x03C3, (wchar_t)0x03C4, (wchar_t)0x03C5, (wchar_t)0x03C6, + (wchar_t)0x03C7, (wchar_t)0x03C8, (wchar_t)0x03C9, (wchar_t)0x03CA, (wchar_t)0x03CB, + (wchar_t)0x03CC, (wchar_t)0x03CD, (wchar_t)0x03CE, (wchar_t)0x03E3, (wchar_t)0x03E5, + (wchar_t)0x03E7, (wchar_t)0x03E9, (wchar_t)0x03EB, (wchar_t)0x03ED, (wchar_t)0x03EF, + (wchar_t)0x0430, (wchar_t)0x0431, (wchar_t)0x0432, (wchar_t)0x0433, (wchar_t)0x0434, + (wchar_t)0x0435, (wchar_t)0x0436, (wchar_t)0x0437, (wchar_t)0x0438, (wchar_t)0x0439, + (wchar_t)0x043A, (wchar_t)0x043B, (wchar_t)0x043C, (wchar_t)0x043D, (wchar_t)0x043E, + (wchar_t)0x043F, (wchar_t)0x0440, (wchar_t)0x0441, (wchar_t)0x0442, (wchar_t)0x0443, + (wchar_t)0x0444, (wchar_t)0x0445, (wchar_t)0x0446, (wchar_t)0x0447, (wchar_t)0x0448, + (wchar_t)0x0449, (wchar_t)0x044A, (wchar_t)0x044B, (wchar_t)0x044C, (wchar_t)0x044D, + (wchar_t)0x044E, (wchar_t)0x044F, (wchar_t)0x0451, (wchar_t)0x0452, (wchar_t)0x0453, + (wchar_t)0x0454, (wchar_t)0x0455, (wchar_t)0x0456, (wchar_t)0x0457, (wchar_t)0x0458, + (wchar_t)0x0459, (wchar_t)0x045A, (wchar_t)0x045B, (wchar_t)0x045C, (wchar_t)0x045E, + (wchar_t)0x045F, (wchar_t)0x0461, (wchar_t)0x0463, (wchar_t)0x0465, (wchar_t)0x0467, + (wchar_t)0x0469, (wchar_t)0x046B, (wchar_t)0x046D, (wchar_t)0x046F, (wchar_t)0x0471, + (wchar_t)0x0473, (wchar_t)0x0475, (wchar_t)0x0477, (wchar_t)0x0479, (wchar_t)0x047B, + (wchar_t)0x047D, (wchar_t)0x047F, (wchar_t)0x0481, (wchar_t)0x0491, (wchar_t)0x0493, + (wchar_t)0x0495, (wchar_t)0x0497, (wchar_t)0x0499, (wchar_t)0x049B, (wchar_t)0x049D, + (wchar_t)0x049F, (wchar_t)0x04A1, (wchar_t)0x04A3, (wchar_t)0x04A5, (wchar_t)0x04A7, + (wchar_t)0x04A9, (wchar_t)0x04AB, (wchar_t)0x04AD, (wchar_t)0x04AF, (wchar_t)0x04B1, + (wchar_t)0x04B3, (wchar_t)0x04B5, (wchar_t)0x04B7, (wchar_t)0x04B9, (wchar_t)0x04BB, + (wchar_t)0x04BD, (wchar_t)0x04BF, (wchar_t)0x04C2, (wchar_t)0x04C4, (wchar_t)0x04C8, + (wchar_t)0x04CC, (wchar_t)0x04D1, (wchar_t)0x04D3, (wchar_t)0x04D5, (wchar_t)0x04D7, + (wchar_t)0x04D9, (wchar_t)0x04DB, (wchar_t)0x04DD, (wchar_t)0x04DF, (wchar_t)0x04E1, + (wchar_t)0x04E3, (wchar_t)0x04E5, (wchar_t)0x04E7, (wchar_t)0x04E9, (wchar_t)0x04EB, + (wchar_t)0x04EF, (wchar_t)0x04F1, (wchar_t)0x04F3, (wchar_t)0x04F5, (wchar_t)0x04F9, + (wchar_t)0x0561, (wchar_t)0x0562, (wchar_t)0x0563, (wchar_t)0x0564, (wchar_t)0x0565, + (wchar_t)0x0566, (wchar_t)0x0567, (wchar_t)0x0568, (wchar_t)0x0569, (wchar_t)0x056A, + (wchar_t)0x056B, (wchar_t)0x056C, (wchar_t)0x056D, (wchar_t)0x056E, (wchar_t)0x056F, + (wchar_t)0x0570, (wchar_t)0x0571, (wchar_t)0x0572, (wchar_t)0x0573, (wchar_t)0x0574, + (wchar_t)0x0575, (wchar_t)0x0576, (wchar_t)0x0577, (wchar_t)0x0578, (wchar_t)0x0579, + (wchar_t)0x057A, (wchar_t)0x057B, (wchar_t)0x057C, (wchar_t)0x057D, (wchar_t)0x057E, + (wchar_t)0x057F, (wchar_t)0x0580, (wchar_t)0x0581, (wchar_t)0x0582, (wchar_t)0x0583, + (wchar_t)0x0584, (wchar_t)0x0585, (wchar_t)0x0586, (wchar_t)0x10D0, (wchar_t)0x10D1, + (wchar_t)0x10D2, (wchar_t)0x10D3, (wchar_t)0x10D4, (wchar_t)0x10D5, (wchar_t)0x10D6, + (wchar_t)0x10D7, (wchar_t)0x10D8, (wchar_t)0x10D9, (wchar_t)0x10DA, (wchar_t)0x10DB, + (wchar_t)0x10DC, (wchar_t)0x10DD, (wchar_t)0x10DE, (wchar_t)0x10DF, (wchar_t)0x10E0, + (wchar_t)0x10E1, (wchar_t)0x10E2, (wchar_t)0x10E3, (wchar_t)0x10E4, (wchar_t)0x10E5, + (wchar_t)0x10E6, (wchar_t)0x10E7, (wchar_t)0x10E8, (wchar_t)0x10E9, (wchar_t)0x10EA, + (wchar_t)0x10EB, (wchar_t)0x10EC, (wchar_t)0x10ED, (wchar_t)0x10EE, (wchar_t)0x10EF, + (wchar_t)0x10F0, (wchar_t)0x10F1, (wchar_t)0x10F2, (wchar_t)0x10F3, (wchar_t)0x10F4, + (wchar_t)0x10F5, (wchar_t)0x1E01, (wchar_t)0x1E03, (wchar_t)0x1E05, (wchar_t)0x1E07, + (wchar_t)0x1E09, (wchar_t)0x1E0B, (wchar_t)0x1E0D, (wchar_t)0x1E0F, (wchar_t)0x1E11, + (wchar_t)0x1E13, (wchar_t)0x1E15, (wchar_t)0x1E17, (wchar_t)0x1E19, (wchar_t)0x1E1B, + (wchar_t)0x1E1D, (wchar_t)0x1E1F, (wchar_t)0x1E21, (wchar_t)0x1E23, (wchar_t)0x1E25, + (wchar_t)0x1E27, (wchar_t)0x1E29, (wchar_t)0x1E2B, (wchar_t)0x1E2D, (wchar_t)0x1E2F, + (wchar_t)0x1E31, (wchar_t)0x1E33, (wchar_t)0x1E35, (wchar_t)0x1E37, (wchar_t)0x1E39, + (wchar_t)0x1E3B, (wchar_t)0x1E3D, (wchar_t)0x1E3F, (wchar_t)0x1E41, (wchar_t)0x1E43, + (wchar_t)0x1E45, (wchar_t)0x1E47, (wchar_t)0x1E49, (wchar_t)0x1E4B, (wchar_t)0x1E4D, + (wchar_t)0x1E4F, (wchar_t)0x1E51, (wchar_t)0x1E53, (wchar_t)0x1E55, (wchar_t)0x1E57, + (wchar_t)0x1E59, (wchar_t)0x1E5B, (wchar_t)0x1E5D, (wchar_t)0x1E5F, (wchar_t)0x1E61, + (wchar_t)0x1E63, (wchar_t)0x1E65, (wchar_t)0x1E67, (wchar_t)0x1E69, (wchar_t)0x1E6B, + (wchar_t)0x1E6D, (wchar_t)0x1E6F, (wchar_t)0x1E71, (wchar_t)0x1E73, (wchar_t)0x1E75, + (wchar_t)0x1E77, (wchar_t)0x1E79, (wchar_t)0x1E7B, (wchar_t)0x1E7D, (wchar_t)0x1E7F, + (wchar_t)0x1E81, (wchar_t)0x1E83, (wchar_t)0x1E85, (wchar_t)0x1E87, (wchar_t)0x1E89, + (wchar_t)0x1E8B, (wchar_t)0x1E8D, (wchar_t)0x1E8F, (wchar_t)0x1E91, (wchar_t)0x1E93, + (wchar_t)0x1E95, (wchar_t)0x1EA1, (wchar_t)0x1EA3, (wchar_t)0x1EA5, (wchar_t)0x1EA7, + (wchar_t)0x1EA9, (wchar_t)0x1EAB, (wchar_t)0x1EAD, (wchar_t)0x1EAF, (wchar_t)0x1EB1, + (wchar_t)0x1EB3, (wchar_t)0x1EB5, (wchar_t)0x1EB7, (wchar_t)0x1EB9, (wchar_t)0x1EBB, + (wchar_t)0x1EBD, (wchar_t)0x1EBF, (wchar_t)0x1EC1, (wchar_t)0x1EC3, (wchar_t)0x1EC5, + (wchar_t)0x1EC7, (wchar_t)0x1EC9, (wchar_t)0x1ECB, (wchar_t)0x1ECD, (wchar_t)0x1ECF, + (wchar_t)0x1ED1, (wchar_t)0x1ED3, (wchar_t)0x1ED5, (wchar_t)0x1ED7, (wchar_t)0x1ED9, + (wchar_t)0x1EDB, (wchar_t)0x1EDD, (wchar_t)0x1EDF, (wchar_t)0x1EE1, (wchar_t)0x1EE3, + (wchar_t)0x1EE5, (wchar_t)0x1EE7, (wchar_t)0x1EE9, (wchar_t)0x1EEB, (wchar_t)0x1EED, + (wchar_t)0x1EEF, (wchar_t)0x1EF1, (wchar_t)0x1EF3, (wchar_t)0x1EF5, (wchar_t)0x1EF7, + (wchar_t)0x1EF9, (wchar_t)0x1F00, (wchar_t)0x1F01, (wchar_t)0x1F02, (wchar_t)0x1F03, + (wchar_t)0x1F04, (wchar_t)0x1F05, (wchar_t)0x1F06, (wchar_t)0x1F07, (wchar_t)0x1F10, + (wchar_t)0x1F11, (wchar_t)0x1F12, (wchar_t)0x1F13, (wchar_t)0x1F14, (wchar_t)0x1F15, + (wchar_t)0x1F20, (wchar_t)0x1F21, (wchar_t)0x1F22, (wchar_t)0x1F23, (wchar_t)0x1F24, + (wchar_t)0x1F25, (wchar_t)0x1F26, (wchar_t)0x1F27, (wchar_t)0x1F30, (wchar_t)0x1F31, + (wchar_t)0x1F32, (wchar_t)0x1F33, (wchar_t)0x1F34, (wchar_t)0x1F35, (wchar_t)0x1F36, + (wchar_t)0x1F37, (wchar_t)0x1F40, (wchar_t)0x1F41, (wchar_t)0x1F42, (wchar_t)0x1F43, + (wchar_t)0x1F44, (wchar_t)0x1F45, (wchar_t)0x1F51, (wchar_t)0x1F53, (wchar_t)0x1F55, + (wchar_t)0x1F57, (wchar_t)0x1F60, (wchar_t)0x1F61, (wchar_t)0x1F62, (wchar_t)0x1F63, + (wchar_t)0x1F64, (wchar_t)0x1F65, (wchar_t)0x1F66, (wchar_t)0x1F67, (wchar_t)0x1F80, + (wchar_t)0x1F81, (wchar_t)0x1F82, (wchar_t)0x1F83, (wchar_t)0x1F84, (wchar_t)0x1F85, + (wchar_t)0x1F86, (wchar_t)0x1F87, (wchar_t)0x1F90, (wchar_t)0x1F91, (wchar_t)0x1F92, + (wchar_t)0x1F93, (wchar_t)0x1F94, (wchar_t)0x1F95, (wchar_t)0x1F96, (wchar_t)0x1F97, + (wchar_t)0x1FA0, (wchar_t)0x1FA1, (wchar_t)0x1FA2, (wchar_t)0x1FA3, (wchar_t)0x1FA4, + (wchar_t)0x1FA5, (wchar_t)0x1FA6, (wchar_t)0x1FA7, (wchar_t)0x1FB0, (wchar_t)0x1FB1, + (wchar_t)0x1FD0, (wchar_t)0x1FD1, (wchar_t)0x1FE0, (wchar_t)0x1FE1, (wchar_t)0x24D0, + (wchar_t)0x24D1, (wchar_t)0x24D2, (wchar_t)0x24D3, (wchar_t)0x24D4, (wchar_t)0x24D5, + (wchar_t)0x24D6, (wchar_t)0x24D7, (wchar_t)0x24D8, (wchar_t)0x24D9, (wchar_t)0x24DA, + (wchar_t)0x24DB, (wchar_t)0x24DC, (wchar_t)0x24DD, (wchar_t)0x24DE, (wchar_t)0x24DF, + (wchar_t)0x24E0, (wchar_t)0x24E1, (wchar_t)0x24E2, (wchar_t)0x24E3, (wchar_t)0x24E4, + (wchar_t)0x24E5, (wchar_t)0x24E6, (wchar_t)0x24E7, (wchar_t)0x24E8, (wchar_t)0x24E9, + (wchar_t)0xFF41, (wchar_t)0xFF42, (wchar_t)0xFF43, (wchar_t)0xFF44, (wchar_t)0xFF45, + (wchar_t)0xFF46, (wchar_t)0xFF47, (wchar_t)0xFF48, (wchar_t)0xFF49, (wchar_t)0xFF4A, + (wchar_t)0xFF4B, (wchar_t)0xFF4C, (wchar_t)0xFF4D, (wchar_t)0xFF4E, (wchar_t)0xFF4F, + (wchar_t)0xFF50, (wchar_t)0xFF51, (wchar_t)0xFF52, (wchar_t)0xFF53, (wchar_t)0xFF54, + (wchar_t)0xFF55, (wchar_t)0xFF56, (wchar_t)0xFF57, (wchar_t)0xFF58, (wchar_t)0xFF59, + (wchar_t)0xFF5A}; + +static const wchar_t unicode_uppers[] = { + (wchar_t)0x0041, (wchar_t)0x0042, (wchar_t)0x0043, (wchar_t)0x0044, (wchar_t)0x0045, + (wchar_t)0x0046, (wchar_t)0x0047, (wchar_t)0x0048, (wchar_t)0x0049, (wchar_t)0x004A, + (wchar_t)0x004B, (wchar_t)0x004C, (wchar_t)0x004D, (wchar_t)0x004E, (wchar_t)0x004F, + (wchar_t)0x0050, (wchar_t)0x0051, (wchar_t)0x0052, (wchar_t)0x0053, (wchar_t)0x0054, + (wchar_t)0x0055, (wchar_t)0x0056, (wchar_t)0x0057, (wchar_t)0x0058, (wchar_t)0x0059, + (wchar_t)0x005A, (wchar_t)0x00C0, (wchar_t)0x00C1, (wchar_t)0x00C2, (wchar_t)0x00C3, + (wchar_t)0x00C4, (wchar_t)0x00C5, (wchar_t)0x00C6, (wchar_t)0x00C7, (wchar_t)0x00C8, + (wchar_t)0x00C9, (wchar_t)0x00CA, (wchar_t)0x00CB, (wchar_t)0x00CC, (wchar_t)0x00CD, + (wchar_t)0x00CE, (wchar_t)0x00CF, (wchar_t)0x00D0, (wchar_t)0x00D1, (wchar_t)0x00D2, + (wchar_t)0x00D3, (wchar_t)0x00D4, (wchar_t)0x00D5, (wchar_t)0x00D6, (wchar_t)0x00D8, + (wchar_t)0x00D9, (wchar_t)0x00DA, (wchar_t)0x00DB, (wchar_t)0x00DC, (wchar_t)0x00DD, + (wchar_t)0x00DE, (wchar_t)0x0178, (wchar_t)0x0100, (wchar_t)0x0102, (wchar_t)0x0104, + (wchar_t)0x0106, (wchar_t)0x0108, (wchar_t)0x010A, (wchar_t)0x010C, (wchar_t)0x010E, + (wchar_t)0x0110, (wchar_t)0x0112, (wchar_t)0x0114, (wchar_t)0x0116, (wchar_t)0x0118, + (wchar_t)0x011A, (wchar_t)0x011C, (wchar_t)0x011E, (wchar_t)0x0120, (wchar_t)0x0122, + (wchar_t)0x0124, (wchar_t)0x0126, (wchar_t)0x0128, (wchar_t)0x012A, (wchar_t)0x012C, + (wchar_t)0x012E, (wchar_t)0x0049, (wchar_t)0x0132, (wchar_t)0x0134, (wchar_t)0x0136, + (wchar_t)0x0139, (wchar_t)0x013B, (wchar_t)0x013D, (wchar_t)0x013F, (wchar_t)0x0141, + (wchar_t)0x0143, (wchar_t)0x0145, (wchar_t)0x0147, (wchar_t)0x014A, (wchar_t)0x014C, + (wchar_t)0x014E, (wchar_t)0x0150, (wchar_t)0x0152, (wchar_t)0x0154, (wchar_t)0x0156, + (wchar_t)0x0158, (wchar_t)0x015A, (wchar_t)0x015C, (wchar_t)0x015E, (wchar_t)0x0160, + (wchar_t)0x0162, (wchar_t)0x0164, (wchar_t)0x0166, (wchar_t)0x0168, (wchar_t)0x016A, + (wchar_t)0x016C, (wchar_t)0x016E, (wchar_t)0x0170, (wchar_t)0x0172, (wchar_t)0x0174, + (wchar_t)0x0176, (wchar_t)0x0179, (wchar_t)0x017B, (wchar_t)0x017D, (wchar_t)0x0182, + (wchar_t)0x0184, (wchar_t)0x0187, (wchar_t)0x018B, (wchar_t)0x0191, (wchar_t)0x0198, + (wchar_t)0x01A0, (wchar_t)0x01A2, (wchar_t)0x01A4, (wchar_t)0x01A7, (wchar_t)0x01AC, + (wchar_t)0x01AF, (wchar_t)0x01B3, (wchar_t)0x01B5, (wchar_t)0x01B8, (wchar_t)0x01BC, + (wchar_t)0x01C4, (wchar_t)0x01C7, (wchar_t)0x01CA, (wchar_t)0x01CD, (wchar_t)0x01CF, + (wchar_t)0x01D1, (wchar_t)0x01D3, (wchar_t)0x01D5, (wchar_t)0x01D7, (wchar_t)0x01D9, + (wchar_t)0x01DB, (wchar_t)0x01DE, (wchar_t)0x01E0, (wchar_t)0x01E2, (wchar_t)0x01E4, + (wchar_t)0x01E6, (wchar_t)0x01E8, (wchar_t)0x01EA, (wchar_t)0x01EC, (wchar_t)0x01EE, + (wchar_t)0x01F1, (wchar_t)0x01F4, (wchar_t)0x01FA, (wchar_t)0x01FC, (wchar_t)0x01FE, + (wchar_t)0x0200, (wchar_t)0x0202, (wchar_t)0x0204, (wchar_t)0x0206, (wchar_t)0x0208, + (wchar_t)0x020A, (wchar_t)0x020C, (wchar_t)0x020E, (wchar_t)0x0210, (wchar_t)0x0212, + (wchar_t)0x0214, (wchar_t)0x0216, (wchar_t)0x0181, (wchar_t)0x0186, (wchar_t)0x018A, + (wchar_t)0x018E, (wchar_t)0x018F, (wchar_t)0x0190, (wchar_t)0x0193, (wchar_t)0x0194, + (wchar_t)0x0197, (wchar_t)0x0196, (wchar_t)0x019C, (wchar_t)0x019D, (wchar_t)0x019F, + (wchar_t)0x01A9, (wchar_t)0x01AE, (wchar_t)0x01B1, (wchar_t)0x01B2, (wchar_t)0x01B7, + (wchar_t)0x0386, (wchar_t)0x0388, (wchar_t)0x0389, (wchar_t)0x038A, (wchar_t)0x0391, + (wchar_t)0x0392, (wchar_t)0x0393, (wchar_t)0x0394, (wchar_t)0x0395, (wchar_t)0x0396, + (wchar_t)0x0397, (wchar_t)0x0398, (wchar_t)0x0399, (wchar_t)0x039A, (wchar_t)0x039B, + (wchar_t)0x039C, (wchar_t)0x039D, (wchar_t)0x039E, (wchar_t)0x039F, (wchar_t)0x03A0, + (wchar_t)0x03A1, (wchar_t)0x03A3, (wchar_t)0x03A4, (wchar_t)0x03A5, (wchar_t)0x03A6, + (wchar_t)0x03A7, (wchar_t)0x03A8, (wchar_t)0x03A9, (wchar_t)0x03AA, (wchar_t)0x03AB, + (wchar_t)0x038C, (wchar_t)0x038E, (wchar_t)0x038F, (wchar_t)0x03E2, (wchar_t)0x03E4, + (wchar_t)0x03E6, (wchar_t)0x03E8, (wchar_t)0x03EA, (wchar_t)0x03EC, (wchar_t)0x03EE, + (wchar_t)0x0410, (wchar_t)0x0411, (wchar_t)0x0412, (wchar_t)0x0413, (wchar_t)0x0414, + (wchar_t)0x0415, (wchar_t)0x0416, (wchar_t)0x0417, (wchar_t)0x0418, (wchar_t)0x0419, + (wchar_t)0x041A, (wchar_t)0x041B, (wchar_t)0x041C, (wchar_t)0x041D, (wchar_t)0x041E, + (wchar_t)0x041F, (wchar_t)0x0420, (wchar_t)0x0421, (wchar_t)0x0422, (wchar_t)0x0423, + (wchar_t)0x0424, (wchar_t)0x0425, (wchar_t)0x0426, (wchar_t)0x0427, (wchar_t)0x0428, + (wchar_t)0x0429, (wchar_t)0x042A, (wchar_t)0x042B, (wchar_t)0x042C, (wchar_t)0x042D, + (wchar_t)0x042E, (wchar_t)0x042F, (wchar_t)0x0401, (wchar_t)0x0402, (wchar_t)0x0403, + (wchar_t)0x0404, (wchar_t)0x0405, (wchar_t)0x0406, (wchar_t)0x0407, (wchar_t)0x0408, + (wchar_t)0x0409, (wchar_t)0x040A, (wchar_t)0x040B, (wchar_t)0x040C, (wchar_t)0x040E, + (wchar_t)0x040F, (wchar_t)0x0460, (wchar_t)0x0462, (wchar_t)0x0464, (wchar_t)0x0466, + (wchar_t)0x0468, (wchar_t)0x046A, (wchar_t)0x046C, (wchar_t)0x046E, (wchar_t)0x0470, + (wchar_t)0x0472, (wchar_t)0x0474, (wchar_t)0x0476, (wchar_t)0x0478, (wchar_t)0x047A, + (wchar_t)0x047C, (wchar_t)0x047E, (wchar_t)0x0480, (wchar_t)0x0490, (wchar_t)0x0492, + (wchar_t)0x0494, (wchar_t)0x0496, (wchar_t)0x0498, (wchar_t)0x049A, (wchar_t)0x049C, + (wchar_t)0x049E, (wchar_t)0x04A0, (wchar_t)0x04A2, (wchar_t)0x04A4, (wchar_t)0x04A6, + (wchar_t)0x04A8, (wchar_t)0x04AA, (wchar_t)0x04AC, (wchar_t)0x04AE, (wchar_t)0x04B0, + (wchar_t)0x04B2, (wchar_t)0x04B4, (wchar_t)0x04B6, (wchar_t)0x04B8, (wchar_t)0x04BA, + (wchar_t)0x04BC, (wchar_t)0x04BE, (wchar_t)0x04C1, (wchar_t)0x04C3, (wchar_t)0x04C7, + (wchar_t)0x04CB, (wchar_t)0x04D0, (wchar_t)0x04D2, (wchar_t)0x04D4, (wchar_t)0x04D6, + (wchar_t)0x04D8, (wchar_t)0x04DA, (wchar_t)0x04DC, (wchar_t)0x04DE, (wchar_t)0x04E0, + (wchar_t)0x04E2, (wchar_t)0x04E4, (wchar_t)0x04E6, (wchar_t)0x04E8, (wchar_t)0x04EA, + (wchar_t)0x04EE, (wchar_t)0x04F0, (wchar_t)0x04F2, (wchar_t)0x04F4, (wchar_t)0x04F8, + (wchar_t)0x0531, (wchar_t)0x0532, (wchar_t)0x0533, (wchar_t)0x0534, (wchar_t)0x0535, + (wchar_t)0x0536, (wchar_t)0x0537, (wchar_t)0x0538, (wchar_t)0x0539, (wchar_t)0x053A, + (wchar_t)0x053B, (wchar_t)0x053C, (wchar_t)0x053D, (wchar_t)0x053E, (wchar_t)0x053F, + (wchar_t)0x0540, (wchar_t)0x0541, (wchar_t)0x0542, (wchar_t)0x0543, (wchar_t)0x0544, + (wchar_t)0x0545, (wchar_t)0x0546, (wchar_t)0x0547, (wchar_t)0x0548, (wchar_t)0x0549, + (wchar_t)0x054A, (wchar_t)0x054B, (wchar_t)0x054C, (wchar_t)0x054D, (wchar_t)0x054E, + (wchar_t)0x054F, (wchar_t)0x0550, (wchar_t)0x0551, (wchar_t)0x0552, (wchar_t)0x0553, + (wchar_t)0x0554, (wchar_t)0x0555, (wchar_t)0x0556, (wchar_t)0x10A0, (wchar_t)0x10A1, + (wchar_t)0x10A2, (wchar_t)0x10A3, (wchar_t)0x10A4, (wchar_t)0x10A5, (wchar_t)0x10A6, + (wchar_t)0x10A7, (wchar_t)0x10A8, (wchar_t)0x10A9, (wchar_t)0x10AA, (wchar_t)0x10AB, + (wchar_t)0x10AC, (wchar_t)0x10AD, (wchar_t)0x10AE, (wchar_t)0x10AF, (wchar_t)0x10B0, + (wchar_t)0x10B1, (wchar_t)0x10B2, (wchar_t)0x10B3, (wchar_t)0x10B4, (wchar_t)0x10B5, + (wchar_t)0x10B6, (wchar_t)0x10B7, (wchar_t)0x10B8, (wchar_t)0x10B9, (wchar_t)0x10BA, + (wchar_t)0x10BB, (wchar_t)0x10BC, (wchar_t)0x10BD, (wchar_t)0x10BE, (wchar_t)0x10BF, + (wchar_t)0x10C0, (wchar_t)0x10C1, (wchar_t)0x10C2, (wchar_t)0x10C3, (wchar_t)0x10C4, + (wchar_t)0x10C5, (wchar_t)0x1E00, (wchar_t)0x1E02, (wchar_t)0x1E04, (wchar_t)0x1E06, + (wchar_t)0x1E08, (wchar_t)0x1E0A, (wchar_t)0x1E0C, (wchar_t)0x1E0E, (wchar_t)0x1E10, + (wchar_t)0x1E12, (wchar_t)0x1E14, (wchar_t)0x1E16, (wchar_t)0x1E18, (wchar_t)0x1E1A, + (wchar_t)0x1E1C, (wchar_t)0x1E1E, (wchar_t)0x1E20, (wchar_t)0x1E22, (wchar_t)0x1E24, + (wchar_t)0x1E26, (wchar_t)0x1E28, (wchar_t)0x1E2A, (wchar_t)0x1E2C, (wchar_t)0x1E2E, + (wchar_t)0x1E30, (wchar_t)0x1E32, (wchar_t)0x1E34, (wchar_t)0x1E36, (wchar_t)0x1E38, + (wchar_t)0x1E3A, (wchar_t)0x1E3C, (wchar_t)0x1E3E, (wchar_t)0x1E40, (wchar_t)0x1E42, + (wchar_t)0x1E44, (wchar_t)0x1E46, (wchar_t)0x1E48, (wchar_t)0x1E4A, (wchar_t)0x1E4C, + (wchar_t)0x1E4E, (wchar_t)0x1E50, (wchar_t)0x1E52, (wchar_t)0x1E54, (wchar_t)0x1E56, + (wchar_t)0x1E58, (wchar_t)0x1E5A, (wchar_t)0x1E5C, (wchar_t)0x1E5E, (wchar_t)0x1E60, + (wchar_t)0x1E62, (wchar_t)0x1E64, (wchar_t)0x1E66, (wchar_t)0x1E68, (wchar_t)0x1E6A, + (wchar_t)0x1E6C, (wchar_t)0x1E6E, (wchar_t)0x1E70, (wchar_t)0x1E72, (wchar_t)0x1E74, + (wchar_t)0x1E76, (wchar_t)0x1E78, (wchar_t)0x1E7A, (wchar_t)0x1E7C, (wchar_t)0x1E7E, + (wchar_t)0x1E80, (wchar_t)0x1E82, (wchar_t)0x1E84, (wchar_t)0x1E86, (wchar_t)0x1E88, + (wchar_t)0x1E8A, (wchar_t)0x1E8C, (wchar_t)0x1E8E, (wchar_t)0x1E90, (wchar_t)0x1E92, + (wchar_t)0x1E94, (wchar_t)0x1EA0, (wchar_t)0x1EA2, (wchar_t)0x1EA4, (wchar_t)0x1EA6, + (wchar_t)0x1EA8, (wchar_t)0x1EAA, (wchar_t)0x1EAC, (wchar_t)0x1EAE, (wchar_t)0x1EB0, + (wchar_t)0x1EB2, (wchar_t)0x1EB4, (wchar_t)0x1EB6, (wchar_t)0x1EB8, (wchar_t)0x1EBA, + (wchar_t)0x1EBC, (wchar_t)0x1EBE, (wchar_t)0x1EC0, (wchar_t)0x1EC2, (wchar_t)0x1EC4, + (wchar_t)0x1EC6, (wchar_t)0x1EC8, (wchar_t)0x1ECA, (wchar_t)0x1ECC, (wchar_t)0x1ECE, + (wchar_t)0x1ED0, (wchar_t)0x1ED2, (wchar_t)0x1ED4, (wchar_t)0x1ED6, (wchar_t)0x1ED8, + (wchar_t)0x1EDA, (wchar_t)0x1EDC, (wchar_t)0x1EDE, (wchar_t)0x1EE0, (wchar_t)0x1EE2, + (wchar_t)0x1EE4, (wchar_t)0x1EE6, (wchar_t)0x1EE8, (wchar_t)0x1EEA, (wchar_t)0x1EEC, + (wchar_t)0x1EEE, (wchar_t)0x1EF0, (wchar_t)0x1EF2, (wchar_t)0x1EF4, (wchar_t)0x1EF6, + (wchar_t)0x1EF8, (wchar_t)0x1F08, (wchar_t)0x1F09, (wchar_t)0x1F0A, (wchar_t)0x1F0B, + (wchar_t)0x1F0C, (wchar_t)0x1F0D, (wchar_t)0x1F0E, (wchar_t)0x1F0F, (wchar_t)0x1F18, + (wchar_t)0x1F19, (wchar_t)0x1F1A, (wchar_t)0x1F1B, (wchar_t)0x1F1C, (wchar_t)0x1F1D, + (wchar_t)0x1F28, (wchar_t)0x1F29, (wchar_t)0x1F2A, (wchar_t)0x1F2B, (wchar_t)0x1F2C, + (wchar_t)0x1F2D, (wchar_t)0x1F2E, (wchar_t)0x1F2F, (wchar_t)0x1F38, (wchar_t)0x1F39, + (wchar_t)0x1F3A, (wchar_t)0x1F3B, (wchar_t)0x1F3C, (wchar_t)0x1F3D, (wchar_t)0x1F3E, + (wchar_t)0x1F3F, (wchar_t)0x1F48, (wchar_t)0x1F49, (wchar_t)0x1F4A, (wchar_t)0x1F4B, + (wchar_t)0x1F4C, (wchar_t)0x1F4D, (wchar_t)0x1F59, (wchar_t)0x1F5B, (wchar_t)0x1F5D, + (wchar_t)0x1F5F, (wchar_t)0x1F68, (wchar_t)0x1F69, (wchar_t)0x1F6A, (wchar_t)0x1F6B, + (wchar_t)0x1F6C, (wchar_t)0x1F6D, (wchar_t)0x1F6E, (wchar_t)0x1F6F, (wchar_t)0x1F88, + (wchar_t)0x1F89, (wchar_t)0x1F8A, (wchar_t)0x1F8B, (wchar_t)0x1F8C, (wchar_t)0x1F8D, + (wchar_t)0x1F8E, (wchar_t)0x1F8F, (wchar_t)0x1F98, (wchar_t)0x1F99, (wchar_t)0x1F9A, + (wchar_t)0x1F9B, (wchar_t)0x1F9C, (wchar_t)0x1F9D, (wchar_t)0x1F9E, (wchar_t)0x1F9F, + (wchar_t)0x1FA8, (wchar_t)0x1FA9, (wchar_t)0x1FAA, (wchar_t)0x1FAB, (wchar_t)0x1FAC, + (wchar_t)0x1FAD, (wchar_t)0x1FAE, (wchar_t)0x1FAF, (wchar_t)0x1FB8, (wchar_t)0x1FB9, + (wchar_t)0x1FD8, (wchar_t)0x1FD9, (wchar_t)0x1FE8, (wchar_t)0x1FE9, (wchar_t)0x24B6, + (wchar_t)0x24B7, (wchar_t)0x24B8, (wchar_t)0x24B9, (wchar_t)0x24BA, (wchar_t)0x24BB, + (wchar_t)0x24BC, (wchar_t)0x24BD, (wchar_t)0x24BE, (wchar_t)0x24BF, (wchar_t)0x24C0, + (wchar_t)0x24C1, (wchar_t)0x24C2, (wchar_t)0x24C3, (wchar_t)0x24C4, (wchar_t)0x24C5, + (wchar_t)0x24C6, (wchar_t)0x24C7, (wchar_t)0x24C8, (wchar_t)0x24C9, (wchar_t)0x24CA, + (wchar_t)0x24CB, (wchar_t)0x24CC, (wchar_t)0x24CD, (wchar_t)0x24CE, (wchar_t)0x24CF, + (wchar_t)0xFF21, (wchar_t)0xFF22, (wchar_t)0xFF23, (wchar_t)0xFF24, (wchar_t)0xFF25, + (wchar_t)0xFF26, (wchar_t)0xFF27, (wchar_t)0xFF28, (wchar_t)0xFF29, (wchar_t)0xFF2A, + (wchar_t)0xFF2B, (wchar_t)0xFF2C, (wchar_t)0xFF2D, (wchar_t)0xFF2E, (wchar_t)0xFF2F, + (wchar_t)0xFF30, (wchar_t)0xFF31, (wchar_t)0xFF32, (wchar_t)0xFF33, (wchar_t)0xFF34, + (wchar_t)0xFF35, (wchar_t)0xFF36, (wchar_t)0xFF37, (wchar_t)0xFF38, (wchar_t)0xFF39, + (wchar_t)0xFF3A}; + +namespace kodi +{ +namespace tools +{ + +template::value, int> = 0> +constexpr auto&& EnumToInt(T&& arg) noexcept +{ + return arg; +} +template::value, int> = 0> +constexpr auto EnumToInt(T&& arg) noexcept +{ + return static_cast(arg); +} + +//============================================================================== +/// @defgroup cpp_kodi_tools_StringUtils_Defs Definitions, structures and enumerators +/// @ingroup cpp_kodi_tools_StringUtils +/// @brief **Parts used within string util functions**\n +/// All to string functions associated data structures. +/// +/// It is divided into individual modules that correspond to the respective +/// types. +/// +/// +/// + +//============================================================================== +/// @defgroup cpp_kodi_tools_StringUtils_Defs_TIME_FORMAT enum TIME_FORMAT +/// @ingroup cpp_kodi_tools_StringUtils_Defs +/// @brief TIME_FORMAT enum/bitmask used for formatting time strings. +/// +/// Note the use of bitmasking, e.g. TIME_FORMAT_HH_MM_SS = TIME_FORMAT_HH | TIME_FORMAT_MM | TIME_FORMAT_SS +/// @sa kodi::tools::StringUtils::SecondsToTimeString +/// +/// @note For InfoLabels use the equivalent value listed (bold) on the +/// description of each enum value. +/// +/// Example: 3661 seconds => h=1, hh=01, m=1, mm=01, ss=01, hours=1, mins=61, secs=3661 +/// +///@{ +enum TIME_FORMAT +{ + /// Usually used as the fallback value if the format value is empty + TIME_FORMAT_GUESS = 0, + + /// ss - seconds only + TIME_FORMAT_SS = 1, + + /// mm - minutes only (2-digit) + TIME_FORMAT_MM = 2, + + /// mm:ss - minutes and seconds + TIME_FORMAT_MM_SS = 3, + + /// hh - hours only (2-digit) + TIME_FORMAT_HH = 4, + + /// hh:ss - hours and seconds (this is not particularly useful) + TIME_FORMAT_HH_SS = 5, + + /// hh:mm - hours and minutes + TIME_FORMAT_HH_MM = 6, + + /// hh:mm:ss - hours, minutes and seconds + TIME_FORMAT_HH_MM_SS = 7, + + /// xx - returns AM/PM for a 12-hour clock + TIME_FORMAT_XX = 8, + + /// hh:mm xx - returns hours and minutes in a 12-hour clock format (AM/PM) + TIME_FORMAT_HH_MM_XX = 14, + + /// hh:mm:ss xx - returns hours (2-digit), minutes and seconds in a 12-hour clock format (AM/PM) + TIME_FORMAT_HH_MM_SS_XX = 15, + + /// h - hours only (1-digit) + TIME_FORMAT_H = 16, + + /// hh:mm:ss - hours, minutes and seconds + TIME_FORMAT_H_MM_SS = 19, + + /// hh:mm:ss xx - returns hours (1-digit), minutes and seconds in a 12-hour clock format (AM/PM) + TIME_FORMAT_H_MM_SS_XX = 27, + + /// secs - total time in seconds + TIME_FORMAT_SECS = 32, + + /// mins - total time in minutes + TIME_FORMAT_MINS = 64, + + /// hours - total time in hours + TIME_FORMAT_HOURS = 128, + + /// m - minutes only (1-digit) + TIME_FORMAT_M = 256 +}; +///@} +//------------------------------------------------------------------------------ + +//============================================================================== +/// @defgroup cpp_kodi_tools_StringUtils class StringUtils +/// @ingroup cpp_kodi_tools +/// @brief **C++ class for processing strings**\n +/// This class brings many different functions to edit, check or search texts. +/// +/// Is intended to reduce any code work of C++ on addons and to have them faster +/// to use. +/// +/// All functions are static within the `kodi::tools::StringUtils` class. +/// +///@{ +class StringUtils +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_tools_StringUtils_Defs + /// @brief Defines a static empty `std::string`. + /// + static const std::string Empty; + //---------------------------------------------------------------------------- + + //---------------------------------------------------------------------------- + /// @defgroup cpp_kodi_tools_StringUtils_FormatControl String format + /// @ingroup cpp_kodi_tools_StringUtils + /// @brief **Formatting functions**\n + /// Used to output the given values in newly formatted text using functions. + /// + /*!@{*/ + + //============================================================================ + /// @brief Returns the C++ string pointed by given format. If format includes + /// format specifiers (subsequences beginning with %), the additional arguments + /// following format are formatted and inserted in the resulting string replacing + /// their respective specifiers. + /// + /// After the format parameter, the function expects at least as many additional + /// arguments as specified by format. + /// + /// @param[in] fmt The format of the text to process for output. + /// C string that contains the text to be written to the stream. + /// It can optionally contain embedded format specifiers that are + /// replaced by the values specified in subsequent additional + /// arguments and formatted as requested. + /// | specifier | Output | Example + /// |------------|----------------------------------------------------|------------ + /// | d or i | Signed decimal integer | 392 + /// | u | Unsigned decimal integer | 7235 + /// | o | Unsigned octal | 610 + /// | x | Unsigned hexadecimal integer | 7fa + /// | X | Unsigned hexadecimal integer (uppercase) | 7FA + /// | f | Decimal floating point, lowercase | 392.65 + /// | F | Decimal floating point, uppercase | 392.65 + /// | e | Scientific notation (mantissa/exponent), lowercase | 3.9265e+2 + /// | E | Scientific notation (mantissa/exponent), uppercase | 3.9265E+2 + /// | g | Use the shortest representation: %e or %f | 392.65 + /// | G | Use the shortest representation: %E or %F | 392.65 + /// | a | Hexadecimal floating point, lowercase | -0xc.90fep-2 + /// | A | Hexadecimal floating point, uppercase | -0XC.90FEP-2 + /// | c | Character | a + /// | s | String of characters | sample + /// | p | Pointer address | b8000000 + /// | % | A % followed by another % character will write a single % to the stream. | % + /// The length sub-specifier modifies the length of the data type. This is a chart + /// showing the types used to interpret the corresponding arguments with and without + /// length specifier (if a different type is used, the proper type promotion or + /// conversion is performed, if allowed): + /// | length| d i | u o x X | f F e E g G a A | c | s | p | n | + /// |-------|---------------|-----------------------|-----------------|-------|---------|---------|-----------------| + /// | (none)| int | unsigned int | double | int | char* | void* | int* | + /// | hh | signed char | unsigned char | | | | | signed char* | + /// | h | short int | unsigned short int | | | | | short int* | + /// | l | long int | unsigned long int | | wint_t| wchar_t*| | long int* | + /// | ll | long long int | unsigned long long int| | | | | long long int* | + /// | j | intmax_t | uintmax_t | | | | | intmax_t* | + /// | z | size_t | size_t | | | | | size_t* | + /// | t | ptrdiff_t | ptrdiff_t | | | | | ptrdiff_t* | + /// | L | | | long double | | | | | + /// Note: that the c specifier takes an int (or wint_t) as argument, but performs the proper conversion to a char value + /// (or a wchar_t) before formatting it for output. + /// @param[in] ... (additional arguments)\n + /// Depending on the format string, the function may expect a + /// sequence of additional arguments, each containing a value + /// to be used to replace a format specifier in the format + /// string (or a pointer to a storage location, for n).\n + /// There should be at least as many of these arguments as the + /// number of values specified in the format specifiers. + /// Additional arguments are ignored by the function. + /// @return Formatted string + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string str = kodi::tools::StringUtils::Format("Hello %s %i", "World", 2020); + /// ~~~~~~~~~~~~~ + /// + inline static std::string Format(const char* fmt, ...) + { + va_list args; + va_start(args, fmt); + std::string str = FormatV(fmt, args); + va_end(args); + + return str; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Returns the C++ wide string pointed by given format. + /// + /// @param[in] fmt The format of the text to process for output + /// (see @ref Format(const char* fmt, ...) for details). + /// @param[in] ... (additional arguments)\n + /// Depending on the format string, the function may expect a + /// sequence of additional arguments, each containing a value + /// to be used to replace a format specifier in the format + /// string (or a pointer to a storage location, for n).\n + /// There should be at least as many of these arguments as the + /// number of values specified in the format specifiers. + /// Additional arguments are ignored by the function. + /// @return Formatted string + /// + inline static std::wstring Format(const wchar_t* fmt, ...) + { + va_list args; + va_start(args, fmt); + std::wstring str = FormatV(fmt, args); + va_end(args); + + return str; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Returns the C++ string pointed by given format list. + /// + /// @param[in] fmt The format of the text to process for output + /// (see @ref Format(const char* fmt, ...) for details). + /// @param[in] args A value identifying a variable arguments list initialized + /// with `va_start`. + /// @return Formatted string + /// + inline static std::string FormatV(PRINTF_FORMAT_STRING const char* fmt, va_list args) + { + if (!fmt || !fmt[0]) + return ""; + + int size = FORMAT_BLOCK_SIZE; + va_list argCopy; + + while (true) + { + char* cstr = reinterpret_cast(malloc(sizeof(char) * size)); + if (!cstr) + return ""; + + va_copy(argCopy, args); + int nActual = vsnprintf(cstr, size, fmt, argCopy); + va_end(argCopy); + + if (nActual > -1 && nActual < size) // We got a valid result + { + std::string str(cstr, nActual); + free(cstr); + return str; + } + free(cstr); +#ifndef TARGET_WINDOWS + if (nActual > -1) // Exactly what we will need (glibc 2.1) + size = nActual + 1; + else // Let's try to double the size (glibc 2.0) + size *= 2; +#else // TARGET_WINDOWS + va_copy(argCopy, args); + size = _vscprintf(fmt, argCopy); + va_end(argCopy); + if (size < 0) + return ""; + else + size++; // increment for null-termination +#endif // TARGET_WINDOWS + } + + return ""; // unreachable + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Returns the C++ wide string pointed by given format list. + /// + /// @param[in] fmt The format of the text to process for output + /// (see @ref Format(const char* fmt, ...) for details). + /// @param[in] args A value identifying a variable arguments list initialized + /// with `va_start`. + /// @return Formatted string + /// + inline static std::wstring FormatV(PRINTF_FORMAT_STRING const wchar_t* fmt, va_list args) + { + if (!fmt || !fmt[0]) + return L""; + + int size = FORMAT_BLOCK_SIZE; + va_list argCopy; + + while (true) + { + wchar_t* cstr = reinterpret_cast(malloc(sizeof(wchar_t) * size)); + if (!cstr) + return L""; + + va_copy(argCopy, args); + int nActual = vswprintf(cstr, size, fmt, argCopy); + va_end(argCopy); + + if (nActual > -1 && nActual < size) // We got a valid result + { + std::wstring str(cstr, nActual); + free(cstr); + return str; + } + free(cstr); + +#ifndef TARGET_WINDOWS + if (nActual > -1) // Exactly what we will need (glibc 2.1) + size = nActual + 1; + else // Let's try to double the size (glibc 2.0) + size *= 2; +#else // TARGET_WINDOWS + va_copy(argCopy, args); + size = _vscwprintf(fmt, argCopy); + va_end(argCopy); + if (size < 0) + return L""; + else + size++; // increment for null-termination +#endif // TARGET_WINDOWS + } + + return L""; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Returns bytes in a human readable format using the smallest unit + /// that will fit `bytes` in at most three digits. The number of decimals are + /// adjusted with significance such that 'small' numbers will have more + /// decimals than larger ones. + /// + /// For example: 1024 bytes will be formatted as "1.00kB", 10240 bytes as + /// "10.0kB" and 102400 bytes as "100kB". See TestStringUtils for more + /// examples. + /// + /// Supported file sizes: + /// | Value | Short | Metric + /// |------------|-------|----------- + /// | 1 | B | byte + /// | 1024¹ | kB | kilobyte + /// | 1024² | MB | megabyte + /// | 1024³ | GB | gigabyte + /// | 1024 exp 4 | TB | terabyte + /// | 1024 exp 5 | PB | petabyte + /// | 1024 exp 6 | EB | exabyte + /// | 1024 exp 7 | ZB | zettabyte + /// | 1024 exp 8 | YB | yottabyte + /// + /// @param[in] bytes Bytes amount to return as human readable string + /// @return Size as string + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// EXPECT_STREQ("0B", kodi::tools::StringUtils::FormatFileSize(0).c_str()); + /// + /// EXPECT_STREQ("999B", kodi::tools::StringUtils::FormatFileSize(999).c_str()); + /// EXPECT_STREQ("0.98kB", kodi::tools::StringUtils::FormatFileSize(1000).c_str()); + /// + /// EXPECT_STREQ("1.00kB", kodi::tools::StringUtils::FormatFileSize(1024).c_str()); + /// EXPECT_STREQ("9.99kB", kodi::tools::StringUtils::FormatFileSize(10229).c_str()); + /// + /// EXPECT_STREQ("10.1kB", kodi::tools::StringUtils::FormatFileSize(10387).c_str()); + /// EXPECT_STREQ("99.9kB", kodi::tools::StringUtils::FormatFileSize(102297).c_str()); + /// + /// EXPECT_STREQ("100kB", kodi::tools::StringUtils::FormatFileSize(102400).c_str()); + /// EXPECT_STREQ("999kB", kodi::tools::StringUtils::FormatFileSize(1023431).c_str()); + /// + /// EXPECT_STREQ("0.98MB", kodi::tools::StringUtils::FormatFileSize(1023897).c_str()); + /// EXPECT_STREQ("0.98MB", kodi::tools::StringUtils::FormatFileSize(1024000).c_str()); + /// + /// EXPECT_STREQ("5.30EB", kodi::tools::StringUtils::FormatFileSize(6115888293969133568).c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static std::string FormatFileSize(uint64_t bytes) + { + const std::array units{{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}}; + if (bytes < 1000) + return Format("%" PRIu64 "B", bytes); + + size_t i = 0; + double value = static_cast(bytes); + while (i + 1 < units.size() && value >= 999.5) + { + ++i; + value /= 1024.0; + } + unsigned int decimals = value < 9.995 ? 2 : (value < 99.95 ? 1 : 0); + auto frmt = "%." + Format("%u", decimals) + "f%s"; + return Format(frmt.c_str(), value, units[i].c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Convert the string of binary chars to the actual string. + /// + /// Convert the string representation of binary chars to the actual string. + /// For example `\1\2\3` is converted to a string with binary char + /// `\1`, `\2` and `\3` + /// + /// @param[in] in String to convert + /// @return Converted string + /// + inline static std::string BinaryStringToString(const std::string& in) + { + std::string out; + out.reserve(in.size() / 2); + for (const char *cur = in.c_str(), *end = cur + in.size(); cur != end; ++cur) + { + if (*cur == '\\') + { + ++cur; + if (cur == end) + { + break; + } + if (isdigit(*cur)) + { + char* end; + unsigned long num = strtol(cur, &end, 10); + cur = end - 1; + out.push_back(static_cast(num)); + continue; + } + } + out.push_back(*cur); + } + return out; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Convert each character in the string to its hexadecimal + /// representation and return the concatenated result + /// + /// Example: "abc\n" -> "6162630a" + /// + /// @param[in] in String to convert + /// @return Converted string + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// EXPECT_STREQ("", kodi::tools::StringUtils::ToHexadecimal("").c_str()); + /// EXPECT_STREQ("616263", kodi::tools::StringUtils::ToHexadecimal("abc").c_str()); + /// std::string a{"a\0b\n", 4}; + /// EXPECT_STREQ("6100620a", kodi::tools::StringUtils::ToHexadecimal(a).c_str()); + /// std::string nul{"\0", 1}; + /// EXPECT_STREQ("00", kodi::tools::StringUtils::ToHexadecimal(nul).c_str()); + /// std::string ff{"\xFF", 1}; + /// EXPECT_STREQ("ff", kodi::tools::StringUtils::ToHexadecimal(ff).c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static std::string ToHexadecimal(const std::string& in) + { + std::ostringstream ss; + ss << std::hex; + for (unsigned char ch : in) + { + ss << std::setw(2) << std::setfill('0') << static_cast(ch); + } + return ss.str(); + } + //---------------------------------------------------------------------------- + + /*!@}*/ + + //---------------------------------------------------------------------------- + /// @defgroup cpp_kodi_tools_StringUtils_EditControl String edit + /// @ingroup cpp_kodi_tools_StringUtils + /// @brief **Edits given texts**\n + /// This is used to revise the respective strings and to get them in the desired format. + /// + /*!@{*/ + + //============================================================================ + /// @brief Convert a string to uppercase. + /// + /// @param[in,out] str String to convert + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string refstr = "TEST"; + /// + /// std::string varstr = "TeSt"; + /// kodi::tools::StringUtils::ToUpper(varstr); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static void ToUpper(std::string& str) + { + std::transform(str.begin(), str.end(), str.begin(), ::toupper); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Convert a 16bit wide string to uppercase. + /// + /// @param[in,out] str String to convert + /// + inline static void ToUpper(std::wstring& str) + { + transform(str.begin(), str.end(), str.begin(), toupperUnicode); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Convert a string to lowercase. + /// + /// @param[in,out] str String to convert + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string refstr = "test"; + /// + /// std::string varstr = "TeSt"; + /// kodi::tools::StringUtils::ToLower(varstr); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static void ToLower(std::string& str) + { + transform(str.begin(), str.end(), str.begin(), ::tolower); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Convert a 16bit wide string to lowercase. + /// + /// @param[in,out] str String to convert + /// + inline static void ToLower(std::wstring& str) + { + transform(str.begin(), str.end(), str.begin(), tolowerUnicode); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Combine all numerical digits and give it as integer value. + /// + /// @param[in,out] str String to check for digits + /// @return All numerical digits fit together as integer value + /// + inline static int ReturnDigits(const std::string& str) + { + std::stringstream ss; + for (const auto& character : str) + { + if (isdigit(character)) + ss << character; + } + return atoi(ss.str().c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Returns a string from start with givent count. + /// + /// @param[in] str String to use + /// @param[in] count Amount of characters to go from left + /// @return The left part string in amount of given count or complete if it + /// was higher. + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string refstr, varstr; + /// std::string origstr = "test"; + /// + /// refstr = ""; + /// varstr = kodi::tools::StringUtils::Left(origstr, 0); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// + /// refstr = "te"; + /// varstr = kodi::tools::StringUtils::Left(origstr, 2); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// + /// refstr = "test"; + /// varstr = kodi::tools::StringUtils::Left(origstr, 10); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static std::string Left(const std::string& str, size_t count) + { + count = std::max((size_t)0, std::min(count, str.size())); + return str.substr(0, count); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Get substring from mid of given string. + /// + /// @param[in] str String to get substring from + /// @param[in] first Position from where to start + /// @param[in] count [opt] length of position to get after start, default is + /// complete to end + /// @return The substring taken from middle of input string + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string refstr, varstr; + /// std::string origstr = "test"; + /// + /// refstr = ""; + /// varstr = kodi::tools::StringUtils::Mid(origstr, 0, 0); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// + /// refstr = "te"; + /// varstr = kodi::tools::StringUtils::Mid(origstr, 0, 2); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// + /// refstr = "test"; + /// varstr = kodi::tools::StringUtils::Mid(origstr, 0, 10); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// + /// refstr = "st"; + /// varstr = kodi::tools::StringUtils::Mid(origstr, 2); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// + /// refstr = "st"; + /// varstr = kodi::tools::StringUtils::Mid(origstr, 2, 2); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// + /// refstr = "es"; + /// varstr = kodi::tools::StringUtils::Mid(origstr, 1, 2); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static std::string Mid(const std::string& str, + size_t first, + size_t count = std::string::npos) + { + if (first + count > str.size()) + count = str.size() - first; + + if (first > str.size()) + return std::string(); + + assert(first + count <= str.size()); + + return str.substr(first, count); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Returns a string from end with givent count. + /// + /// @param[in] str String to use + /// @param[in] count Amount of characters to go from right + /// @return The right part string in amount of given count or complete if it + /// was higher. + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string refstr, varstr; + /// std::string origstr = "test"; + /// + /// refstr = ""; + /// varstr = kodi::tools::StringUtils::Right(origstr, 0); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// + /// refstr = "st"; + /// varstr = kodi::tools::StringUtils::Right(origstr, 2); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// + /// refstr = "test"; + /// varstr = kodi::tools::StringUtils::Right(origstr, 10); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static std::string Right(const std::string& str, size_t count) + { + count = std::max((size_t)0, std::min(count, str.size())); + return str.substr(str.size() - count); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Trim a string with remove of not wanted spaces at begin and end + /// of string. + /// + /// @param[in,out] str String to trim, becomes also changed and given on + /// return + /// @return The changed string + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string refstr = "test test"; + /// + /// std::string varstr = " test test "; + /// kodi::tools::StringUtils::Trim(varstr); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static std::string& Trim(std::string& str) + { + TrimLeft(str); + return TrimRight(str); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Trim a string with remove of not wanted characters at begin and end + /// of string. + /// + /// @param[in,out] str String to trim, becomes also changed and given on + /// return + /// @param[in] chars Characters to use for trim + /// @return The changed string + /// + inline static std::string& Trim(std::string& str, const char* const chars) + { + TrimLeft(str, chars); + return TrimRight(str, chars); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Trim a string with remove of not wanted spaces at begin of string. + /// + /// @param[in,out] str String to trim, becomes also changed and given on + /// return + /// @return The changed string + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string refstr = "test test "; + /// + /// std::string varstr = " test test "; + /// kodi::tools::StringUtils::TrimLeft(varstr); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static std::string& TrimLeft(std::string& str) + { + str.erase(str.begin(), + std::find_if(str.begin(), str.end(), [](char s) { return IsSpace(s) == 0; })); + return str; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Trim a string with remove of not wanted characters at begin of + /// string. + /// + /// @param[in,out] str String to trim, becomes also changed and given on + /// return + /// @param[in] chars Characters to use for trim + /// @return The changed string + /// + inline static std::string& TrimLeft(std::string& str, const char* const chars) + { + size_t nidx = str.find_first_not_of(chars); + str.erase(0, nidx); + return str; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Trim a string with remove of not wanted spaces at end of string. + /// + /// @param[in,out] str String to trim, becomes also changed and given on + /// return + /// @return The changed string + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string refstr = " test test"; + /// + /// std::string varstr = " test test "; + /// kodi::tools::StringUtils::TrimRight(varstr); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static std::string& TrimRight(std::string& str) + { + str.erase(std::find_if(str.rbegin(), str.rend(), [](char s) { return IsSpace(s) == 0; }).base(), + str.end()); + return str; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Trim a string with remove of not wanted characters at end of + /// string. + /// + /// @param[in,out] str String to trim, becomes also changed and given on + /// return + /// @param[in] chars Characters to use for trim + /// @return The changed string + /// + inline static std::string& TrimRight(std::string& str, const char* const chars) + { + size_t nidx = str.find_last_not_of(chars); + str.erase(str.npos == nidx ? 0 : ++nidx); + return str; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Cleanup string by remove of duplicates of spaces and tabs. + /// + /// @param[in,out] str String to remove duplicates, becomes also changed and + /// given further on return + /// @return The changed string + /// + inline static std::string& RemoveDuplicatedSpacesAndTabs(std::string& str) + { + std::string::iterator it = str.begin(); + bool onSpace = false; + while (it != str.end()) + { + if (*it == '\t') + *it = ' '; + + if (*it == ' ') + { + if (onSpace) + { + it = str.erase(it); + continue; + } + else + onSpace = true; + } + else + onSpace = false; + + ++it; + } + return str; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Replace a character with another inside text string. + /// + /// @param[in] str String to replace within + /// @param[in] oldChar Character to search for replacement + /// @param[in] newChar New character to use for replacement + /// @return Amount of replaced characters + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string refstr = "text text"; + /// + /// std::string varstr = "test test"; + /// EXPECT_EQ(kodi::tools::StringUtils::Replace(varstr, 's', 'x'), 2); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// + /// EXPECT_EQ(kodi::tools::StringUtils::Replace(varstr, 's', 'x'), 0); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static int Replace(std::string& str, char oldChar, char newChar) + { + int replacedChars = 0; + for (std::string::iterator it = str.begin(); it != str.end(); ++it) + { + if (*it == oldChar) + { + *it = newChar; + replacedChars++; + } + } + + return replacedChars; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Replace a complete text with another inside text string. + /// + /// @param[in] str String to replace within + /// @param[in] oldStr String to search for replacement + /// @param[in] newStr New string to use for replacement + /// @return Amount of replaced text fields + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string refstr = "text text"; + /// + /// std::string varstr = "test test"; + /// EXPECT_EQ(kodi::tools::StringUtils::Replace(varstr, "s", "x"), 2); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// + /// EXPECT_EQ(kodi::tools::StringUtils::Replace(varstr, "s", "x"), 0); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static int Replace(std::string& str, const std::string& oldStr, const std::string& newStr) + { + if (oldStr.empty()) + return 0; + + int replacedChars = 0; + size_t index = 0; + + while (index < str.size() && (index = str.find(oldStr, index)) != std::string::npos) + { + str.replace(index, oldStr.size(), newStr); + index += newStr.size(); + replacedChars++; + } + + return replacedChars; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Replace a complete text with another inside 16bit wide text string. + /// + /// @param[in] str String to replace within + /// @param[in] oldStr String to search for replacement + /// @param[in] newStr New string to use for replacement + /// @return Amount of replaced text fields + /// + inline static int Replace(std::wstring& str, + const std::wstring& oldStr, + const std::wstring& newStr) + { + if (oldStr.empty()) + return 0; + + int replacedChars = 0; + size_t index = 0; + + while (index < str.size() && (index = str.find(oldStr, index)) != std::string::npos) + { + str.replace(index, oldStr.size(), newStr); + index += newStr.size(); + replacedChars++; + } + + return replacedChars; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Transform characters to create a safe URL. + /// + /// @param[in] str The string to transform + /// @return The transformed string, with unsafe characters replaced by "_" + /// + /// Safe URLs are composed of the unreserved characters defined in + /// RFC 3986 section 2.3: + /// + /// ALPHA / DIGIT / "-" / "." / "_" / "~" + /// + /// Characters outside of this set will be replaced by "_". + /// + inline static std::string MakeSafeUrl(const std::string& str) + { + std::string safeUrl; + + safeUrl.reserve(str.size()); + + std::transform(str.begin(), str.end(), std::back_inserter(safeUrl), [](char c) { + if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '-' || + c == '.' || c == '_' || c == '~') + { + return c; + } + return '_'; + }); + + return safeUrl; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Transform characters to create a safe, printable string. + /// + /// @param[in] str The string to transform + /// @return The transformed string, with unsafe characters replaced by " " + /// + /// Unsafe characters are defined as the non-printable ASCII characters + /// (character code 0-31). + /// + inline static std::string MakeSafeString(const std::string& str) + { + std::string safeString; + + safeString.reserve(str.size()); + + std::transform(str.begin(), str.end(), std::back_inserter(safeString), [](char c) { + if (c < 0x20) + return ' '; + + return c; + }); + + return safeString; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Removes a MAC address from a given string. + /// + /// @param[in] str The string containing a MAC address + /// @return The string without the MAC address (for chaining) + /// + inline static std::string RemoveMACAddress(const std::string& str) + { + std::regex re(R"mac([\(\[]?([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})[\)\]]?)mac"); + return std::regex_replace(str, re, "", std::regex_constants::format_default); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Remove carriage return and line feeds on string ends. + /// + /// @param[in,out] str String where CR and LF becomes removed on end + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string refstr, varstr; + /// + /// refstr = "test\r\nstring\nblah blah"; + /// varstr = "test\r\nstring\nblah blah\n"; + /// kodi::tools::StringUtils::RemoveCRLF(varstr); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static void RemoveCRLF(std::string& strLine) { StringUtils::TrimRight(strLine, "\n\r"); } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Convert a word to a digit numerical string + /// + /// @param[in] str String to convert + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// std::string ref, var; + /// + /// ref = "8378 787464"; + /// var = "test string"; + /// kodi::tools::StringUtils::WordToDigits(var); + /// EXPECT_STREQ(ref.c_str(), var.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static void WordToDigits(std::string& word) + { + static const char word_to_letter[] = "22233344455566677778889999"; + StringUtils::ToLower(word); + for (unsigned int i = 0; i < word.size(); ++i) + { // NB: This assumes ascii, which probably needs extending at some point. + char letter = word[i]; + if ((letter >= 'a' && letter <= 'z')) // assume contiguous letter range + { + word[i] = word_to_letter[letter - 'a']; + } + else if (letter < '0' || letter > '9') // We want to keep 0-9! + { + word[i] = ' '; // replace everything else with a space + } + } + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Escapes the given string to be able to be used as a parameter. + /// + /// Escapes backslashes and double-quotes with an additional backslash and + /// adds double-quotes around the whole string. + /// + /// @param[in] param String to escape/paramify + /// @return Escaped/Paramified string + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// const char *input = "some, very \\ odd \"string\""; + /// const char *ref = "\"some, very \\\\ odd \\\"string\\\"\""; + /// + /// std::string result = kodi::tools::StringUtils::Paramify(input); + /// EXPECT_STREQ(ref, result.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static std::string Paramify(const std::string& param) + { + std::string result = param; + // escape backspaces + StringUtils::Replace(result, "\\", "\\\\"); + // escape double quotes + StringUtils::Replace(result, "\"", "\\\""); + + // add double quotes around the whole string + return "\"" + result + "\""; + } + //---------------------------------------------------------------------------- + + /*!@}*/ + + //---------------------------------------------------------------------------- + /// @defgroup cpp_kodi_tools_StringUtils_CompareControl String compare + /// @ingroup cpp_kodi_tools_StringUtils + /// @brief **Check strings for the desired state**\n + /// With this, texts can be checked to see that they correspond to a required + /// format. + /// + /*!@{*/ + + //============================================================================ + /// @brief Compare two strings with ignore of lower-/uppercase. + /// + /// @param[in] str1 C++ string to compare + /// @param[in] str2 C++ string to compare + /// @return True if the strings are equal, false otherwise + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string refstr = "TeSt"; + /// + /// EXPECT_TRUE(kodi::tools::StringUtils::EqualsNoCase(refstr, "TeSt")); + /// EXPECT_TRUE(kodi::tools::StringUtils::EqualsNoCase(refstr, "tEsT")); + /// ~~~~~~~~~~~~~ + /// + inline static bool EqualsNoCase(const std::string& str1, const std::string& str2) + { + // before we do the char-by-char comparison, first compare sizes of both strings. + // This led to a 33% improvement in benchmarking on average. (size() just returns a member of std::string) + if (str1.size() != str2.size()) + return false; + return EqualsNoCase(str1.c_str(), str2.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Compare two strings with ignore of lower-/uppercase. + /// + /// @param[in] str1 C++ string to compare + /// @param[in] s2 C string to compare + /// @return True if the strings are equal, false otherwise + /// + inline static bool EqualsNoCase(const std::string& str1, const char* s2) + { + return EqualsNoCase(str1.c_str(), s2); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Compare two strings with ignore of lower-/uppercase. + /// + /// @param[in] s1 C string to compare + /// @param[in] s2 C string to compare + /// @return True if the strings are equal, false otherwise + /// + inline static bool EqualsNoCase(const char* s1, const char* s2) + { + char c2; // we need only one char outside the loop + do + { + const char c1 = *s1++; // const local variable should help compiler to optimize + c2 = *s2++; + // This includes the possibility that one of the characters is the null-terminator, + // which implies a string mismatch. + if (c1 != c2 && ::tolower(c1) != ::tolower(c2)) + return false; + } while (c2 != '\0'); // At this point, we know c1 == c2, so there's no need to test them both. + return true; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Compare two strings with ignore of lower-/uppercase with given + /// size. + /// + /// Equal to @ref EqualsNoCase only that size can defined and on return the + /// difference between compared character becomes given. + /// + /// @param[in] str1 C++ string to compare + /// @param[in] str2 C++ string to compare + /// @param[in] n [opt] Length to check, 0 as default to make complete + /// @return 0 if equal, otherwise difference of failed character in string to + /// other ("a" - "b" = -1) + /// + inline static int CompareNoCase(const std::string& str1, const std::string& str2, size_t n = 0) + { + return CompareNoCase(str1.c_str(), str2.c_str(), n); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Compare two strings with ignore of lower-/uppercase with given + /// size. + /// + /// Equal to @ref EqualsNoCase only that size can defined and on return the + /// difference between compared character becomes given. + /// + /// @param[in] s1 C string to compare + /// @param[in] s2 C string to compare + /// @param[in] n [opt] Length to check, 0 as default to make complete + /// @return 0 if equal, otherwise difference of failed character in string to + /// other ("a" - "b" = -1) + /// + inline static int CompareNoCase(const char* s1, const char* s2, size_t n = 0) + { + char c2; // we need only one char outside the loop + size_t index = 0; + do + { + const char c1 = *s1++; // const local variable should help compiler to optimize + c2 = *s2++; + index++; + // This includes the possibility that one of the characters is the null-terminator, + // which implies a string mismatch. + if (c1 != c2 && ::tolower(c1) != ::tolower(c2)) + return ::tolower(c1) - ::tolower(c2); + } while (c2 != '\0' && + index != n); // At this point, we know c1 == c2, so there's no need to test them both. + return 0; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a string for the begin of another string. + /// + /// @param[in] str1 C++ string to be checked + /// @param[in] str2 C++ string with which text defined in str1 is checked at + /// the beginning + /// @return True if string started with asked text, false otherwise + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// bool ret; + /// std::string refstr = "test"; + /// + /// ret = kodi::tools::StringUtils::StartsWith(refstr, "te"); + /// fprintf(stderr, "Excpect true for here and is '%s'\n", ret ? "true" : "false"); + /// + /// ret = kodi::tools::StringUtils::StartsWith(refstr, "abc"); + /// fprintf(stderr, "Excpect false for here and is '%s'\n", ret ? "true" : "false"); + /// ~~~~~~~~~~~~~ + /// + inline static bool StartsWith(const std::string& str1, const std::string& str2) + { + return str1.compare(0, str2.size(), str2) == 0; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a string for the begin of another string. + /// + /// @param[in] str1 C++ string to be checked + /// @param[in] s2 C string with which text defined in str1 is checked at + /// the beginning + /// @return True if string started with asked text, false otherwise + /// + inline static bool StartsWith(const std::string& str1, const char* s2) + { + return StartsWith(str1.c_str(), s2); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a string for the begin of another string. + /// + /// @param[in] s1 C string to be checked + /// @param[in] s2 C string with which text defined in str1 is checked at + /// the beginning + /// @return True if string started with asked text, false otherwise + /// + inline static bool StartsWith(const char* s1, const char* s2) + { + while (*s2 != '\0') + { + if (*s1 != *s2) + return false; + s1++; + s2++; + } + return true; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a string for the begin of another string by ignore of + /// upper-/lowercase. + /// + /// @param[in] str1 C++ string to be checked + /// @param[in] str2 C++ string with which text defined in str1 is checked at + /// the beginning + /// @return True if string started with asked text, false otherwise + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// bool ret; + /// std::string refstr = "test"; + /// + /// ret = kodi::tools::StringUtils::StartsWithNoCase(refstr, "te"); + /// fprintf(stderr, "Excpect true for here and is '%s'\n", ret ? "true" : "false"); + /// + /// ret = kodi::tools::StringUtils::StartsWithNoCase(refstr, "TEs"); + /// fprintf(stderr, "Excpect true for here and is '%s'\n", ret ? "true" : "false"); + /// + /// ret = kodi::tools::StringUtils::StartsWithNoCase(refstr, "abc"); + /// fprintf(stderr, "Excpect false for here and is '%s'\n", ret ? "true" : "false"); + /// ~~~~~~~~~~~~~ + /// + inline static bool StartsWithNoCase(const std::string& str1, const std::string& str2) + { + return StartsWithNoCase(str1.c_str(), str2.c_str()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a string for the begin of another string by ignore of + /// upper-/lowercase. + /// + /// @param[in] str1 C++ string to be checked + /// @param[in] s2 C string with which text defined in str1 is checked at + /// the beginning + /// @return True if string started with asked text, false otherwise + /// + inline static bool StartsWithNoCase(const std::string& str1, const char* s2) + { + return StartsWithNoCase(str1.c_str(), s2); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a string for the begin of another string by ignore of + /// upper-/lowercase. + /// + /// @param[in] s1 C string to be checked + /// @param[in] s2 C string with which text defined in str1 is checked at + /// the beginning + /// @return True if string started with asked text, false otherwise + /// + inline static bool StartsWithNoCase(const char* s1, const char* s2) + { + while (*s2 != '\0') + { + if (::tolower(*s1) != ::tolower(*s2)) + return false; + s1++; + s2++; + } + return true; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a string for the ending of another string. + /// + /// @param[in] str1 C++ string to be checked + /// @param[in] str2 C++ string with which text defined in str1 is checked at + /// the ending + /// @return True if string ended with asked text, false otherwise + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// bool ret; + /// std::string refstr = "test"; + /// + /// ret = kodi::tools::StringUtils::EndsWith(refstr, "st"); + /// fprintf(stderr, "Excpect true for here and is '%s'\n", ret ? "true" : "false"); + /// + /// ret = kodi::tools::StringUtils::EndsWith(refstr, "abc"); + /// fprintf(stderr, "Excpect false for here and is '%s'\n", ret ? "true" : "false"); + /// ~~~~~~~~~~~~~ + /// + inline static bool EndsWith(const std::string& str1, const std::string& str2) + { + if (str1.size() < str2.size()) + return false; + return str1.compare(str1.size() - str2.size(), str2.size(), str2) == 0; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a string for the ending of another string. + /// + /// @param[in] str1 C++ string to be checked + /// @param[in] s2 C string with which text defined in str1 is checked at + /// the ending + /// @return True if string ended with asked text, false otherwise + /// + inline static bool EndsWith(const std::string& str1, const char* s2) + { + size_t len2 = strlen(s2); + if (str1.size() < len2) + return false; + return str1.compare(str1.size() - len2, len2, s2) == 0; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a string for the ending of another string by ignore of + /// upper-/lowercase. + /// + /// @param[in] str1 C++ string to be checked + /// @param[in] str2 C++ string with which text defined in str1 is checked at + /// the ending + /// @return True if string ended with asked text, false otherwise + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// bool ret; + /// std::string refstr = "test"; + /// + /// ret = kodi::tools::StringUtils::EndsWithNoCase(refstr, "ST"); + /// fprintf(stderr, "Excpect true for here and is '%s'\n", ret ? "true" : "false"); + /// + /// ret = kodi::tools::StringUtils::EndsWithNoCase(refstr, "ABC"); + /// fprintf(stderr, "Excpect false for here and is '%s'\n", ret ? "true" : "false"); + /// ~~~~~~~~~~~~~ + /// + inline static bool EndsWithNoCase(const std::string& str1, const std::string& str2) + { + if (str1.size() < str2.size()) + return false; + const char* s1 = str1.c_str() + str1.size() - str2.size(); + const char* s2 = str2.c_str(); + while (*s2 != '\0') + { + if (::tolower(*s1) != ::tolower(*s2)) + return false; + s1++; + s2++; + } + return true; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a string for the ending of another string by ignore of + /// upper-/lowercase. + /// + /// @param[in] str1 C++ string to be checked + /// @param[in] s2 C string with which text defined in str1 is checked at + /// the ending + /// @return True if string ended with asked text, false otherwise + /// + inline static bool EndsWithNoCase(const std::string& str1, const char* s2) + { + size_t len2 = strlen(s2); + if (str1.size() < len2) + return false; + const char* s1 = str1.c_str() + str1.size() - len2; + while (*s2 != '\0') + { + if (::tolower(*s1) != ::tolower(*s2)) + return false; + s1++; + s2++; + } + return true; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Compare two strings by his calculated alpha numeric values. + /// + /// @param[in] left Left string to compare with right + /// @param[in] right Right string to compare with left + /// @return Return about compare + /// - 0 if left and right the same + /// - -1 if right is longer + /// - 1 if left is longer + /// - < 0 if less equal + /// - > 0 if more equal + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// int64_t ref, var; + /// + /// ref = 0; + /// var = kodi::tools::StringUtils::AlphaNumericCompare(L"123abc", L"abc123"); + /// EXPECT_LT(var, ref); + /// ~~~~~~~~~~~~~ + /// + inline static int64_t AlphaNumericCompare(const wchar_t* left, const wchar_t* right) + { + const wchar_t* l = left; + const wchar_t* r = right; + const wchar_t *ld, *rd; + wchar_t lc, rc; + int64_t lnum, rnum; + const std::collate& coll = std::use_facet>(std::locale()); + int cmp_res = 0; + while (*l != 0 && *r != 0) + { + // check if we have a numerical value + if (*l >= L'0' && *l <= L'9' && *r >= L'0' && *r <= L'9') + { + ld = l; + lnum = 0; + while (*ld >= L'0' && *ld <= L'9' && ld < l + 15) + { // compare only up to 15 digits + lnum *= 10; + lnum += *ld++ - '0'; + } + rd = r; + rnum = 0; + while (*rd >= L'0' && *rd <= L'9' && rd < r + 15) + { // compare only up to 15 digits + rnum *= 10; + rnum += *rd++ - L'0'; + } + // do we have numbers? + if (lnum != rnum) + { // yes - and they're different! + return lnum - rnum; + } + l = ld; + r = rd; + continue; + } + // do case less comparison + lc = *l; + if (lc >= L'A' && lc <= L'Z') + lc += L'a' - L'A'; + rc = *r; + if (rc >= L'A' && rc <= L'Z') + rc += L'a' - L'A'; + + // ok, do a normal comparison, taking current locale into account. Add special case stuff (eg '(' characters)) in here later + if ((cmp_res = coll.compare(&lc, &lc + 1, &rc, &rc + 1)) != 0) + { + return cmp_res; + } + l++; + r++; + } + if (*r) + { // r is longer + return -1; + } + else if (*l) + { // l is longer + return 1; + } + return 0; // files are the same + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief UTF8 version of strlen + /// + /// Skips any non-starting bytes in the count, thus returning the number of + /// utf8 characters. + /// + /// @param[in] s c-string to find the length of. + /// @return The number of utf8 characters in the string. + /// + inline static size_t Utf8StringLength(const char* s) + { + size_t length = 0; + while (*s) + { + if ((*s++ & 0xC0) != 0x80) + length++; + } + return length; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Check given character is a space. + /// + /// Hack to check only first byte of UTF-8 character + /// without this hack "TrimX" functions failed on Win32 and OS X with UTF-8 strings + /// + /// @param[in] c Character to check + /// @return true if space, false otherwise + /// + inline static int IsSpace(char c) { return (c & 0x80) == 0 && ::isspace(c); } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks given pointer in string is a UTF8 letter. + /// + /// @param[in] str Given character values to check, must be minimum array of 2 + /// @return return -1 if not, else return the utf8 char length. + /// + inline static int IsUTF8Letter(const unsigned char* str) + { + // reference: + // unicode -> utf8 table: http://www.utf8-chartable.de/ + // latin characters in unicode: http://en.wikipedia.org/wiki/Latin_characters_in_Unicode + unsigned char ch = str[0]; + if (!ch) + return -1; + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) + return 1; + if (!(ch & 0x80)) + return -1; + unsigned char ch2 = str[1]; + if (!ch2) + return -1; + // check latin 1 letter table: http://en.wikipedia.org/wiki/C1_Controls_and_Latin-1_Supplement + if (ch == 0xC3 && ch2 >= 0x80 && ch2 <= 0xBF && ch2 != 0x97 && ch2 != 0xB7) + return 2; + // check latin extended A table: http://en.wikipedia.org/wiki/Latin_Extended-A + if (ch >= 0xC4 && ch <= 0xC7 && ch2 >= 0x80 && ch2 <= 0xBF) + return 2; + // check latin extended B table: http://en.wikipedia.org/wiki/Latin_Extended-B + // and International Phonetic Alphabet: http://en.wikipedia.org/wiki/IPA_Extensions_(Unicode_block) + if (((ch == 0xC8 || ch == 0xC9) && ch2 >= 0x80 && ch2 <= 0xBF) || + (ch == 0xCA && ch2 >= 0x80 && ch2 <= 0xAF)) + return 2; + return -1; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Check whether a string is a natural number. + /// + /// Matches `[ \t]*[0-9]+[ \t]*` + /// + /// @param[in] str The string to check + /// @return true if the string is a natural number, false otherwise. + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// EXPECT_TRUE(kodi::tools::StringUtils::IsNaturalNumber("10")); + /// EXPECT_TRUE(kodi::tools::StringUtils::IsNaturalNumber(" 10")); + /// EXPECT_TRUE(kodi::tools::StringUtils::IsNaturalNumber("0")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsNaturalNumber(" 1 0")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsNaturalNumber("1.0")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsNaturalNumber("1.1")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsNaturalNumber("0x1")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsNaturalNumber("blah")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsNaturalNumber("120 h")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsNaturalNumber(" ")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsNaturalNumber("")); + /// ~~~~~~~~~~~~~ + /// + inline static bool IsNaturalNumber(const std::string& str) + { + size_t i = 0, n = 0; + // allow whitespace,digits,whitespace + while (i < str.size() && isspace((unsigned char)str[i])) + i++; + while (i < str.size() && isdigit((unsigned char)str[i])) + { + i++; + n++; + } + while (i < str.size() && isspace((unsigned char)str[i])) + i++; + return i == str.size() && n > 0; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Check whether a string is an integer. + /// + /// Matches `[ \t]*[\-]*[0-9]+[ \t]*` + /// + /// @param str The string to check + /// @return true if the string is an integer, false otherwise. + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// EXPECT_TRUE(kodi::tools::StringUtils::IsInteger("10")); + /// EXPECT_TRUE(kodi::tools::StringUtils::IsInteger(" -10")); + /// EXPECT_TRUE(kodi::tools::StringUtils::IsInteger("0")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsInteger(" 1 0")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsInteger("1.0")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsInteger("1.1")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsInteger("0x1")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsInteger("blah")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsInteger("120 h")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsInteger(" ")); + /// EXPECT_FALSE(kodi::tools::StringUtils::IsInteger("")); + /// ~~~~~~~~~~~~~ + /// + inline static bool IsInteger(const std::string& str) + { + size_t i = 0, n = 0; + // allow whitespace,-,digits,whitespace + while (i < str.size() && isspace((unsigned char)str[i])) + i++; + if (i < str.size() && str[i] == '-') + i++; + while (i < str.size() && isdigit((unsigned char)str[i])) + { + i++; + n++; + } + while (i < str.size() && isspace((unsigned char)str[i])) + i++; + return i == str.size() && n > 0; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a character is ascii number. + /// + /// @param[in] chr Single character to test + /// @return true if yes, false otherwise + /// + inline static bool IsAasciiDigit(char chr) // locale independent + { + return chr >= '0' && chr <= '9'; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a character is ascii hexadecimal number. + /// + /// @param[in] chr Single character to test + /// @return true if yes, false otherwise + /// + inline static bool IsAsciiXDigit(char chr) // locale independent + { + return (chr >= '0' && chr <= '9') || (chr >= 'a' && chr <= 'f') || (chr >= 'A' && chr <= 'F'); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Translate a character where defined as a numerical value (0-9) + /// string to right integer. + /// + /// @param[in] chr Single character to translate + /// @return + /// + inline static int AsciiDigitValue(char chr) // locale independent + { + if (!IsAasciiDigit(chr)) + return -1; + + return chr - '0'; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Translate a character where defined as a hexadecimal value string + /// to right integer. + /// + /// @param[in] chr Single character to translate + /// @return Corresponding integer value, e.g. character is "A" becomes + /// returned as a integer with 10. + /// + inline static int AsciiXDigitValue(char chr) // locale independent + { + int v = AsciiDigitValue(chr); + if (v >= 0) + return v; + if (chr >= 'a' && chr <= 'f') + return chr - 'a' + 10; + if (chr >= 'A' && chr <= 'F') + return chr - 'A' + 10; + + return -1; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a character is ascii alphabetic lowercase. + /// + /// @param[in] chr Single character to test + /// @return True if ascii uppercase letter, false otherwise + /// + inline static bool IsAsciiUppercaseLetter(char chr) // locale independent + { + return (chr >= 'A' && chr <= 'Z'); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a character is ascii alphabetic lowercase. + /// + /// @param[in] chr Single character to test + /// @return True if ascii lowercase letter, false otherwise + /// + inline static bool IsAsciiLowercaseLetter(char chr) // locale independent + { + return (chr >= 'a' && chr <= 'z'); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Checks a character is within ascii alphabetic and numerical fields. + /// + /// @param[in] chr Single character to test + /// @return true if alphabetic / numerical ascii value + /// + inline static bool IsAsciiAlphaNum(char chr) // locale independent + { + return IsAsciiUppercaseLetter(chr) || IsAsciiLowercaseLetter(chr) || IsAasciiDigit(chr); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Check a string for another text. + /// + /// @param[in] str String to seach for keywords + /// @param[in] keywords List of keywords to search in text + /// @return true if string contains word in list + /// + inline static bool ContainsKeyword(const std::string& str, + const std::vector& keywords) + { + for (const auto& it : keywords) + { + if (str.find(it) != str.npos) + return true; + } + return false; + } + //---------------------------------------------------------------------------- + + /*!@}*/ + + //---------------------------------------------------------------------------- + /// @defgroup cpp_kodi_tools_StringUtils_SearchControl String search + /// @ingroup cpp_kodi_tools_StringUtils + /// @brief **To search a string**\n + /// Various functions are defined in here which allow you to search through a + /// text in different ways. + /// + /*!@{*/ + + //============================================================================ + /// @brief Search for a single word within a text. + /// + /// @param[in] str String to search within + /// @param[in] wordLowerCase Word as lowercase to search + /// @return Position in string where word is found, -1 (std::string::npos) if + /// not found + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// size_t ref, var; + /// + /// // The name "string" is alone within text and becomes found on position 5 + /// ref = 5; + /// var = kodi::tools::StringUtils::FindWords("test string", "string"); + /// EXPECT_EQ(ref, var); + /// + /// // The 12 is included inside another word and then not found as it should alone (-1 return) + /// ref = -1; + /// var = kodi::tools::StringUtils::FindWords("apple2012", "12"); + /// EXPECT_EQ(ref, var); + /// ~~~~~~~~~~~~~ + /// + inline static size_t FindWords(const char* str, const char* wordLowerCase) + { + // NOTE: This assumes word is lowercase! + const unsigned char* s = (const unsigned char*)str; + do + { + // start with a compare + const unsigned char* c = s; + const unsigned char* w = (const unsigned char*)wordLowerCase; + bool same = true; + while (same && *c && *w) + { + unsigned char lc = *c++; + if (lc >= 'A' && lc <= 'Z') + lc += 'a' - 'A'; + + if (lc != *w++) // different + same = false; + } + if (same && *w == 0) // only the same if word has been exhausted + return (const char*)s - str; + + // otherwise, skip current word (composed by latin letters) or number + int l; + if (*s >= '0' && *s <= '9') + { + ++s; + while (*s >= '0' && *s <= '9') + ++s; + } + else if ((l = IsUTF8Letter(s)) > 0) + { + s += l; + while ((l = IsUTF8Letter(s)) > 0) + s += l; + } + else + ++s; + while (*s && *s == ' ') + s++; + + // and repeat until we're done + } while (*s); + + return std::string::npos; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Search a string for a given bracket and give its end position. + /// + /// @param[in] str String to search within + /// @param[in] opener Begin character to start search + /// @param[in] closer End character to end search + /// @param[in] startPos [opt] Position to start search in string, 0 as default + /// to start from begin + /// @return End position where found, -1 if failed + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// int ref, var; + /// + /// ref = 11; + /// var = kodi::tools::StringUtils::FindEndBracket("atest testbb test", 'a', 'b'); + /// EXPECT_EQ(ref, var); + /// ~~~~~~~~~~~~~ + /// + inline static size_t FindEndBracket(const std::string& str, + char opener, + char closer, + size_t startPos = 0) + { + size_t blocks = 1; + for (size_t i = startPos; i < str.size(); i++) + { + if (str[i] == opener) + blocks++; + else if (str[i] == closer) + { + blocks--; + if (!blocks) + return i; + } + } + + return std::string::npos; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Search a text and return the number of parts found as a number. + /// + /// @param[in] strInput Input string to search for + /// @param[in] strFind String to search in input + /// @return Amount how much the string is found + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// EXPECT_EQ(3, kodi::tools::StringUtils::FindNumber("aabcaadeaa", "aa")); + /// EXPECT_EQ(1, kodi::tools::StringUtils::FindNumber("aabcaadeaa", "b")); + /// ~~~~~~~~~~~~~ + /// + inline static int FindNumber(const std::string& strInput, const std::string& strFind) + { + size_t pos = strInput.find(strFind, 0); + int numfound = 0; + while (pos != std::string::npos) + { + numfound++; + pos = strInput.find(strFind, pos + 1); + } + return numfound; + } + //---------------------------------------------------------------------------- + + /*!@}*/ + + //---------------------------------------------------------------------------- + /// @defgroup cpp_kodi_tools_StringUtils_ListControl String list + /// @ingroup cpp_kodi_tools_StringUtils + /// @brief **Creating lists using a string**\n + /// With this, either simple vectors or lists defined by templates can be given + /// for the respective divided text. + /// + /*!@{*/ + + //============================================================================ + /// @brief Concatenates the elements of a specified array or the members of a + /// collection and uses the specified separator between each element or + /// member. + /// + /// @param[in] strings An array of objects whose string representations are + /// concatenated. + /// @param[in] delimiter Delimiter to be used to join the input string + /// @return A string consisting of the elements of values, separated by the + /// separator character. + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string refstr, varstr; + /// std::vector strarray; + /// + /// strarray.emplace_back("a"); + /// strarray.emplace_back("b"); + /// strarray.emplace_back("c"); + /// strarray.emplace_back("de"); + /// strarray.emplace_back(","); + /// strarray.emplace_back("fg"); + /// strarray.emplace_back(","); + /// refstr = "a,b,c,de,,,fg,,"; + /// varstr = kodi::tools::StringUtils::Join(strarray, ","); + /// EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + /// ~~~~~~~~~~~~~ + /// + template + inline static std::string Join(const CONTAINER& strings, const std::string& delimiter) + { + std::string result; + for (const auto& str : strings) + result += str + delimiter; + + if (!result.empty()) + result.erase(result.size() - delimiter.size()); + return result; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Splits the given input string using the given delimiter into + /// separate strings. + /// + /// If the given input string is empty the result will be an empty array (not + /// an array containing an empty string). + /// + /// @param[in] input Input string to be split + /// @param[in] delimiter Delimiter to be used to split the input string + /// @param[in] iMaxStrings [opt] Maximum number of resulting split strings + /// @return List of splitted strings + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::vector varresults; + /// + /// varresults = kodi::tools::StringUtils::Split("g,h,ij,k,lm,,n", ","); + /// EXPECT_STREQ("g", varresults.at(0).c_str()); + /// EXPECT_STREQ("h", varresults.at(1).c_str()); + /// EXPECT_STREQ("ij", varresults.at(2).c_str()); + /// EXPECT_STREQ("k", varresults.at(3).c_str()); + /// EXPECT_STREQ("lm", varresults.at(4).c_str()); + /// EXPECT_STREQ("", varresults.at(5).c_str()); + /// EXPECT_STREQ("n", varresults.at(6).c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static std::vector Split(const std::string& input, + const std::string& delimiter, + unsigned int iMaxStrings = 0) + { + std::vector result; + SplitTo(std::back_inserter(result), input, delimiter, iMaxStrings); + return result; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Splits the given input string using the given delimiter into + /// separate strings. + /// + /// If the given input string is empty the result will be an empty array (not + /// an array containing an empty string). + /// + /// @param[in] input Input string to be split + /// @param[in] delimiter Delimiter to be used to split the input string + /// @param[in] iMaxStrings [opt] Maximum number of resulting split strings + /// @return List of splitted strings + /// + inline static std::vector Split(const std::string& input, + const char delimiter, + int iMaxStrings = 0) + { + std::vector result; + SplitTo(std::back_inserter(result), input, delimiter, iMaxStrings); + return result; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Splits the given input string using the given delimiter into + /// separate strings. + /// + /// If the given input string is empty the result will be an empty array (not + /// an array containing an empty string). + /// + /// @param[in] input Input string to be split + /// @param[in] delimiters Delimiter strings to be used to split the input + /// strings + /// @return List of splitted strings + /// + inline static std::vector Split(const std::string& input, + const std::vector& delimiters) + { + std::vector result; + SplitTo(std::back_inserter(result), input, delimiters); + return result; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Splits the given input string using the given delimiter into + /// separate strings. + /// + /// If the given input string is empty nothing will be put into the target + /// iterator. + /// + /// @param[in] d_first The beginning of the destination range + /// @param[in] input Input string to be split + /// @param[in] delimiter Delimiter to be used to split the input string + /// @param[in] iMaxStrings [opt] Maximum number of resulting split strings + /// @return Output iterator to the element in the destination range, one past + /// the last element that was put there + /// + template + inline static OutputIt SplitTo(OutputIt d_first, + const std::string& input, + const std::string& delimiter, + unsigned int iMaxStrings = 0) + { + OutputIt dest = d_first; + + if (input.empty()) + return dest; + if (delimiter.empty()) + { + *d_first++ = input; + return dest; + } + + const size_t delimLen = delimiter.length(); + size_t nextDelim; + size_t textPos = 0; + do + { + if (--iMaxStrings == 0) + { + *dest++ = input.substr(textPos); + break; + } + nextDelim = input.find(delimiter, textPos); + *dest++ = input.substr(textPos, nextDelim - textPos); + textPos = nextDelim + delimLen; + } while (nextDelim != std::string::npos); + + return dest; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Splits the given input string using the given delimiter into + /// separate strings. + /// + /// If the given input string is empty nothing will be put into the target + /// iterator. + /// + /// @param[in] d_first The beginning of the destination range + /// @param[in] input Input string to be split + /// @param[in] delimiter Delimiter to be used to split the input string + /// @param[in] iMaxStrings [opt] Maximum number of resulting split strings + /// @return Output iterator to the element in the destination range, one past + /// the last element that was put there + /// + template + inline static OutputIt SplitTo(OutputIt d_first, + const std::string& input, + const char delimiter, + int iMaxStrings = 0) + { + return SplitTo(d_first, input, std::string(1, delimiter), iMaxStrings); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Splits the given input string using the given delimiter into + /// separate strings. + /// + /// If the given input string is empty nothing will be put into the target + /// iterator. + /// + /// @param[in] d_first The beginning of the destination range + /// @param[in] input Input string to be split + /// @param[in] delimiters Delimiter strings to be used to split the input + /// strings + /// @return Output iterator to the element in the destination range, one past + /// the last element that was put there + /// + template + inline static OutputIt SplitTo(OutputIt d_first, + const std::string& input, + const std::vector& delimiters) + { + OutputIt dest = d_first; + if (input.empty()) + return dest; + + if (delimiters.empty()) + { + *dest++ = input; + return dest; + } + std::string str = input; + for (size_t di = 1; di < delimiters.size(); di++) + StringUtils::Replace(str, delimiters[di], delimiters[0]); + return SplitTo(dest, str, delimiters[0]); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Splits the given input strings using the given delimiters into + /// further separate strings. + /// + /// If the given input string vector is empty the result will be an empty + /// array (not an array containing an empty string). + /// + /// Delimiter strings are applied in order, so once the (optional) maximum + /// number of items is produced no other delimiters are applied. This produces + /// different results to applying all delimiters at once e.g. "a/b#c/d" + /// becomes "a", "b#c", "d" rather than "a", "b", "c/d" + /// + /// @param[in] input Input vector of strings each to be split + /// @param[in] delimiters Delimiter strings to be used to split the input + /// strings + /// @param[in] iMaxStrings [opt] Maximum number of resulting split strings + /// @return List of splitted strings + /// + inline static std::vector SplitMulti(const std::vector& input, + const std::vector& delimiters, + unsigned int iMaxStrings = 0) + { + if (input.empty()) + return std::vector(); + + std::vector results(input); + + if (delimiters.empty() || (iMaxStrings > 0 && iMaxStrings <= input.size())) + return results; + + std::vector strings1; + if (iMaxStrings == 0) + { + for (size_t di = 0; di < delimiters.size(); di++) + { + for (size_t i = 0; i < results.size(); i++) + { + std::vector substrings = StringUtils::Split(results[i], delimiters[di]); + for (size_t j = 0; j < substrings.size(); j++) + strings1.push_back(substrings[j]); + } + results = strings1; + strings1.clear(); + } + return results; + } + + // Control the number of strings input is split into, keeping the original strings. + // Note iMaxStrings > input.size() + size_t iNew = iMaxStrings - results.size(); + for (size_t di = 0; di < delimiters.size(); di++) + { + for (size_t i = 0; i < results.size(); i++) + { + if (iNew > 0) + { + std::vector substrings = + StringUtils::Split(results[i], delimiters[di], static_cast(iNew + 1)); + iNew = iNew - substrings.size() + 1; + for (size_t j = 0; j < substrings.size(); j++) + strings1.push_back(substrings[j]); + } + else + strings1.push_back(results[i]); + } + results = strings1; + iNew = iMaxStrings - results.size(); + strings1.clear(); + if ((iNew <= 0)) + break; //Stop trying any more delimiters + } + return results; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Split a string by the specified delimiters. + /// + /// Splits a string using one or more delimiting characters, ignoring empty + /// tokens. + /// + /// Differs from Split() in two ways: + /// 1. The delimiters are treated as individual characters, rather than a single delimiting string. + /// 2. Empty tokens are ignored. + /// + /// + /// @param[in] input String to split + /// @param[in] delimiters Delimiters + /// @return A vector of tokens + /// + inline static std::vector Tokenize(const std::string& input, + const std::string& delimiters) + { + std::vector tokens; + Tokenize(input, tokens, delimiters); + return tokens; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Tokenizing a string denotes splitting a string with respect to a + /// delimiter. + /// + /// @param[in] input String to split + /// @param[out] tokens A vector of tokens + /// @param[in] delimiters Delimiters + /// + inline static void Tokenize(const std::string& input, + std::vector& tokens, + const std::string& delimiters) + { + tokens.clear(); + // Skip delimiters at beginning. + std::string::size_type dataPos = input.find_first_not_of(delimiters); + while (dataPos != std::string::npos) + { + // Find next delimiter + const std::string::size_type nextDelimPos = input.find_first_of(delimiters, dataPos); + // Found a token, add it to the vector. + tokens.push_back(input.substr(dataPos, nextDelimPos - dataPos)); + // Skip delimiters. Note the "not_of" + dataPos = input.find_first_not_of(delimiters, nextDelimPos); + } + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Tokenizing a string denotes splitting a string with respect to a + /// delimiter. + /// + /// @param[in] input String to split + /// @param[in] delimiter Delimiters + /// @return A vector of tokens + /// + inline static std::vector Tokenize(const std::string& input, const char delimiter) + { + std::vector tokens; + Tokenize(input, tokens, delimiter); + return tokens; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Tokenizing a string denotes splitting a string with respect to a + /// delimiter. + /// + /// @param[in] input String to split + /// @param[out] tokens List of + /// @param[in] delimiter Delimiters + /// + inline static void Tokenize(const std::string& input, + std::vector& tokens, + const char delimiter) + { + tokens.clear(); + // Skip delimiters at beginning. + std::string::size_type dataPos = input.find_first_not_of(delimiter); + while (dataPos != std::string::npos) + { + // Find next delimiter + const std::string::size_type nextDelimPos = input.find(delimiter, dataPos); + // Found a token, add it to the vector. + tokens.push_back(input.substr(dataPos, nextDelimPos - dataPos)); + // Skip delimiters. Note the "not_of" + dataPos = input.find_first_not_of(delimiter, nextDelimPos); + } + } + //---------------------------------------------------------------------------- + + /*!@}*/ + + //---------------------------------------------------------------------------- + /// @defgroup cpp_kodi_tools_StringUtils_TimeControl Time value processing + /// @ingroup cpp_kodi_tools_StringUtils + /// @brief **String time formats**\n + /// This is used to process the respective time formats in text fields. + /*!@{*/ + + //============================================================================ + /// @brief Converts a time string to the respective integer value. + /// + /// @param[in] timeString String with time.\n + /// Following types are possible: + /// - "MM min" (integer number with "min" on end) + /// - "HH:MM:SS" + /// @return Time in seconds + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// EXPECT_EQ(77455, kodi::tools::StringUtils::TimeStringToSeconds("21:30:55")); + /// EXPECT_EQ(7*60, kodi::tools::StringUtils::TimeStringToSeconds("7 min")); + /// EXPECT_EQ(7*60, kodi::tools::StringUtils::TimeStringToSeconds("7 min\t")); + /// EXPECT_EQ(154*60, kodi::tools::StringUtils::TimeStringToSeconds(" 154 min")); + /// EXPECT_EQ(1*60+1, kodi::tools::StringUtils::TimeStringToSeconds("1:01")); + /// EXPECT_EQ(4*60+3, kodi::tools::StringUtils::TimeStringToSeconds("4:03")); + /// EXPECT_EQ(2*3600+4*60+3, kodi::tools::StringUtils::TimeStringToSeconds("2:04:03")); + /// EXPECT_EQ(2*3600+4*60+3, kodi::tools::StringUtils::TimeStringToSeconds(" 2:4:3")); + /// EXPECT_EQ(2*3600+4*60+3, kodi::tools::StringUtils::TimeStringToSeconds(" \t\t 02:04:03 \n ")); + /// EXPECT_EQ(1*3600+5*60+2, kodi::tools::StringUtils::TimeStringToSeconds("01:05:02:04:03 \n ")); + /// EXPECT_EQ(0, kodi::tools::StringUtils::TimeStringToSeconds("blah")); + /// EXPECT_EQ(0, kodi::tools::StringUtils::TimeStringToSeconds("ля-ля")); + /// ~~~~~~~~~~~~~ + /// + inline static long TimeStringToSeconds(const std::string& timeString) + { + std::string strCopy(timeString); + StringUtils::Trim(strCopy); + if (StringUtils::EndsWithNoCase(strCopy, " min")) + { + // this is imdb format of "XXX min" + return 60 * atoi(strCopy.c_str()); + } + else + { + std::vector secs = StringUtils::Split(strCopy, ':'); + int timeInSecs = 0; + for (unsigned int i = 0; i < 3 && i < secs.size(); i++) + { + timeInSecs *= 60; + timeInSecs += atoi(secs[i].c_str()); + } + return timeInSecs; + } + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Convert a time in seconds to a string based on the given time + /// format. + /// + /// @param[in] seconds time in seconds + /// @param[in] format [opt] The format we want the time in + /// @return The formatted time + /// + /// @sa TIME_FORMAT + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// std::string ref, var; + /// + /// ref = "21:30:55"; + /// var = kodi::tools::StringUtils::SecondsToTimeString(77455); + /// EXPECT_STREQ(ref.c_str(), var.c_str()); + /// ~~~~~~~~~~~~~ + /// + inline static std::string SecondsToTimeString(long seconds, + TIME_FORMAT format = TIME_FORMAT_GUESS) + { + bool isNegative = seconds < 0; + seconds = std::abs(seconds); + + std::string strHMS; + if (format == TIME_FORMAT_SECS) + strHMS = StringUtils::Format("%i", seconds); + else if (format == TIME_FORMAT_MINS) + strHMS = StringUtils::Format("%i", lrintf(static_cast(seconds) / 60.0f)); + else if (format == TIME_FORMAT_HOURS) + strHMS = StringUtils::Format("%i", lrintf(static_cast(seconds) / 3600.0f)); + else if (format & TIME_FORMAT_M) + strHMS += StringUtils::Format("%i", seconds % 3600 / 60); + else + { + int hh = seconds / 3600; + seconds = seconds % 3600; + int mm = seconds / 60; + int ss = seconds % 60; + + if (format == TIME_FORMAT_GUESS) + format = (hh >= 1) ? TIME_FORMAT_HH_MM_SS : TIME_FORMAT_MM_SS; + if (format & TIME_FORMAT_HH) + strHMS += StringUtils::Format("%2.2i", hh); + else if (format & TIME_FORMAT_H) + strHMS += StringUtils::Format("%i", hh); + if (format & TIME_FORMAT_MM) + strHMS += StringUtils::Format(strHMS.empty() ? "%2.2i" : ":%2.2i", mm); + if (format & TIME_FORMAT_SS) + strHMS += StringUtils::Format(strHMS.empty() ? "%2.2i" : ":%2.2i", ss); + } + + if (isNegative) + strHMS = "-" + strHMS; + + return strHMS; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @brief Converts a string in the format YYYYMMDD to the corresponding + /// integer value. + /// + /// @param[in] dateString The date in the associated format, possible values + /// are: + /// - DD (for days only) + /// - MM-DD (for days with month) + /// - YYYY-MM-DD (for years, then month and last days) + /// @return Corresponding integer, e.g. "2020-12-24" return as integer value + /// 20201224 + /// + /// + /// -------------------------------------------------------------------------- + /// Example: + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// int ref, var; + /// + /// ref = 20120706; + /// var = kodi::tools::StringUtils::DateStringToYYYYMMDD("2012-07-06"); + /// EXPECT_EQ(ref, var); + /// ~~~~~~~~~~~~~ + /// + inline static int DateStringToYYYYMMDD(const std::string& dateString) + { + std::vector days = StringUtils::Split(dateString, '-'); + if (days.size() == 1) + return atoi(days[0].c_str()); + else if (days.size() == 2) + return atoi(days[0].c_str()) * 100 + atoi(days[1].c_str()); + else if (days.size() == 3) + return atoi(days[0].c_str()) * 10000 + atoi(days[1].c_str()) * 100 + atoi(days[2].c_str()); + else + return -1; + } + //---------------------------------------------------------------------------- + + /*!@}*/ + +private: + inline static int compareWchar(const void* a, const void* b) + { + if (*static_cast(a) < *static_cast(b)) + return -1; + else if (*static_cast(a) > *static_cast(b)) + return 1; + return 0; + } + + inline static wchar_t tolowerUnicode(const wchar_t& c) + { + wchar_t* p = + static_cast(bsearch(&c, unicode_uppers, sizeof(unicode_uppers) / sizeof(wchar_t), + sizeof(wchar_t), compareWchar)); + if (p) + return *(unicode_lowers + (p - unicode_uppers)); + + return c; + } + + inline static wchar_t toupperUnicode(const wchar_t& c) + { + wchar_t* p = + static_cast(bsearch(&c, unicode_lowers, sizeof(unicode_lowers) / sizeof(wchar_t), + sizeof(wchar_t), compareWchar)); + if (p) + return *(unicode_uppers + (p - unicode_lowers)); + + return c; + } + + static uint32_t UTF8ToUnicode(const unsigned char* z, int nKey, unsigned char& bytes) + { + // Lookup table used decode the first byte of a multi-byte UTF8 character + // clang-format off + static const unsigned char utf8Trans1[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, + }; + // clang-format on + + uint32_t c; + bytes = 0; + c = z[0]; + if (c >= 0xc0) + { + c = utf8Trans1[c - 0xc0]; + int index = 1; + while (index < nKey && (z[index] & 0xc0) == 0x80) + { + c = (c << 6) + (0x3f & z[index]); + index++; + } + if (c < 0x80 || (c & 0xFFFFF800) == 0xD800 || (c & 0xFFFFFFFE) == 0xFFFE) + c = 0xFFFD; + bytes = static_cast(index - 1); + } + return c; + } +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace tools */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/tools/Thread.h b/xbmc/addons/kodi-dev-kit/include/kodi/tools/Thread.h new file mode 100644 index 0000000..4cae13e --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/tools/Thread.h @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifdef __cplusplus + +#include "../General.h" + +#include +#include +#include +#include +#include + +namespace kodi +{ +namespace tools +{ + +//============================================================================== +/// @defgroup cpp_kodi_tools_CThread class CThread +/// @ingroup cpp_kodi_tools +/// @brief **Helper class to represent threads of execution**\n +/// An execution thread is a sequence of instructions that can run concurrently +/// with other such sequences in multithreaded environments while sharing the +/// same address space. +/// +/// Is intended to reduce any code work of C++ on addons and to have them faster +/// to use. +/// +/// His code uses the support of platform-independent thread system introduced +/// with C++11. +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// #include +/// +/// class ATTRIBUTE_HIDDEN CTestAddon +/// : public kodi::addon::CAddonBase, +/// public kodi::tools::CThread +/// { +/// public: +/// CTestAddon() = default; +/// +/// ADDON_STATUS Create() override; +/// +/// void Process() override; +/// }; +/// +/// ADDON_STATUS CTestAddon::Create() +/// { +/// kodi::Log(ADDON_LOG_INFO, "Starting thread"); +/// CreateThread(); +/// +/// Sleep(4000); +/// +/// kodi::Log(ADDON_LOG_INFO, "Stopping thread"); +/// // This added as example and also becomes stopped by class destructor +/// StopThread(); +/// +/// return ADDON_STATUS_OK; +/// } +/// +/// void CTestAddon::Process() +/// { +/// kodi::Log(ADDON_LOG_INFO, "Thread started"); +/// +/// while (!m_threadStop) +/// { +/// kodi::Log(ADDON_LOG_INFO, "Hello World"); +/// Sleep(1000); +/// } +/// +/// kodi::Log(ADDON_LOG_INFO, "Thread ended"); +/// } +/// +/// ADDONCREATOR(CTestAddon) +/// ~~~~~~~~~~~~~ +/// +///@{ +class CThread +{ +public: + //============================================================================ + /// @ingroup cpp_kodi_tools_CThread + /// @brief Class constructor. + /// + CThread() : m_threadStop(false) {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CThread + /// @brief Class destructor. + /// + virtual ~CThread() + { + StopThread(); + if (m_thread != nullptr) + { + m_thread->detach(); + delete m_thread; + } + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CThread + /// @brief Check auto delete is enabled on this thread class. + /// + /// @return true if auto delete is used, false otherwise + /// + bool IsAutoDelete() const { return m_autoDelete; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CThread + /// @brief Check caller is on this running thread. + /// + /// @return true if called from thread inside the class, false if from another + /// thread + /// + bool IsCurrentThread() const { return m_threadId == std::this_thread::get_id(); } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CThread + /// @brief Check thread inside this class is running and active. + /// + /// @note This function should be used from outside and not within process to + /// check thread is active. Use use atomic bool @ref m_threadStop for this. + /// + /// @return true if running, false if not + /// + bool IsRunning() const + { + if (m_thread != nullptr) + { + // it's possible that the thread exited on it's own without a call to StopThread. If so then + // the promise should be fulfilled. + std::future_status stat = m_future.wait_for(std::chrono::milliseconds(0)); + // a status of 'ready' means the future contains the value so the thread has exited + // since the thread can't exit without setting the future. + if (stat == std::future_status::ready) // this is an indication the thread has exited. + return false; + return true; // otherwise the thread is still active. + } + else + return false; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CThread + /// @brief Create a new thread defined by this class on child. + /// + /// This starts then @ref Process() where is available on the child by addon. + /// + /// @param[in] autoDelete To set thread to delete itself after end, default is + /// false + /// + void CreateThread(bool autoDelete = false) + { + if (m_thread != nullptr) + { + // if the thread exited on it's own, without a call to StopThread, then we can get here + // incorrectly. We should be able to determine this by checking the promise. + std::future_status stat = m_future.wait_for(std::chrono::milliseconds(0)); + // a status of 'ready' means the future contains the value so the thread has exited + // since the thread can't exit without setting the future. + if (stat == std::future_status::ready) // this is an indication the thread has exited. + StopThread(true); // so let's just clean up + else + { // otherwise we have a problem. + kodi::Log(ADDON_LOG_FATAL, "%s - fatal error creating thread - old thread id not null", + __func__); + exit(1); + } + } + + m_autoDelete = autoDelete; + m_threadStop = false; + m_startEvent.notify_all(); + m_stopEvent.notify_all(); + + std::promise prom; + m_future = prom.get_future(); + + { + // The std::thread internals must be set prior to the lambda doing + // any work. This will cause the lambda to wait until m_thread + // is fully initialized. Interestingly, using a std::atomic doesn't + // have the appropriate memory barrier behavior to accomplish the + // same thing so a full system mutex needs to be used. + std::unique_lock lock(m_threadMutex); + m_thread = new std::thread( + [](CThread* thread, std::promise promise) { + try + { + { + // Wait for the pThread->m_thread internals to be set. Otherwise we could + // get to a place where we're reading, say, the thread id inside this + // lambda's call stack prior to the thread that kicked off this lambda + // having it set. Once this lock is released, the CThread::Create function + // that kicked this off is done so everything should be set. + std::unique_lock lock(thread->m_threadMutex); + } + + thread->m_threadId = std::this_thread::get_id(); + std::stringstream ss; + ss << thread->m_threadId; + std::string id = ss.str(); + bool autodelete = thread->m_autoDelete; + + kodi::Log(ADDON_LOG_DEBUG, "Thread %s start, auto delete: %s", id.c_str(), + (autodelete ? "true" : "false")); + + thread->m_running = true; + thread->m_startEvent.notify_one(); + + thread->Process(); + + if (autodelete) + { + kodi::Log(ADDON_LOG_DEBUG, "Thread %s terminating (autodelete)", id.c_str()); + delete thread; + thread = nullptr; + } + else + kodi::Log(ADDON_LOG_DEBUG, "Thread %s terminating", id.c_str()); + } + catch (const std::exception& e) + { + kodi::Log(ADDON_LOG_DEBUG, "Thread Terminating with Exception: %s", e.what()); + } + catch (...) + { + kodi::Log(ADDON_LOG_DEBUG, "Thread Terminating with Exception"); + } + + promise.set_value(true); + }, + this, std::move(prom)); + + m_startEvent.wait(lock); + } + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CThread + /// @brief Stop a running thread. + /// + /// @param[in] wait As true (default) to wait until thread is finished and + /// stopped, as false the function return directly and thread + /// becomes independently stopped. + /// + void StopThread(bool wait = true) + { + std::unique_lock lock(m_threadMutex); + + if (m_threadStop) + return; + + if (m_thread && !m_running) + m_startEvent.wait(lock); + m_running = false; + m_threadStop = true; + m_stopEvent.notify_one(); + + std::thread* lthread = m_thread; + if (lthread != nullptr && wait && !IsCurrentThread()) + { + lock.unlock(); + if (lthread->joinable()) + lthread->join(); + delete m_thread; + m_thread = nullptr; + m_threadId = std::thread::id(); + } + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CThread + /// @brief Thread sleep with given amount of milliseconds. + /// + /// This makes a sleep in the thread with a given time value. If it is called + /// within the process itself, it is also checked whether the thread is + /// terminated and the sleep process is thereby interrupted. + /// + /// If the external point calls this, only a regular sleep is used, which runs + /// through completely. + /// + /// @param[in] milliseconds Time to sleep + /// + void Sleep(uint32_t milliseconds) + { + if (milliseconds > 10 && IsCurrentThread()) + { + std::unique_lock lock(m_threadMutex); + m_stopEvent.wait_for(lock, std::chrono::milliseconds(milliseconds)); + } + else + { + std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); + } + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CThread + /// @brief The function returns when the thread execution has completed or + /// timing is reached in milliseconds beforehand + /// + /// This synchronizes the moment this function returns with the completion of + /// all operations on the thread. + /// + /// @param[in] milliseconds Time to wait for join + /// + bool Join(unsigned int milliseconds) + { + std::unique_lock lock(m_threadMutex); + std::thread* lthread = m_thread; + if (lthread != nullptr) + { + if (IsCurrentThread()) + return false; + + { + m_threadMutex.unlock(); // don't hold the thread lock while we're waiting + std::future_status stat = m_future.wait_for(std::chrono::milliseconds(milliseconds)); + if (stat != std::future_status::ready) + return false; + m_threadMutex.lock(); + } + + // it's possible it's already joined since we released the lock above. + if (lthread->joinable()) + m_thread->join(); + return true; + } + else + return false; + } + //---------------------------------------------------------------------------- + +protected: + //============================================================================ + /// @ingroup cpp_kodi_tools_CThread + /// @brief The function to be added by the addon as a child to carry out the + /// process thread. + /// + /// Use @ref m_threadStop to check about active of thread and want stopped from + /// external place. + /// + /// @note This function is necessary and must be implemented by the addon. + /// + virtual void Process() = 0; + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CThread + /// @brief Atomic bool to indicate thread is active. + /// + /// This should be used in @ref Process() to check the activity of the thread and, + /// if true, to terminate the process. + /// + /// - `false`: Thread active and should be run + /// - `true`: Thread ends and should be stopped + /// + std::atomic m_threadStop; + //---------------------------------------------------------------------------- + +private: + bool m_autoDelete = false; + bool m_running = false; + std::condition_variable_any m_stopEvent; + std::condition_variable_any m_startEvent; + std::recursive_mutex m_threadMutex; + std::thread::id m_threadId; + std::thread* m_thread = nullptr; + std::future m_future; +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace tools */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/tools/Timer.h b/xbmc/addons/kodi-dev-kit/include/kodi/tools/Timer.h new file mode 100644 index 0000000..0e0ced7 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/tools/Timer.h @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifdef __cplusplus + +#include "Thread.h" + +#include + +namespace kodi +{ +namespace tools +{ + +//============================================================================== +/// @defgroup cpp_kodi_tools_CTimer class CTimer +/// @ingroup cpp_kodi_tools +/// @brief **Time interval management**\n +/// Class which enables a time interval to be called up by a given function or +/// class by means of a thread. +/// +/// His code uses the support of platform-independent thread system introduced +/// with C++11. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class ATTRIBUTE_HIDDEN CExample +/// { +/// public: +/// CExample() : m_timer([this](){TimerCall();}) +/// { +/// m_timer.Start(5000, true); // let call continuously all 5 seconds +/// } +/// +/// void TimerCall() +/// { +/// fprintf(stderr, "Hello World\n"); +/// } +/// +/// private: +/// kodi::tools::CTimer m_timer; +/// }; +/// ~~~~~~~~~~~~~ +/// +///@{ +class CTimer : protected CThread +{ +public: + class ITimerCallback; + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Class constructor to pass individual other class as callback. + /// + /// @param[in] callback Child class of parent @ref ITimerCallback with + /// implemented function @ref ITimerCallback::OnTimeout(). + /// + explicit CTimer(kodi::tools::CTimer::ITimerCallback* callback) + : CTimer(std::bind(&ITimerCallback::OnTimeout, callback)) + { + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Class constructor to pass individual function as callback. + /// + /// @param[in] callback Function to pass as callback about timeout. + /// + /// **Callback function style:** + /// ~~~~~~~~~~~~~{.cpp} + /// void TimerCallback() + /// { + /// } + /// ~~~~~~~~~~~~~ + explicit CTimer(std::function const& callback) : m_callback(callback) {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Class destructor. + /// + ~CTimer() override { Stop(true); } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Start the timer by given time in milliseconds to make his call + /// by arrive of them. + /// + /// If interval is activated, it calls the associated callback function + /// continuously in the given interval. + /// + /// @param[in] timeout Timeout in milliseconds + /// @param[in] interval [opt] To run continuously if true, false only one time + /// and default + /// @return True if successfully done, false if not (callback missing, + /// timeout = 0 or was already running. + /// + bool Start(uint64_t timeout, bool interval = false) + { + using namespace std::chrono; + + if (m_callback == nullptr || timeout == 0 || IsRunning()) + return false; + + m_timeout = milliseconds(timeout); + m_interval = interval; + + CreateThread(); + return true; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Stop the timer if it is active. + /// + /// @param[in] wait [opt] Wait until timer is stopped, false is default and + /// call unblocked + /// @return True if timer was active and was stopped, false if already was + /// stopped. + /// + bool Stop(bool wait = false) + { + if (!IsRunning()) + return false; + + m_threadStop = true; + m_eventTimeout.notify_all(); + StopThread(wait); + + return true; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Restart timer complete by stop and restart his thread again. + /// + /// @note Restart only possible as long the timer was running and not done his + /// work. + /// + /// @return True if start was successfully done, on error, or if was already + /// finished returned as false + /// + bool Restart() + { + using namespace std::chrono; + + if (!IsRunning()) + return false; + + Stop(true); + return Start(duration_cast(m_timeout).count(), m_interval); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Restart the timer with new timeout without touch of his thread. + /// + /// @param[in] timeout Time as milliseconds to wait for next call + /// + void RestartAsync(uint64_t timeout) + { + using namespace std::chrono; + + m_timeout = milliseconds(timeout); + const auto now = system_clock::now(); + m_endTime = now.time_since_epoch() + m_timeout; + m_eventTimeout.notify_all(); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Check timer is still active to wait for next call. + /// + /// @return True if active, false if all his work done and no more running + /// + bool IsRunning() const { return CThread::IsRunning(); } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Get elapsed time as floating point of timer as seconds. + /// + /// @return Elapsed time + /// + float GetElapsedSeconds() const { return GetElapsedMilliseconds() / 1000.0f; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Get elapsed time as floating point of timer as milliseconds. + /// + /// @return Elapsed time + /// + float GetElapsedMilliseconds() const + { + using namespace std::chrono; + + if (!IsRunning()) + return 0.0f; + + const auto now = system_clock::now(); + return static_cast(duration_cast(now.time_since_epoch() - (m_endTime - m_timeout)).count()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_tools_CTimer_CB class ITimerCallback + /// @ingroup cpp_kodi_tools_CTimer + /// @brief **Callback class of timer**\n + /// To give on contructor by @ref CTimer(kodi::tools::CTimer::ITimerCallback* callback) + /// + class ITimerCallback + { + public: + //========================================================================== + /// @ingroup cpp_kodi_tools_CTimer_CB + /// @brief Class destructor. + /// + virtual ~ITimerCallback() = default; + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_tools_CTimer_CB + /// @brief Callback function to implement if constuctor @ref CTimer(kodi::tools::CTimer::ITimerCallback* callback) + /// is used and this as parent on related class + /// + /// ---------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// class CExample : public kodi::tools::CTimer, + /// private kodi::tools::CTimer::ITimerCallback + /// { + /// public: + /// CExample() : kodi::tools::CTimer(this) + /// { + /// } + /// + /// void OnTimeout() override + /// { + /// // Some work + /// } + /// }; + /// + /// ~~~~~~~~~~~~~ + /// + virtual void OnTimeout() = 0; + //-------------------------------------------------------------------------- + }; + //---------------------------------------------------------------------------- + +protected: + void Process() override + { + using namespace std::chrono; + + while (!m_threadStop) + { + auto currentTime = system_clock::now(); + m_endTime = currentTime.time_since_epoch() + m_timeout; + + // wait the necessary time + std::mutex mutex; + std::unique_lock lock(mutex); + const auto waitTime = duration_cast(m_endTime - currentTime.time_since_epoch()); + if (m_eventTimeout.wait_for(lock, waitTime) == std::cv_status::timeout) + { + currentTime = system_clock::now(); + if (m_endTime.count() <= currentTime.time_since_epoch().count()) + { + // execute OnTimeout() callback + m_callback(); + + // continue if this is an interval timer, or if it was restarted during callback + if (!m_interval && m_endTime.count() <= currentTime.time_since_epoch().count()) + break; + } + } + } + } + +private: + bool m_interval = false; + std::function m_callback; + std::chrono::system_clock::duration m_timeout; + std::chrono::system_clock::duration m_endTime; + std::condition_variable_any m_eventTimeout; +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace tools */ +} /* namespace kodi */ + +#endif /* __cplusplus */ diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/versions.h b/xbmc/addons/kodi-dev-kit/include/kodi/versions.h new file mode 100644 index 0000000..e632f5a --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/include/kodi/versions.h @@ -0,0 +1,492 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + +/* + *------------------------------------------------------------------------------ + * Some parts on headers are only be used for Kodi itself and internally (not + * for add-on development). + * + * For this reason also no doxygen part with "///" defined there. + * ----------------------------------------------------------------------------- + */ + +/* + * Versions of all add-on globals and instances are defined below. + * + * This is added here and not in related header to prevent not + * needed includes during compile. Also have it here a better + * overview. + */ + +// Ignore clang here, as this must be good in overview and as the main reason, +// because cmake uses this area in this form to perform its addon dependency +// check. +// clang-format off +#define ADDON_GLOBAL_VERSION_MAIN "1.2.4" +#define ADDON_GLOBAL_VERSION_MAIN_MIN "1.2.0" +#define ADDON_GLOBAL_VERSION_MAIN_XML_ID "kodi.binary.global.main" +#define ADDON_GLOBAL_VERSION_MAIN_DEPENDS "AddonBase.h" \ + "addon-instance/" \ + "c-api/addon_base.h" + +#define ADDON_GLOBAL_VERSION_GENERAL "1.0.5" +#define ADDON_GLOBAL_VERSION_GENERAL_MIN "1.0.4" +#define ADDON_GLOBAL_VERSION_GENERAL_XML_ID "kodi.binary.global.general" +#define ADDON_GLOBAL_VERSION_GENERAL_DEPENDS "General.h" + +#define ADDON_GLOBAL_VERSION_GUI "5.15.0" +#define ADDON_GLOBAL_VERSION_GUI_MIN "5.15.0" +#define ADDON_GLOBAL_VERSION_GUI_XML_ID "kodi.binary.global.gui" +#define ADDON_GLOBAL_VERSION_GUI_DEPENDS "c-api/gui/input/action_ids.h" \ + "c-api/gui/" \ + "gui/" + +#define ADDON_GLOBAL_VERSION_AUDIOENGINE "1.1.1" +#define ADDON_GLOBAL_VERSION_AUDIOENGINE_MIN "1.1.0" +#define ADDON_GLOBAL_VERSION_AUDIOENGINE_XML_ID "kodi.binary.global.audioengine" +#define ADDON_GLOBAL_VERSION_AUDIOENGINE_DEPENDS "AudioEngine.h" \ + "c-api/audio_engine.h" + +#define ADDON_GLOBAL_VERSION_FILESYSTEM "1.1.6" +#define ADDON_GLOBAL_VERSION_FILESYSTEM_MIN "1.1.0" +#define ADDON_GLOBAL_VERSION_FILESYSTEM_XML_ID "kodi.binary.global.filesystem" +#define ADDON_GLOBAL_VERSION_FILESYSTEM_DEPENDS "Filesystem.h" \ + "c-api/filesystem.h" \ + "gui/gl/Shader.h" \ + "tools/DllHelper.h" + +#define ADDON_GLOBAL_VERSION_NETWORK "1.0.4" +#define ADDON_GLOBAL_VERSION_NETWORK_MIN "1.0.0" +#define ADDON_GLOBAL_VERSION_NETWORK_XML_ID "kodi.binary.global.network" +#define ADDON_GLOBAL_VERSION_NETWORK_DEPENDS "Network.h" \ + "c-api/network.h" + +#define ADDON_GLOBAL_VERSION_TOOLS "1.0.4" +#define ADDON_GLOBAL_VERSION_TOOLS_MIN "1.0.0" +#define ADDON_GLOBAL_VERSION_TOOLS_XML_ID "kodi.binary.global.tools" +#define ADDON_GLOBAL_VERSION_TOOLS_DEPENDS "tools/DllHelper.h" \ + "tools/EndTime.h" \ + "tools/StringUtils.h" \ + "tools/Thread.h" \ + "tools/Timer.h" + +#define ADDON_INSTANCE_VERSION_AUDIODECODER "3.0.0" +#define ADDON_INSTANCE_VERSION_AUDIODECODER_MIN "3.0.0" +#define ADDON_INSTANCE_VERSION_AUDIODECODER_XML_ID "kodi.binary.instance.audiodecoder" +#define ADDON_INSTANCE_VERSION_AUDIODECODER_DEPENDS "c-api/addon-instance/audio_decoder.h" \ + "addon-instance/AudioDecoder.h" + +#define ADDON_INSTANCE_VERSION_AUDIOENCODER "2.1.0" +#define ADDON_INSTANCE_VERSION_AUDIOENCODER_MIN "2.1.0" +#define ADDON_INSTANCE_VERSION_AUDIOENCODER_XML_ID "kodi.binary.instance.audioencoder" +#define ADDON_INSTANCE_VERSION_AUDIOENCODER_DEPENDS "c-api/addon-instance/audio_encoder.h" \ + "addon-instance/AudioEncoder.h" + +#define ADDON_INSTANCE_VERSION_GAME "2.1.0" +#define ADDON_INSTANCE_VERSION_GAME_MIN "2.1.0" +#define ADDON_INSTANCE_VERSION_GAME_XML_ID "kodi.binary.instance.game" +#define ADDON_INSTANCE_VERSION_GAME_DEPENDS "addon-instance/Game.h" + +#define ADDON_INSTANCE_VERSION_IMAGEDECODER "2.1.1" +#define ADDON_INSTANCE_VERSION_IMAGEDECODER_MIN "2.1.0" +#define ADDON_INSTANCE_VERSION_IMAGEDECODER_XML_ID "kodi.binary.instance.imagedecoder" +#define ADDON_INSTANCE_VERSION_IMAGEDECODER_DEPENDS "addon-instance/ImageDecoder.h" + +#define ADDON_INSTANCE_VERSION_INPUTSTREAM "2.3.4" +#define ADDON_INSTANCE_VERSION_INPUTSTREAM_MIN "2.3.4" +#define ADDON_INSTANCE_VERSION_INPUTSTREAM_XML_ID "kodi.binary.instance.inputstream" +#define ADDON_INSTANCE_VERSION_INPUTSTREAM_DEPENDS "addon-instance/Inputstream.h" + +#define ADDON_INSTANCE_VERSION_PERIPHERAL "2.0.0" +#define ADDON_INSTANCE_VERSION_PERIPHERAL_MIN "2.0.0" +#define ADDON_INSTANCE_VERSION_PERIPHERAL_XML_ID "kodi.binary.instance.peripheral" +#define ADDON_INSTANCE_VERSION_PERIPHERAL_DEPENDS "addon-instance/Peripheral.h" \ + "addon-instance/PeripheralUtils.h" + +#define ADDON_INSTANCE_VERSION_PVR "7.0.1" +#define ADDON_INSTANCE_VERSION_PVR_MIN "7.0.0" +#define ADDON_INSTANCE_VERSION_PVR_XML_ID "kodi.binary.instance.pvr" +#define ADDON_INSTANCE_VERSION_PVR_DEPENDS "c-api/addon-instance/pvr.h" \ + "c-api/addon-instance/pvr/pvr_channel_groups.h" \ + "c-api/addon-instance/pvr/pvr_channels.h" \ + "c-api/addon-instance/pvr/pvr_defines.h" \ + "c-api/addon-instance/pvr/pvr_edl.h" \ + "c-api/addon-instance/pvr/pvr_epg.h" \ + "c-api/addon-instance/pvr/pvr_general.h" \ + "c-api/addon-instance/pvr/pvr_menu_hook.h" \ + "c-api/addon-instance/pvr/pvr_recordings.h" \ + "c-api/addon-instance/pvr/pvr_stream.h" \ + "c-api/addon-instance/pvr/pvr_timers.h" \ + "addon-instance/PVR.h" \ + "addon-instance/pvr/ChannelGroups.h" \ + "addon-instance/pvr/Channels.h" \ + "addon-instance/pvr/EDL.h" \ + "addon-instance/pvr/EPG.h" \ + "addon-instance/pvr/General.h" \ + "addon-instance/pvr/MenuHook.h" \ + "addon-instance/pvr/Recordings.h" \ + "addon-instance/pvr/Stream.h" \ + "addon-instance/pvr/Timers.h" + +#define ADDON_INSTANCE_VERSION_SCREENSAVER "2.1.0" +#define ADDON_INSTANCE_VERSION_SCREENSAVER_MIN "2.1.0" +#define ADDON_INSTANCE_VERSION_SCREENSAVER_XML_ID "kodi.binary.instance.screensaver" +#define ADDON_INSTANCE_VERSION_SCREENSAVER_DEPENDS "c-api/addon-instance/screensaver.h" \ + "addon-instance/Screensaver.h" + +#define ADDON_INSTANCE_VERSION_VFS "3.0.0" +#define ADDON_INSTANCE_VERSION_VFS_MIN "3.0.0" +#define ADDON_INSTANCE_VERSION_VFS_XML_ID "kodi.binary.instance.vfs" +#define ADDON_INSTANCE_VERSION_VFS_DEPENDS "c-api/addon-instance/vfs.h" \ + "addon-instance/VFS.h" + +#define ADDON_INSTANCE_VERSION_VISUALIZATION "3.0.0" +#define ADDON_INSTANCE_VERSION_VISUALIZATION_MIN "3.0.0" +#define ADDON_INSTANCE_VERSION_VISUALIZATION_XML_ID "kodi.binary.instance.visualization" +#define ADDON_INSTANCE_VERSION_VISUALIZATION_DEPENDS "addon-instance/Visualization.h" \ + "c-api/addon-instance/visualization.h" + +#define ADDON_INSTANCE_VERSION_VIDEOCODEC "1.0.4" +#define ADDON_INSTANCE_VERSION_VIDEOCODEC_MIN "1.0.4" +#define ADDON_INSTANCE_VERSION_VIDEOCODEC_XML_ID "kodi.binary.instance.videocodec" +#define ADDON_INSTANCE_VERSION_VIDEOCODEC_DEPENDS "addon-instance/VideoCodec.h" \ + "StreamCodec.h" \ + "StreamCrypto.h" +// clang-format on + +//============================================================================== +/// +/// @ingroup cpp_kodi_addon_addonbase +/// The currently available instance types for Kodi add-ons +/// +/// \internal +/// @note For add of new types take a new number on end. To change +/// existing numbers can be make problems on already compiled add-ons. +/// \endinternal +/// +typedef enum ADDON_TYPE +{ + /* addon global parts */ + ADDON_GLOBAL_MAIN = 0, + ADDON_GLOBAL_GUI = 1, + ADDON_GLOBAL_AUDIOENGINE = 2, + ADDON_GLOBAL_GENERAL = 3, + ADDON_GLOBAL_NETWORK = 4, + ADDON_GLOBAL_FILESYSTEM = 5, + ADDON_GLOBAL_TOOLS = 6, + // Last used global id, used in loops to check versions. + // Need to change if new global type becomes added! + ADDON_GLOBAL_MAX = 6, + + /* addon type instances */ + + /// Audio decoder instance, see \ref cpp_kodi_addon_audiodecoder "kodi::addon::CInstanceAudioDecoder" + ADDON_INSTANCE_AUDIODECODER = 102, + + /// Audio encoder instance, see \ref cpp_kodi_addon_audioencoder "kodi::addon::CInstanceAudioEncoder" + ADDON_INSTANCE_AUDIOENCODER = 103, + + /// Game instance, see \ref cpp_kodi_addon_game "kodi::addon::CInstanceGame" + ADDON_INSTANCE_GAME = 104, + + /// Input stream instance, see \ref cpp_kodi_addon_inputstream "kodi::addon::CInstanceInputStream" + ADDON_INSTANCE_INPUTSTREAM = 105, + + /// Peripheral instance, see \ref cpp_kodi_addon_peripheral "kodi::addon::CInstancePeripheral" + ADDON_INSTANCE_PERIPHERAL = 106, + + /// Game instance, see \ref cpp_kodi_addon_pvr "kodi::addon::CInstancePVRClient" + ADDON_INSTANCE_PVR = 107, + + /// PVR client instance, see \ref cpp_kodi_addon_screensaver "kodi::addon::CInstanceScreensaver" + ADDON_INSTANCE_SCREENSAVER = 108, + + /// Music visualization instance, see \ref cpp_kodi_addon_visualization "kodi::addon::CInstanceVisualization" + ADDON_INSTANCE_VISUALIZATION = 109, + + /// Virtual Filesystem (VFS) instance, see \ref cpp_kodi_addon_vfs "kodi::addon::CInstanceVFS" + ADDON_INSTANCE_VFS = 110, + + /// Image Decoder instance, see \ref cpp_kodi_addon_imagedecoder "kodi::addon::CInstanceImageDecoder" + ADDON_INSTANCE_IMAGEDECODER = 111, + + /// Video Decoder instance, see \ref cpp_kodi_addon_videocodec "kodi::addon::CInstanceVideoCodec" + ADDON_INSTANCE_VIDEOCODEC = 112, +} ADDON_TYPE; +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +extern "C" { +namespace kodi { +namespace addon { +#endif + +/// +/// This is used from Kodi to get the active version of add-on parts. +/// It is compiled in add-on and also in Kodi itself, with this can be Kodi +/// compare the version from him with them on add-on. +/// +/// @param[in] type The with 'enum ADDON_TYPE' type to ask +/// @return version The current version of asked type +/// +inline const char* GetTypeVersion(int type) +{ + /* + * #ifdef's below becomes set by cmake, no set by hand needed. + */ + switch (type) + { + /* addon global parts */ + case ADDON_GLOBAL_MAIN: + return ADDON_GLOBAL_VERSION_MAIN; +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_GENERAL_USED) + case ADDON_GLOBAL_GENERAL: + return ADDON_GLOBAL_VERSION_GENERAL; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_GUI_USED) + case ADDON_GLOBAL_GUI: + return ADDON_GLOBAL_VERSION_GUI; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_AUDIOENGINE_USED) + case ADDON_GLOBAL_AUDIOENGINE: + return ADDON_GLOBAL_VERSION_AUDIOENGINE; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_FILESYSTEM_USED) + case ADDON_GLOBAL_FILESYSTEM: + return ADDON_GLOBAL_VERSION_FILESYSTEM; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_NETWORK_USED) + case ADDON_GLOBAL_NETWORK: + return ADDON_GLOBAL_VERSION_NETWORK; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_GLOBAL_VERSION_TOOLS_USED) + case ADDON_GLOBAL_TOOLS: + return ADDON_GLOBAL_VERSION_TOOLS; +#endif + + /* addon type instances */ +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_AUDIODECODER_USED) + case ADDON_INSTANCE_AUDIODECODER: + return ADDON_INSTANCE_VERSION_AUDIODECODER; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_AUDIOENCODER_USED) + case ADDON_INSTANCE_AUDIOENCODER: + return ADDON_INSTANCE_VERSION_AUDIOENCODER; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_GAME_USED) + case ADDON_INSTANCE_GAME: + return ADDON_INSTANCE_VERSION_GAME; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_IMAGEDECODER_USED) + case ADDON_INSTANCE_IMAGEDECODER: + return ADDON_INSTANCE_VERSION_IMAGEDECODER; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_INPUTSTREAM_USED) + case ADDON_INSTANCE_INPUTSTREAM: + return ADDON_INSTANCE_VERSION_INPUTSTREAM; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_PERIPHERAL_USED) + case ADDON_INSTANCE_PERIPHERAL: + return ADDON_INSTANCE_VERSION_PERIPHERAL; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_PVR_USED) + case ADDON_INSTANCE_PVR: + return ADDON_INSTANCE_VERSION_PVR; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_SCREENSAVER_USED) + case ADDON_INSTANCE_SCREENSAVER: + return ADDON_INSTANCE_VERSION_SCREENSAVER; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_VFS_USED) + case ADDON_INSTANCE_VFS: + return ADDON_INSTANCE_VERSION_VFS; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_VISUALIZATION_USED) + case ADDON_INSTANCE_VISUALIZATION: + return ADDON_INSTANCE_VERSION_VISUALIZATION; +#endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_VIDEOCODEC_USED) + case ADDON_INSTANCE_VIDEOCODEC: + return ADDON_INSTANCE_VERSION_VIDEOCODEC; +#endif + } + return "0.0.0"; +} + +/// +/// This is used from Kodi to get the minimum supported version of add-on parts. +/// It is compiled in add-on and also in Kodi itself, with this can be Kodi +/// compare the version from him with them on add-on. +/// +/// @param[in] type The with 'enum ADDON_TYPE' type to ask +/// @return version The minimum version of asked type +/// +inline const char* GetTypeMinVersion(int type) +{ + switch (type) + { + /* addon global parts */ + case ADDON_GLOBAL_MAIN: + return ADDON_GLOBAL_VERSION_MAIN_MIN; + case ADDON_GLOBAL_GUI: + return ADDON_GLOBAL_VERSION_GUI_MIN; + case ADDON_GLOBAL_GENERAL: + return ADDON_GLOBAL_VERSION_GENERAL_MIN; + case ADDON_GLOBAL_AUDIOENGINE: + return ADDON_GLOBAL_VERSION_AUDIOENGINE_MIN; + case ADDON_GLOBAL_FILESYSTEM: + return ADDON_GLOBAL_VERSION_FILESYSTEM_MIN; + case ADDON_GLOBAL_NETWORK: + return ADDON_GLOBAL_VERSION_NETWORK_MIN; + case ADDON_GLOBAL_TOOLS: + return ADDON_GLOBAL_VERSION_TOOLS_MIN; + + /* addon type instances */ + case ADDON_INSTANCE_AUDIODECODER: + return ADDON_INSTANCE_VERSION_AUDIODECODER_MIN; + case ADDON_INSTANCE_AUDIOENCODER: + return ADDON_INSTANCE_VERSION_AUDIOENCODER_MIN; + case ADDON_INSTANCE_GAME: + return ADDON_INSTANCE_VERSION_GAME_MIN; + case ADDON_INSTANCE_IMAGEDECODER: + return ADDON_INSTANCE_VERSION_IMAGEDECODER_MIN; + case ADDON_INSTANCE_INPUTSTREAM: + return ADDON_INSTANCE_VERSION_INPUTSTREAM_MIN; + case ADDON_INSTANCE_PERIPHERAL: + return ADDON_INSTANCE_VERSION_PERIPHERAL_MIN; + case ADDON_INSTANCE_PVR: + return ADDON_INSTANCE_VERSION_PVR_MIN; + case ADDON_INSTANCE_SCREENSAVER: + return ADDON_INSTANCE_VERSION_SCREENSAVER_MIN; + case ADDON_INSTANCE_VFS: + return ADDON_INSTANCE_VERSION_VFS_MIN; + case ADDON_INSTANCE_VISUALIZATION: + return ADDON_INSTANCE_VERSION_VISUALIZATION_MIN; + case ADDON_INSTANCE_VIDEOCODEC: + return ADDON_INSTANCE_VERSION_VIDEOCODEC_MIN; + } + return "0.0.0"; +} + +/// +/// Function used internally on add-on and in Kodi itself to get name +/// about given type. +/// +/// @param[in] type The with 'enum ADDON_TYPE' defined type to ask +/// @return Name of the asked instance type +/// +inline const char* GetTypeName(int type) +{ + switch (type) + { + /* addon global parts */ + case ADDON_GLOBAL_MAIN: + return "Addon"; + case ADDON_GLOBAL_GUI: + return "GUI"; + case ADDON_GLOBAL_GENERAL: + return "General"; + case ADDON_GLOBAL_AUDIOENGINE: + return "AudioEngine"; + case ADDON_GLOBAL_FILESYSTEM: + return "Filesystem"; + case ADDON_GLOBAL_NETWORK: + return "Network"; + case ADDON_GLOBAL_TOOLS: + return "Tools"; + + /* addon type instances */ + case ADDON_INSTANCE_AUDIODECODER: + return "AudioDecoder"; + case ADDON_INSTANCE_AUDIOENCODER: + return "AudioEncoder"; + case ADDON_INSTANCE_GAME: + return "Game"; + case ADDON_INSTANCE_IMAGEDECODER: + return "ImageDecoder"; + case ADDON_INSTANCE_INPUTSTREAM: + return "Inputstream"; + case ADDON_INSTANCE_PERIPHERAL: + return "Peripheral"; + case ADDON_INSTANCE_PVR: + return "PVR"; + case ADDON_INSTANCE_SCREENSAVER: + return "ScreenSaver"; + case ADDON_INSTANCE_VISUALIZATION: + return "Visualization"; + case ADDON_INSTANCE_VIDEOCODEC: + return "VideoCodec"; + } + return "unknown"; +} + +/// +/// Function used internally on add-on and in Kodi itself to get id number +/// about given type name. +/// +/// @param[in] name The type name string to ask +/// @return Id number of the asked instance type +/// +/// @warning String must be lower case here! +/// +inline int GetTypeId(const char* name) +{ + if (name) + { + if (strcmp(name, "addon") == 0) + return ADDON_GLOBAL_MAIN; + else if (strcmp(name, "general") == 0) + return ADDON_GLOBAL_GENERAL; + else if (strcmp(name, "gui") == 0) + return ADDON_GLOBAL_GUI; + else if (strcmp(name, "audioengine") == 0) + return ADDON_GLOBAL_AUDIOENGINE; + else if (strcmp(name, "filesystem") == 0) + return ADDON_GLOBAL_FILESYSTEM; + else if (strcmp(name, "network") == 0) + return ADDON_GLOBAL_NETWORK; + else if (strcmp(name, "tools") == 0) + return ADDON_GLOBAL_TOOLS; + else if (strcmp(name, "audiodecoder") == 0) + return ADDON_INSTANCE_AUDIODECODER; + else if (strcmp(name, "audioencoder") == 0) + return ADDON_INSTANCE_AUDIOENCODER; + else if (strcmp(name, "game") == 0) + return ADDON_INSTANCE_GAME; + else if (strcmp(name, "imagedecoder") == 0) + return ADDON_INSTANCE_IMAGEDECODER; + else if (strcmp(name, "inputstream") == 0) + return ADDON_INSTANCE_INPUTSTREAM; + else if (strcmp(name, "peripheral") == 0) + return ADDON_INSTANCE_PERIPHERAL; + else if (strcmp(name, "pvr") == 0) + return ADDON_INSTANCE_PVR; + else if (strcmp(name, "screensaver") == 0) + return ADDON_INSTANCE_SCREENSAVER; + else if (strcmp(name, "vfs") == 0) + return ADDON_INSTANCE_VFS; + else if (strcmp(name, "visualization") == 0) + return ADDON_INSTANCE_VISUALIZATION; + else if (strcmp(name, "videocodec") == 0) + return ADDON_INSTANCE_VIDEOCODEC; + } + return -1; +} + +#ifdef __cplusplus +} /* namespace addon */ +} /* namespace kodi */ +} /* extern "C" */ +#endif diff --git a/xbmc/cores/VideoPlayer/Interface/Addon/DemuxPacket.h b/xbmc/cores/VideoPlayer/Interface/Addon/DemuxPacket.h index 6da4838..7f3f85d 100644 --- a/xbmc/cores/VideoPlayer/Interface/Addon/DemuxPacket.h +++ b/xbmc/cores/VideoPlayer/Interface/Addon/DemuxPacket.h @@ -43,7 +43,7 @@ extern "C" int dispTime = 0; bool recoveryPoint = false; - std::shared_ptr cryptoInfo; + struct DemuxCryptoInfo* cryptoInfo = nullptr; } DemuxPacket; #ifdef __cplusplus diff --git a/xbmc/interfaces/json-rpc/schema/version.txt b/xbmc/interfaces/json-rpc/schema/version.txt index 6fb712b..f0bec16 100644 --- a/xbmc/interfaces/json-rpc/schema/version.txt +++ b/xbmc/interfaces/json-rpc/schema/version.txt @@ -1 +1 @@ -JSONRPC_VERSION 11.11.0 +JSONRPC_VERSION 11.15.0 diff --git a/xbmc/utils/ActorProtocol.cpp b/xbmc/utils/ActorProtocol.cpp new file mode 100644 index 0000000..f83d2fc --- /dev/null +++ b/xbmc/utils/ActorProtocol.cpp @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * See LICENSES/README.md for more information. + */ + +#include "ActorProtocol.h" + +#include "threads/Event.h" + +#include + +using namespace Actor; + +void Message::Release() +{ + bool skip; + origin.Lock(); + skip = isSync ? !isSyncFini : false; + isSyncFini = true; + origin.Unlock(); + + if (skip) + return; + + // free data buffer + if (data != buffer) + delete [] data; + + payloadObj.reset(); + + // delete event in case of sync message + delete event; + + origin.ReturnMessage(this); +} + +bool Message::Reply(int sig, void *data /* = NULL*/, size_t size /* = 0 */) +{ + if (!isSync) + { + if (isOut) + return origin.SendInMessage(sig, data, size); + else + return origin.SendOutMessage(sig, data, size); + } + + origin.Lock(); + + if (!isSyncTimeout) + { + Message *msg = origin.GetMessage(); + msg->signal = sig; + msg->isOut = !isOut; + replyMessage = msg; + if (data) + { + if (size > sizeof(msg->buffer)) + msg->data = new uint8_t[size]; + else + msg->data = msg->buffer; + memcpy(msg->data, data, size); + } + } + + origin.Unlock(); + + if (event) + event->Set(); + + return true; +} + +Protocol::~Protocol() +{ + Message *msg; + Purge(); + while (!freeMessageQueue.empty()) + { + msg = freeMessageQueue.front(); + freeMessageQueue.pop(); + delete msg; + } +} + +Message *Protocol::GetMessage() +{ + Message *msg; + + CSingleLock lock(criticalSection); + + if (!freeMessageQueue.empty()) + { + msg = freeMessageQueue.front(); + freeMessageQueue.pop(); + } + else + msg = new Message(*this); + + msg->isSync = false; + msg->isSyncFini = false; + msg->isSyncTimeout = false; + msg->event = NULL; + msg->data = NULL; + msg->payloadSize = 0; + msg->replyMessage = NULL; + + return msg; +} + +void Protocol::ReturnMessage(Message *msg) +{ + CSingleLock lock(criticalSection); + + freeMessageQueue.push(msg); +} + +bool Protocol::SendOutMessage(int signal, + const void* data /* = NULL */, + size_t size /* = 0 */, + Message* outMsg /* = NULL */) +{ + Message *msg; + if (outMsg) + msg = outMsg; + else + msg = GetMessage(); + + msg->signal = signal; + msg->isOut = true; + + if (data) + { + if (size > sizeof(msg->buffer)) + msg->data = new uint8_t[size]; + else + msg->data = msg->buffer; + memcpy(msg->data, data, size); + } + + { CSingleLock lock(criticalSection); + outMessages.push(msg); + } + if (containerOutEvent) + containerOutEvent->Set(); + + return true; +} + +bool Protocol::SendOutMessage(int signal, CPayloadWrapBase *payload, Message *outMsg) +{ + Message *msg; + if (outMsg) + msg = outMsg; + else + msg = GetMessage(); + + msg->signal = signal; + msg->isOut = true; + + msg->payloadObj.reset(payload); + + { CSingleLock lock(criticalSection); + outMessages.push(msg); + } + if (containerOutEvent) + containerOutEvent->Set(); + + return true; +} + +bool Protocol::SendInMessage(int signal, + const void* data /* = NULL */, + size_t size /* = 0 */, + Message* outMsg /* = NULL */) +{ + Message *msg; + if (outMsg) + msg = outMsg; + else + msg = GetMessage(); + + msg->signal = signal; + msg->isOut = false; + + if (data) + { + if (size > sizeof(msg->data)) + msg->data = new uint8_t[size]; + else + msg->data = msg->buffer; + memcpy(msg->data, data, size); + } + + { CSingleLock lock(criticalSection); + inMessages.push(msg); + } + if (containerInEvent) + containerInEvent->Set(); + + return true; +} + +bool Protocol::SendInMessage(int signal, CPayloadWrapBase *payload, Message *outMsg) +{ + Message *msg; + if (outMsg) + msg = outMsg; + else + msg = GetMessage(); + + msg->signal = signal; + msg->isOut = false; + + msg->payloadObj.reset(payload); + + { CSingleLock lock(criticalSection); + inMessages.push(msg); + } + if (containerInEvent) + containerInEvent->Set(); + + return true; +} + +bool Protocol::SendOutMessageSync( + int signal, Message** retMsg, int timeout, const void* data /* = NULL */, size_t size /* = 0 */) +{ + Message *msg = GetMessage(); + msg->isOut = true; + msg->isSync = true; + msg->event = new CEvent; + msg->event->Reset(); + SendOutMessage(signal, data, size, msg); + + if (!msg->event->WaitMSec(timeout)) + { + const CSingleLock lock(criticalSection); + if (msg->replyMessage) + *retMsg = msg->replyMessage; + else + { + *retMsg = NULL; + msg->isSyncTimeout = true; + } + } + else + *retMsg = msg->replyMessage; + + msg->Release(); + + if (*retMsg) + return true; + else + return false; +} + +bool Protocol::SendOutMessageSync(int signal, Message **retMsg, int timeout, CPayloadWrapBase *payload) +{ + Message *msg = GetMessage(); + msg->isOut = true; + msg->isSync = true; + msg->event = new CEvent; + msg->event->Reset(); + SendOutMessage(signal, payload, msg); + + if (!msg->event->WaitMSec(timeout)) + { + const CSingleLock lock(criticalSection); + if (msg->replyMessage) + *retMsg = msg->replyMessage; + else + { + *retMsg = NULL; + msg->isSyncTimeout = true; + } + } + else + *retMsg = msg->replyMessage; + + msg->Release(); + + if (*retMsg) + return true; + else + return false; +} + +bool Protocol::ReceiveOutMessage(Message **msg) +{ + CSingleLock lock(criticalSection); + + if (outMessages.empty() || outDefered) + return false; + + *msg = outMessages.front(); + outMessages.pop(); + + return true; +} + +bool Protocol::ReceiveInMessage(Message **msg) +{ + CSingleLock lock(criticalSection); + + if (inMessages.empty() || inDefered) + return false; + + *msg = inMessages.front(); + inMessages.pop(); + + return true; +} + + +void Protocol::Purge() +{ + Message *msg; + + while (ReceiveInMessage(&msg)) + msg->Release(); + + while (ReceiveOutMessage(&msg)) + msg->Release(); +} + +void Protocol::PurgeIn(int signal) +{ + Message *msg; + std::queue msgs; + + CSingleLock lock(criticalSection); + + while (!inMessages.empty()) + { + msg = inMessages.front(); + inMessages.pop(); + if (msg->signal != signal) + msgs.push(msg); + } + while (!msgs.empty()) + { + msg = msgs.front(); + msgs.pop(); + inMessages.push(msg); + } +} + +void Protocol::PurgeOut(int signal) +{ + Message *msg; + std::queue msgs; + + CSingleLock lock(criticalSection); + + while (!outMessages.empty()) + { + msg = outMessages.front(); + outMessages.pop(); + if (msg->signal != signal) + msgs.push(msg); + } + while (!msgs.empty()) + { + msg = msgs.front(); + msgs.pop(); + outMessages.push(msg); + } +} diff --git a/xbmc/utils/ActorProtocol.h b/xbmc/utils/ActorProtocol.h new file mode 100644 index 0000000..97297a6 --- /dev/null +++ b/xbmc/utils/ActorProtocol.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "threads/CriticalSection.h" + +#include +#include +#include +#include + +class CEvent; + +namespace Actor +{ + +class CPayloadWrapBase +{ +public: + virtual ~CPayloadWrapBase() = default; +}; + +template +class CPayloadWrap : public CPayloadWrapBase +{ +public: + ~CPayloadWrap() override = default; + CPayloadWrap(Payload *data) {m_pPayload.reset(data);}; + CPayloadWrap(Payload &data) {m_pPayload.reset(new Payload(data));}; + Payload *GetPlayload() {return m_pPayload.get();}; +protected: + std::unique_ptr m_pPayload; +}; + +class Protocol; + +class Message +{ + friend class Protocol; + + static constexpr size_t MSG_INTERNAL_BUFFER_SIZE = 32; + +public: + int signal; + bool isSync = false; + bool isSyncFini; + bool isOut; + bool isSyncTimeout; + size_t payloadSize; + uint8_t buffer[MSG_INTERNAL_BUFFER_SIZE]; + uint8_t *data = nullptr; + std::unique_ptr payloadObj; + Message *replyMessage = nullptr; + Protocol &origin; + CEvent *event = nullptr; + + void Release(); + bool Reply(int sig, void *data = nullptr, size_t size = 0); + +private: + explicit Message(Protocol &_origin) noexcept + :origin(_origin) {} +}; + +class Protocol +{ +public: + Protocol(std::string name, CEvent* inEvent, CEvent *outEvent) + :portName(name), containerInEvent(inEvent), containerOutEvent(outEvent) {} + Protocol(std::string name) + : Protocol(name, nullptr, nullptr) {} + ~Protocol(); + Message *GetMessage(); + void ReturnMessage(Message *msg); + bool SendOutMessage(int signal, + const void* data = nullptr, + size_t size = 0, + Message* outMsg = nullptr); + bool SendOutMessage(int signal, CPayloadWrapBase *payload, Message *outMsg = nullptr); + bool SendInMessage(int signal, + const void* data = nullptr, + size_t size = 0, + Message* outMsg = nullptr); + bool SendInMessage(int signal, CPayloadWrapBase *payload, Message *outMsg = nullptr); + bool SendOutMessageSync( + int signal, Message** retMsg, int timeout, const void* data = nullptr, size_t size = 0); + bool SendOutMessageSync(int signal, Message **retMsg, int timeout, CPayloadWrapBase *payload); + bool ReceiveOutMessage(Message **msg); + bool ReceiveInMessage(Message **msg); + void Purge(); + void PurgeIn(int signal); + void PurgeOut(int signal); + void DeferIn(bool value) {inDefered = value;}; + void DeferOut(bool value) {outDefered = value;}; + void Lock() {criticalSection.lock();}; + void Unlock() {criticalSection.unlock();}; + std::string portName; + +protected: + CEvent *containerInEvent, *containerOutEvent; + CCriticalSection criticalSection; + std::queue outMessages; + std::queue inMessages; + std::queue freeMessageQueue; + bool inDefered = false, outDefered = false; +}; + +} diff --git a/xbmc/utils/AlarmClock.cpp b/xbmc/utils/AlarmClock.cpp new file mode 100644 index 0000000..5e01243 --- /dev/null +++ b/xbmc/utils/AlarmClock.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "AlarmClock.h" + +#include "ServiceBroker.h" +#include "dialogs/GUIDialogKaiToast.h" +#include "events/EventLog.h" +#include "events/NotificationEvent.h" +#include "guilib/LocalizeStrings.h" +#include "log.h" +#include "messaging/ApplicationMessenger.h" +#include "threads/SingleLock.h" +#include "utils/StringUtils.h" + +#include + +using namespace KODI::MESSAGING; + +CAlarmClock::CAlarmClock() : CThread("AlarmClock") +{ +} + +CAlarmClock::~CAlarmClock() = default; + +void CAlarmClock::Start(const std::string& strName, float n_secs, const std::string& strCommand, bool bSilent /* false */, bool bLoop /* false */) +{ + // make lower case so that lookups are case-insensitive + std::string lowerName(strName); + StringUtils::ToLower(lowerName); + Stop(lowerName); + SAlarmClockEvent event; + event.m_fSecs = n_secs; + event.m_strCommand = strCommand; + event.m_loop = bLoop; + if (!m_bIsRunning) + { + StopThread(); + Create(); + m_bIsRunning = true; + } + + uint32_t labelAlarmClock; + uint32_t labelStarted; + if (StringUtils::EqualsNoCase(strName, "shutdowntimer")) + { + labelAlarmClock = 20144; + labelStarted = 20146; + } + else + { + labelAlarmClock = 13208; + labelStarted = 13210; + } + + EventPtr alarmClockActivity(new CNotificationEvent(labelAlarmClock, + StringUtils::Format(g_localizeStrings.Get(labelStarted).c_str(), static_cast(event.m_fSecs) / 60, static_cast(event.m_fSecs) % 60))); + if (bSilent) + CServiceBroker::GetEventLog().Add(alarmClockActivity); + else + CServiceBroker::GetEventLog().AddWithNotification(alarmClockActivity); + + event.watch.StartZero(); + CSingleLock lock(m_events); + m_event.insert(make_pair(lowerName,event)); + CLog::Log(LOGDEBUG,"started alarm with name: %s",lowerName.c_str()); +} + +void CAlarmClock::Stop(const std::string& strName, bool bSilent /* false */) +{ + CSingleLock lock(m_events); + + std::string lowerName(strName); + StringUtils::ToLower(lowerName); // lookup as lowercase only + std::map::iterator iter = m_event.find(lowerName); + + if (iter == m_event.end()) + return; + + uint32_t labelAlarmClock; + if (StringUtils::EqualsNoCase(strName, "shutdowntimer")) + labelAlarmClock = 20144; + else + labelAlarmClock = 13208; + + std::string strMessage; + float elapsed = 0.f; + + if (iter->second.watch.IsRunning()) + elapsed = iter->second.watch.GetElapsedSeconds(); + + if (elapsed > iter->second.m_fSecs) + strMessage = g_localizeStrings.Get(13211); + else + { + float remaining = static_cast(iter->second.m_fSecs - elapsed); + strMessage = StringUtils::Format(g_localizeStrings.Get(13212).c_str(), static_cast(remaining) / 60, static_cast(remaining) % 60); + } + + if (iter->second.m_strCommand.empty() || iter->second.m_fSecs > elapsed) + { + EventPtr alarmClockActivity(new CNotificationEvent(labelAlarmClock, strMessage)); + if (bSilent) + CServiceBroker::GetEventLog().Add(alarmClockActivity); + else + CServiceBroker::GetEventLog().AddWithNotification(alarmClockActivity); + } + else + { + CApplicationMessenger::GetInstance().PostMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, iter->second.m_strCommand); + if (iter->second.m_loop) + { + iter->second.watch.Reset(); + return; + } + } + + iter->second.watch.Stop(); + m_event.erase(iter); +} + +void CAlarmClock::Process() +{ + while( !m_bStop) + { + std::string strLast; + { + CSingleLock lock(m_events); + for (std::map::iterator iter=m_event.begin();iter != m_event.end(); ++iter) + if ( iter->second.watch.IsRunning() + && iter->second.watch.GetElapsedSeconds() >= iter->second.m_fSecs) + { + Stop(iter->first); + if ((iter = m_event.find(strLast)) == m_event.end()) + break; + } + else + strLast = iter->first; + } + CThread::Sleep(100); + } +} + diff --git a/xbmc/utils/AlarmClock.h b/xbmc/utils/AlarmClock.h new file mode 100644 index 0000000..e613595 --- /dev/null +++ b/xbmc/utils/AlarmClock.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "Stopwatch.h" +#include "threads/CriticalSection.h" +#include "threads/Thread.h" + +#include +#include + +struct SAlarmClockEvent +{ + CStopWatch watch; + double m_fSecs; + std::string m_strCommand; + bool m_loop; +}; + +class CAlarmClock : public CThread +{ +public: + CAlarmClock(); + ~CAlarmClock() override; + void Start(const std::string& strName, float n_secs, const std::string& strCommand, bool bSilent = false, bool bLoop = false); + inline bool IsRunning() const + { + return m_bIsRunning; + } + + inline bool HasAlarm(const std::string& strName) + { + // note: strName should be lower case only here + // No point checking it at the moment due to it only being called + // from GUIInfoManager (which is always lowercase) + // CLog::Log(LOGDEBUG,"checking for %s",strName.c_str()); + return (m_event.find(strName) != m_event.end()); + } + + double GetRemaining(const std::string& strName) + { + std::map::iterator iter; + if ((iter=m_event.find(strName)) != m_event.end()) + { + return iter->second.m_fSecs-(iter->second.watch.IsRunning() ? iter->second.watch.GetElapsedSeconds() : 0.f); + } + + return 0.f; + } + + void Stop(const std::string& strName, bool bSilent = false); + void Process() override; +private: + std::map m_event; + CCriticalSection m_events; + + bool m_bIsRunning = false; +}; + +extern CAlarmClock g_alarmClock; + diff --git a/xbmc/utils/AliasShortcutUtils.cpp b/xbmc/utils/AliasShortcutUtils.cpp new file mode 100644 index 0000000..001bc43 --- /dev/null +++ b/xbmc/utils/AliasShortcutUtils.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2009-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#if defined(TARGET_DARWIN_OSX) +#include "utils/URIUtils.h" +#include "platform/darwin/DarwinUtils.h" +#elif defined(TARGET_POSIX) +#else +#endif + +#include "AliasShortcutUtils.h" +#include "utils/log.h" + +bool IsAliasShortcut(const std::string& path, bool isdirectory) +{ + bool rtn = false; + +#if defined(TARGET_DARWIN_OSX) + // Note: regular files that have an .alias extension can be + // reported as an alias when clearly, they are not. Trap them out. + if (!URIUtils::HasExtension(path, ".alias"))//! @todo - check if this is still needed with the new API + { + rtn = CDarwinUtils::IsAliasShortcut(path, isdirectory); + } +#elif defined(TARGET_POSIX) + // Linux does not use alias or shortcut methods +#elif defined(TARGET_WINDOWS) +/* Needs testing under Windows platform so ignore shortcuts for now + if (CUtil::GetExtension(path) == ".lnk") + { + rtn = true; + } +*/ +#endif + return(rtn); +} + +void TranslateAliasShortcut(std::string& path) +{ +#if defined(TARGET_DARWIN_OSX) + CDarwinUtils::TranslateAliasShortcut(path); +#elif defined(TARGET_POSIX) + // Linux does not use alias or shortcut methods +#elif defined(TARGET_WINDOWS_STORE) + // Win10 does not use alias or shortcut methods + CLog::Log(LOGDEBUG, "%s is not implemented", __FUNCTION__); +#elif defined(TARGET_WINDOWS) +/* Needs testing under Windows platform so ignore shortcuts for now + CComPtr ipShellLink; + + // Get a pointer to the IShellLink interface + if (NOERROR == CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&ipShellLink)) + WCHAR wszTemp[MAX_PATH]; + + // Get a pointer to the IPersistFile interface + CComQIPtr ipPersistFile(ipShellLink); + + // IPersistFile is using LPCOLESTR so make sure that the string is Unicode +#if !defined _UNICODE + MultiByteToWideChar(CP_ACP, 0, lpszShortcutPath, -1, wszTemp, MAX_PATH); +#else + wcsncpy(wszTemp, lpszShortcutPath, MAX_PATH); +#endif + + // Open the shortcut file and initialize it from its contents + if (NOERROR == ipPersistFile->Load(wszTemp, STGM_READ)) + { + // Try to find the target of a shortcut even if it has been moved or renamed + if (NOERROR == ipShellLink->Resolve(NULL, SLR_UPDATE)) + { + WIN32_FIND_DATA wfd; + TCHAR real_path[PATH_MAX]; + // Get the path to the shortcut target + if (NOERROR == ipShellLink->GetPath(real_path, MAX_PATH, &wfd, SLGP_RAWPATH)) + { + // Get the description of the target + TCHAR szDesc[MAX_PATH]; + if (NOERROR == ipShellLink->GetDescription(szDesc, MAX_PATH)) + { + path = real_path; + } + } + } + } + } +*/ +#endif +} diff --git a/xbmc/utils/AliasShortcutUtils.h b/xbmc/utils/AliasShortcutUtils.h new file mode 100644 index 0000000..524c8f0 --- /dev/null +++ b/xbmc/utils/AliasShortcutUtils.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2009-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +bool IsAliasShortcut(const std::string& path, bool isdirectory); +void TranslateAliasShortcut(std::string &path); diff --git a/xbmc/utils/Archive.cpp b/xbmc/utils/Archive.cpp new file mode 100644 index 0000000..1b8392b --- /dev/null +++ b/xbmc/utils/Archive.cpp @@ -0,0 +1,461 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Archive.h" + +#include "IArchivable.h" +#include "filesystem/File.h" +#include "utils/Variant.h" +#include "utils/log.h" + +#include +#include +#include +#include + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wlong-long" +#endif + +using namespace XFILE; + +//arbitrarily chosen, should be plenty big enough for our strings +//without causing random bad things happening +//not very bad, just tiny bad +#define MAX_STRING_SIZE 100*1024*1024 + +CArchive::CArchive(CFile* pFile, int mode) +{ + m_pFile = pFile; + m_iMode = mode; + + m_pBuffer = std::unique_ptr(new uint8_t[CARCHIVE_BUFFER_MAX]); + memset(m_pBuffer.get(), 0, CARCHIVE_BUFFER_MAX); + if (mode == load) + { + m_BufferPos = m_pBuffer.get() + CARCHIVE_BUFFER_MAX; + m_BufferRemain = 0; + } + else + { + m_BufferPos = m_pBuffer.get(); + m_BufferRemain = CARCHIVE_BUFFER_MAX; + } +} + +CArchive::~CArchive() +{ + FlushBuffer(); +} + +void CArchive::Close() +{ + FlushBuffer(); +} + +bool CArchive::IsLoading() const +{ + return (m_iMode == load); +} + +bool CArchive::IsStoring() const +{ + return (m_iMode == store); +} + +CArchive& CArchive::operator<<(float f) +{ + return streamout(&f, sizeof(f)); +} + +CArchive& CArchive::operator<<(double d) +{ + return streamout(&d, sizeof(d)); +} + +CArchive& CArchive::operator<<(short int s) +{ + return streamout(&s, sizeof(s)); +} + +CArchive& CArchive::operator<<(unsigned short int us) +{ + return streamout(&us, sizeof(us)); +} + +CArchive& CArchive::operator<<(int i) +{ + return streamout(&i, sizeof(i)); +} + +CArchive& CArchive::operator<<(unsigned int ui) +{ + return streamout(&ui, sizeof(ui)); +} + +CArchive& CArchive::operator<<(long int l) +{ + return streamout(&l, sizeof(l)); +} + +CArchive& CArchive::operator<<(unsigned long int ul) +{ + return streamout(&ul, sizeof(ul)); +} + +CArchive& CArchive::operator<<(long long int ll) +{ + return streamout(&ll, sizeof(ll)); +} + +CArchive& CArchive::operator<<(unsigned long long int ull) +{ + return streamout(&ull, sizeof(ull)); +} + +CArchive& CArchive::operator<<(bool b) +{ + return streamout(&b, sizeof(b)); +} + +CArchive& CArchive::operator<<(char c) +{ + return streamout(&c, sizeof(c)); +} + +CArchive& CArchive::operator<<(const std::string& str) +{ + auto size = static_cast(str.size()); + if (size > MAX_STRING_SIZE) + throw std::out_of_range("String too large, over 100MB"); + + *this << size; + + return streamout(str.data(), size * sizeof(char)); +} + +CArchive& CArchive::operator<<(const std::wstring& wstr) +{ + if (wstr.size() > MAX_STRING_SIZE) + throw std::out_of_range("String too large, over 100MB"); + + auto size = static_cast(wstr.size()); + + *this << size; + + return streamout(wstr.data(), size * sizeof(wchar_t)); +} + +CArchive& CArchive::operator<<(const KODI::TIME::SystemTime& time) +{ + return streamout(&time, sizeof(KODI::TIME::SystemTime)); +} + +CArchive& CArchive::operator<<(IArchivable& obj) +{ + obj.Archive(*this); + + return *this; +} + +CArchive& CArchive::operator<<(const CVariant& variant) +{ + *this << static_cast(variant.type()); + switch (variant.type()) + { + case CVariant::VariantTypeInteger: + *this << variant.asInteger(); + break; + case CVariant::VariantTypeUnsignedInteger: + *this << variant.asUnsignedInteger(); + break; + case CVariant::VariantTypeBoolean: + *this << variant.asBoolean(); + break; + case CVariant::VariantTypeString: + *this << variant.asString(); + break; + case CVariant::VariantTypeWideString: + *this << variant.asWideString(); + break; + case CVariant::VariantTypeDouble: + *this << variant.asDouble(); + break; + case CVariant::VariantTypeArray: + *this << variant.size(); + for (auto i = variant.begin_array(); i != variant.end_array(); ++i) + *this << *i; + break; + case CVariant::VariantTypeObject: + *this << variant.size(); + for (auto itr = variant.begin_map(); itr != variant.end_map(); ++itr) + { + *this << itr->first; + *this << itr->second; + } + break; + case CVariant::VariantTypeNull: + case CVariant::VariantTypeConstNull: + default: + break; + } + + return *this; +} + +CArchive& CArchive::operator<<(const std::vector& strArray) +{ + if (std::numeric_limits::max() < strArray.size()) + throw std::out_of_range("Array too large, over 2^32 in size"); + + *this << static_cast(strArray.size()); + + for (auto&& item : strArray) + *this << item; + + return *this; +} + +CArchive& CArchive::operator<<(const std::vector& iArray) +{ + if (std::numeric_limits::max() < iArray.size()) + throw std::out_of_range("Array too large, over 2^32 in size"); + + *this << static_cast(iArray.size()); + + for (auto&& item : iArray) + *this << item; + + return *this; +} + +CArchive& CArchive::operator>>(std::string& str) +{ + uint32_t iLength = 0; + *this >> iLength; + + if (iLength > MAX_STRING_SIZE) + throw std::out_of_range("String too large, over 100MB"); + + auto s = std::unique_ptr(new char[iLength]); + streamin(s.get(), iLength * sizeof(char)); + str.assign(s.get(), iLength); + + return *this; +} + +CArchive& CArchive::operator>>(std::wstring& wstr) +{ + uint32_t iLength = 0; + *this >> iLength; + + if (iLength > MAX_STRING_SIZE) + throw std::out_of_range("String too large, over 100MB"); + + auto p = std::unique_ptr(new wchar_t[iLength]); + streamin(p.get(), iLength * sizeof(wchar_t)); + wstr.assign(p.get(), iLength); + + return *this; +} + +CArchive& CArchive::operator>>(KODI::TIME::SystemTime& time) +{ + return streamin(&time, sizeof(KODI::TIME::SystemTime)); +} + +CArchive& CArchive::operator>>(IArchivable& obj) +{ + obj.Archive(*this); + + return *this; +} + +CArchive& CArchive::operator>>(CVariant& variant) +{ + int type; + *this >> type; + variant = CVariant(static_cast(type)); + + switch (variant.type()) + { + case CVariant::VariantTypeInteger: + { + int64_t value; + *this >> value; + variant = value; + break; + } + case CVariant::VariantTypeUnsignedInteger: + { + uint64_t value; + *this >> value; + variant = value; + break; + } + case CVariant::VariantTypeBoolean: + { + bool value; + *this >> value; + variant = value; + break; + } + case CVariant::VariantTypeString: + { + std::string value; + *this >> value; + variant = value; + break; + } + case CVariant::VariantTypeWideString: + { + std::wstring value; + *this >> value; + variant = value; + break; + } + case CVariant::VariantTypeDouble: + { + double value; + *this >> value; + variant = value; + break; + } + case CVariant::VariantTypeArray: + { + unsigned int size; + *this >> size; + for (; size > 0; size--) + { + CVariant value; + *this >> value; + variant.append(value); + } + break; + } + case CVariant::VariantTypeObject: + { + unsigned int size; + *this >> size; + for (; size > 0; size--) + { + std::string name; + CVariant value; + *this >> name; + *this >> value; + variant[name] = value; + } + break; + } + case CVariant::VariantTypeNull: + case CVariant::VariantTypeConstNull: + default: + break; + } + + return *this; +} + +CArchive& CArchive::operator>>(std::vector& strArray) +{ + uint32_t size; + *this >> size; + strArray.clear(); + for (uint32_t index = 0; index < size; index++) + { + std::string str; + *this >> str; + strArray.push_back(std::move(str)); + } + + return *this; +} + +CArchive& CArchive::operator>>(std::vector& iArray) +{ + uint32_t size; + *this >> size; + iArray.clear(); + for (uint32_t index = 0; index < size; index++) + { + int i; + *this >> i; + iArray.push_back(i); + } + + return *this; +} + +void CArchive::FlushBuffer() +{ + if (m_iMode == store && m_BufferPos != m_pBuffer.get()) + { + if (m_pFile->Write(m_pBuffer.get(), m_BufferPos - m_pBuffer.get()) != m_BufferPos - m_pBuffer.get()) + CLog::Log(LOGERROR, "%s: Error flushing buffer", __FUNCTION__); + else + { + m_BufferPos = m_pBuffer.get(); + m_BufferRemain = CARCHIVE_BUFFER_MAX; + } + } +} + +CArchive &CArchive::streamout_bufferwrap(const uint8_t *ptr, size_t size) +{ + do + { + auto chunkSize = std::min(size, m_BufferRemain); + m_BufferPos = std::copy(ptr, ptr + chunkSize, m_BufferPos); + ptr += chunkSize; + size -= chunkSize; + m_BufferRemain -= chunkSize; + if (m_BufferRemain == 0) + FlushBuffer(); + } while (size > 0); + return *this; +} + +void CArchive::FillBuffer() +{ + if (m_iMode == load && m_BufferRemain == 0) + { + auto read = m_pFile->Read(m_pBuffer.get(), CARCHIVE_BUFFER_MAX); + if (read > 0) + { + m_BufferRemain = read; + m_BufferPos = m_pBuffer.get(); + } + } +} + +CArchive &CArchive::streamin_bufferwrap(uint8_t *ptr, size_t size) +{ + auto orig_ptr = ptr; + auto orig_size = size; + do + { + if (m_BufferRemain == 0) + { + FillBuffer(); + if (m_BufferRemain < CARCHIVE_BUFFER_MAX && m_BufferRemain < size) + { + CLog::Log(LOGERROR, "%s: can't stream in: requested %lu bytes, was read %lu bytes", __FUNCTION__, + static_cast(orig_size), static_cast(ptr - orig_ptr + m_BufferRemain)); + + memset(orig_ptr, 0, orig_size); + return *this; + } + } + auto chunkSize = std::min(size, m_BufferRemain); + ptr = std::copy(m_BufferPos, m_BufferPos + chunkSize, ptr); + m_BufferPos += chunkSize; + m_BufferRemain -= chunkSize; + size -= chunkSize; + } while (size > 0); + return *this; +} diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h new file mode 100644 index 0000000..f8c7513 --- /dev/null +++ b/xbmc/utils/Archive.h @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "XBDateTime.h" + +#include +#include +#include + +#define CARCHIVE_BUFFER_MAX 4096 + +namespace XFILE +{ + class CFile; +} +class CVariant; +class IArchivable; + +class CArchive +{ +public: + CArchive(XFILE::CFile* pFile, int mode); + ~CArchive(); + + /* CArchive support storing and loading of all C basic integer types + * C basic types was chosen instead of fixed size ints (int16_t - int64_t) to support all integer typedefs + * For example size_t can be typedef of unsigned int, long or long long depending on platform + * while int32_t and int64_t are usually unsigned short, int or long long, but not long + * and even if int and long can have same binary representation they are different types for compiler + * According to section 5.2.4.2.1 of C99 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf + * minimal size of short int is 16 bits + * minimal size of int is 16 bits (usually 32 or 64 bits, larger or equal to short int) + * minimal size of long int is 32 bits (larger or equal to int) + * minimal size of long long int is 64 bits (larger or equal to long int) */ + // storing + CArchive& operator<<(float f); + CArchive& operator<<(double d); + CArchive& operator<<(short int s); + CArchive& operator<<(unsigned short int us); + CArchive& operator<<(int i); + CArchive& operator<<(unsigned int ui); + CArchive& operator<<(long int l); + CArchive& operator<<(unsigned long int ul); + CArchive& operator<<(long long int ll); + CArchive& operator<<(unsigned long long int ull); + CArchive& operator<<(bool b); + CArchive& operator<<(char c); + CArchive& operator<<(const std::string &str); + CArchive& operator<<(const std::wstring& wstr); + CArchive& operator<<(const KODI::TIME::SystemTime& time); + CArchive& operator<<(IArchivable& obj); + CArchive& operator<<(const CVariant& variant); + CArchive& operator<<(const std::vector& strArray); + CArchive& operator<<(const std::vector& iArray); + + // loading + inline CArchive& operator>>(float& f) + { + return streamin(&f, sizeof(f)); + } + + inline CArchive& operator>>(double& d) + { + return streamin(&d, sizeof(d)); + } + + inline CArchive& operator>>(short int& s) + { + return streamin(&s, sizeof(s)); + } + + inline CArchive& operator>>(unsigned short int& us) + { + return streamin(&us, sizeof(us)); + } + + inline CArchive& operator>>(int& i) + { + return streamin(&i, sizeof(i)); + } + + inline CArchive& operator>>(unsigned int& ui) + { + return streamin(&ui, sizeof(ui)); + } + + inline CArchive& operator>>(long int& l) + { + return streamin(&l, sizeof(l)); + } + + inline CArchive& operator>>(unsigned long int& ul) + { + return streamin(&ul, sizeof(ul)); + } + + inline CArchive& operator>>(long long int& ll) + { + return streamin(&ll, sizeof(ll)); + } + + inline CArchive& operator>>(unsigned long long int& ull) + { + return streamin(&ull, sizeof(ull)); + } + + inline CArchive& operator>>(bool& b) + { + return streamin(&b, sizeof(b)); + } + + inline CArchive& operator>>(char& c) + { + return streamin(&c, sizeof(c)); + } + + CArchive& operator>>(std::string &str); + CArchive& operator>>(std::wstring& wstr); + CArchive& operator>>(KODI::TIME::SystemTime& time); + CArchive& operator>>(IArchivable& obj); + CArchive& operator>>(CVariant& variant); + CArchive& operator>>(std::vector& strArray); + CArchive& operator>>(std::vector& iArray); + + bool IsLoading() const; + bool IsStoring() const; + + void Close(); + + enum Mode {load = 0, store}; + +protected: + inline CArchive &streamout(const void *dataPtr, size_t size) + { + auto ptr = static_cast(dataPtr); + /* Note, the buffer is flushed as soon as it is full (m_BufferRemain == size) rather + * than waiting until we attempt to put more data into an already full buffer */ + if (m_BufferRemain > size) + { + memcpy(m_BufferPos, ptr, size); + m_BufferPos += size; + m_BufferRemain -= size; + return *this; + } + + return streamout_bufferwrap(ptr, size); + } + + inline CArchive &streamin(void *dataPtr, size_t size) + { + auto ptr = static_cast(dataPtr); + /* Note, refilling the buffer is deferred until we know we need to read more from it */ + if (m_BufferRemain >= size) + { + memcpy(ptr, m_BufferPos, size); + m_BufferPos += size; + m_BufferRemain -= size; + return *this; + } + + return streamin_bufferwrap(ptr, size); + } + + XFILE::CFile* m_pFile; //non-owning + int m_iMode; + std::unique_ptr m_pBuffer; + uint8_t *m_BufferPos; + size_t m_BufferRemain; + +private: + void FlushBuffer(); + CArchive &streamout_bufferwrap(const uint8_t *ptr, size_t size); + void FillBuffer(); + CArchive &streamin_bufferwrap(uint8_t *ptr, size_t size); +}; diff --git a/xbmc/utils/Base64.cpp b/xbmc/utils/Base64.cpp new file mode 100644 index 0000000..6b41519 --- /dev/null +++ b/xbmc/utils/Base64.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2011-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Base64.h" + +#define PADDING '=' + +const std::string Base64::m_characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +void Base64::Encode(const char* input, unsigned int length, std::string &output) +{ + if (input == NULL || length == 0) + return; + + long l; + output.clear(); + output.reserve(((length + 2) / 3) * 4); + + for (unsigned int i = 0; i < length; i += 3) + { + l = ((((unsigned long) input[i]) << 16) & 0xFFFFFF) | + ((((i + 1) < length) ? (((unsigned long) input[i + 1]) << 8) : 0) & 0xFFFF) | + ((((i + 2) < length) ? (((unsigned long) input[i + 2]) << 0) : 0) & 0x00FF); + + output.push_back(m_characters[(l >> 18) & 0x3F]); + output.push_back(m_characters[(l >> 12) & 0x3F]); + + if (i + 1 < length) + output.push_back(m_characters[(l >> 6) & 0x3F]); + if (i + 2 < length) + output.push_back(m_characters[(l >> 0) & 0x3F]); + } + + int left = 3 - (length % 3); + + if (length % 3) + { + for (int i = 0; i < left; i++) + output.push_back(PADDING); + } +} + +std::string Base64::Encode(const char* input, unsigned int length) +{ + std::string output; + Encode(input, length, output); + + return output; +} + +void Base64::Encode(const std::string &input, std::string &output) +{ + Encode(input.c_str(), input.size(), output); +} + +std::string Base64::Encode(const std::string &input) +{ + std::string output; + Encode(input, output); + + return output; +} + +void Base64::Decode(const char* input, unsigned int length, std::string &output) +{ + if (input == NULL || length == 0) + return; + + long l; + output.clear(); + + for (unsigned int index = 0; index < length; index++) + { + if (input[index] == '=') + { + length = index; + break; + } + } + + output.reserve(length - ((length + 2) / 4)); + + for (unsigned int i = 0; i < length; i += 4) + { + l = ((((unsigned long) m_characters.find(input[i])) & 0x3F) << 18); + l |= (((i + 1) < length) ? ((((unsigned long) m_characters.find(input[i + 1])) & 0x3F) << 12) : 0); + l |= (((i + 2) < length) ? ((((unsigned long) m_characters.find(input[i + 2])) & 0x3F) << 6) : 0); + l |= (((i + 3) < length) ? ((((unsigned long) m_characters.find(input[i + 3])) & 0x3F) << 0) : 0); + + output.push_back((char)((l >> 16) & 0xFF)); + if (i + 2 < length) + output.push_back((char)((l >> 8) & 0xFF)); + if (i + 3 < length) + output.push_back((char)((l >> 0) & 0xFF)); + } +} + +std::string Base64::Decode(const char* input, unsigned int length) +{ + std::string output; + Decode(input, length, output); + + return output; +} + +void Base64::Decode(const std::string &input, std::string &output) +{ + size_t length = input.find_first_of(PADDING); + if (length == std::string::npos) + length = input.size(); + + Decode(input.c_str(), length, output); +} + +std::string Base64::Decode(const std::string &input) +{ + std::string output; + Decode(input, output); + + return output; +} diff --git a/xbmc/utils/Base64.h b/xbmc/utils/Base64.h new file mode 100644 index 0000000..4b645ee --- /dev/null +++ b/xbmc/utils/Base64.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2011-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +class Base64 +{ +public: + static void Encode(const char* input, unsigned int length, std::string &output); + static std::string Encode(const char* input, unsigned int length); + static void Encode(const std::string &input, std::string &output); + static std::string Encode(const std::string &input); + static void Decode(const char* input, unsigned int length, std::string &output); + static std::string Decode(const char* input, unsigned int length); + static void Decode(const std::string &input, std::string &output); + static std::string Decode(const std::string &input); + +private: + static const std::string m_characters; +}; diff --git a/xbmc/utils/BitstreamConverter.cpp b/xbmc/utils/BitstreamConverter.cpp new file mode 100644 index 0000000..011a1e4 --- /dev/null +++ b/xbmc/utils/BitstreamConverter.cpp @@ -0,0 +1,1219 @@ +/* + * Copyright (C) 2010-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/log.h" + +#include + +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif + +#include "BitstreamConverter.h" +#include "BitstreamReader.h" +#include "BitstreamWriter.h" + +#include + +enum { + AVC_NAL_SLICE=1, + AVC_NAL_DPA, + AVC_NAL_DPB, + AVC_NAL_DPC, + AVC_NAL_IDR_SLICE, + AVC_NAL_SEI, + AVC_NAL_SPS, + AVC_NAL_PPS, + AVC_NAL_AUD, + AVC_NAL_END_SEQUENCE, + AVC_NAL_END_STREAM, + AVC_NAL_FILLER_DATA, + AVC_NAL_SPS_EXT, + AVC_NAL_AUXILIARY_SLICE=19 +}; + +enum { + HEVC_NAL_TRAIL_N = 0, + HEVC_NAL_TRAIL_R = 1, + HEVC_NAL_TSA_N = 2, + HEVC_NAL_TSA_R = 3, + HEVC_NAL_STSA_N = 4, + HEVC_NAL_STSA_R = 5, + HEVC_NAL_RADL_N = 6, + HEVC_NAL_RADL_R = 7, + HEVC_NAL_RASL_N = 8, + HEVC_NAL_RASL_R = 9, + HEVC_NAL_BLA_W_LP = 16, + HEVC_NAL_BLA_W_RADL = 17, + HEVC_NAL_BLA_N_LP = 18, + HEVC_NAL_IDR_W_RADL = 19, + HEVC_NAL_IDR_N_LP = 20, + HEVC_NAL_CRA_NUT = 21, + HEVC_NAL_VPS = 32, + HEVC_NAL_SPS = 33, + HEVC_NAL_PPS = 34, + HEVC_NAL_AUD = 35, + HEVC_NAL_EOS_NUT = 36, + HEVC_NAL_EOB_NUT = 37, + HEVC_NAL_FD_NUT = 38, + HEVC_NAL_SEI_PREFIX = 39, + HEVC_NAL_SEI_SUFFIX = 40 +}; + +enum { + SEI_BUFFERING_PERIOD = 0, + SEI_PIC_TIMING, + SEI_PAN_SCAN_RECT, + SEI_FILLER_PAYLOAD, + SEI_USER_DATA_REGISTERED_ITU_T_T35, + SEI_USER_DATA_UNREGISTERED, + SEI_RECOVERY_POINT, + SEI_DEC_REF_PIC_MARKING_REPETITION, + SEI_SPARE_PIC, + SEI_SCENE_INFO, + SEI_SUB_SEQ_INFO, + SEI_SUB_SEQ_LAYER_CHARACTERISTICS, + SEI_SUB_SEQ_CHARACTERISTICS, + SEI_FULL_FRAME_FREEZE, + SEI_FULL_FRAME_FREEZE_RELEASE, + SEI_FULL_FRAME_SNAPSHOT, + SEI_PROGRESSIVE_REFINEMENT_SEGMENT_START, + SEI_PROGRESSIVE_REFINEMENT_SEGMENT_END, + SEI_MOTION_CONSTRAINED_SLICE_GROUP_SET, + SEI_FILM_GRAIN_CHARACTERISTICS, + SEI_DEBLOCKING_FILTER_DISPLAY_PREFERENCE, + SEI_STEREO_VIDEO_INFO, + SEI_POST_FILTER_HINTS, + SEI_TONE_MAPPING +}; + +/* + * GStreamer h264 parser + * Copyright (C) 2005 Michal Benes + * (C) 2008 Wim Taymans + * gsth264parse.c + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * See LICENSES/README.md for more information. + */ +static void nal_bs_init(nal_bitstream *bs, const uint8_t *data, size_t size) +{ + bs->data = data; + bs->end = data + size; + bs->head = 0; + // fill with something other than 0 to detect + // emulation prevention bytes + bs->cache = 0xffffffff; +} + +static uint32_t nal_bs_read(nal_bitstream *bs, int n) +{ + uint32_t res = 0; + int shift; + + if (n == 0) + return res; + + // fill up the cache if we need to + while (bs->head < n) + { + uint8_t a_byte; + bool check_three_byte; + + check_three_byte = true; +next_byte: + if (bs->data >= bs->end) + { + // we're at the end, can't produce more than head number of bits + n = bs->head; + break; + } + // get the byte, this can be an emulation_prevention_three_byte that we need + // to ignore. + a_byte = *bs->data++; + if (check_three_byte && a_byte == 0x03 && ((bs->cache & 0xffff) == 0)) + { + // next byte goes unconditionally to the cache, even if it's 0x03 + check_three_byte = false; + goto next_byte; + } + // shift bytes in cache, moving the head bits of the cache left + bs->cache = (bs->cache << 8) | a_byte; + bs->head += 8; + } + + // bring the required bits down and truncate + if ((shift = bs->head - n) > 0) + res = static_cast(bs->cache >> shift); + else + res = static_cast(bs->cache); + + // mask out required bits + if (n < 32) + res &= (1 << n) - 1; + bs->head = shift; + + return res; +} + +static bool nal_bs_eos(nal_bitstream *bs) +{ + return (bs->data >= bs->end) && (bs->head == 0); +} + +// read unsigned Exp-Golomb code +static int nal_bs_read_ue(nal_bitstream *bs) +{ + int i = 0; + + while (nal_bs_read(bs, 1) == 0 && !nal_bs_eos(bs) && i < 31) + i++; + + return ((1 << i) - 1 + nal_bs_read(bs, i)); +} + +static const uint8_t* avc_find_startcode_internal(const uint8_t *p, const uint8_t *end) +{ + const uint8_t *a = p + 4 - ((intptr_t)p & 3); + + for (end -= 3; p < a && p < end; p++) + { + if (p[0] == 0 && p[1] == 0 && p[2] == 1) + return p; + } + + for (end -= 3; p < end; p += 4) + { + uint32_t x = *(const uint32_t*)p; + if ((x - 0x01010101) & (~x) & 0x80808080) // generic + { + if (p[1] == 0) + { + if (p[0] == 0 && p[2] == 1) + return p; + if (p[2] == 0 && p[3] == 1) + return p+1; + } + if (p[3] == 0) + { + if (p[2] == 0 && p[4] == 1) + return p+2; + if (p[4] == 0 && p[5] == 1) + return p+3; + } + } + } + + for (end += 3; p < end; p++) + { + if (p[0] == 0 && p[1] == 0 && p[2] == 1) + return p; + } + + return end + 3; +} + +static const uint8_t* avc_find_startcode(const uint8_t *p, const uint8_t *end) +{ + const uint8_t *out = avc_find_startcode_internal(p, end); + if (p= 0; + } + offset += ps; + } while (p + offset < end && p[offset] != 0x80); + + return false; +} + +//////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +CBitstreamParser::CBitstreamParser() = default; + +CBitstreamParser::~CBitstreamParser() = default; + +void CBitstreamParser::Close() +{ +} + +bool CBitstreamParser::CanStartDecode(const uint8_t *buf, int buf_size) +{ + if (!buf) + return false; + + bool rtn = false; + uint32_t state = -1; + const uint8_t *buf_begin, *buf_end = buf + buf_size; + + for (; rtn == false;) + { + buf = find_start_code(buf, buf_end, &state); + if (buf >= buf_end) + { + break; + } + + switch (state & 0x1f) + { + case AVC_NAL_SLICE: + break; + case AVC_NAL_IDR_SLICE: + rtn = true; + break; + case AVC_NAL_SEI: + buf_begin = buf - 1; + buf = find_start_code(buf, buf_end, &state) - 4; + if (has_sei_recovery_point(buf_begin, buf)) + rtn = true; + break; + case AVC_NAL_SPS: + rtn = true; + break; + case AVC_NAL_PPS: + break; + default: + break; + } + } + + return rtn; +} + +//////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +CBitstreamConverter::CBitstreamConverter() +{ + m_convert_bitstream = false; + m_convertBuffer = NULL; + m_convertSize = 0; + m_inputBuffer = NULL; + m_inputSize = 0; + m_to_annexb = false; + m_extradata = NULL; + m_extrasize = 0; + m_convert_3byteTo4byteNALSize = false; + m_convert_bytestream = false; + m_sps_pps_context.sps_pps_data = NULL; + m_start_decode = true; +} + +CBitstreamConverter::~CBitstreamConverter() +{ + Close(); +} + +bool CBitstreamConverter::Open(enum AVCodecID codec, uint8_t *in_extradata, int in_extrasize, bool to_annexb) +{ + m_to_annexb = to_annexb; + + m_codec = codec; + switch(m_codec) + { + case AV_CODEC_ID_H264: + if (in_extrasize < 7 || in_extradata == NULL) + { + CLog::Log(LOGERROR, "CBitstreamConverter::Open avcC data too small or missing"); + return false; + } + // valid avcC data (bitstream) always starts with the value 1 (version) + if(m_to_annexb) + { + if ( in_extradata[0] == 1 ) + { + CLog::Log(LOGINFO, "CBitstreamConverter::Open bitstream to annexb init"); + m_extrasize = in_extrasize; + m_extradata = (uint8_t*)av_malloc(in_extrasize); + memcpy(m_extradata, in_extradata, in_extrasize); + m_convert_bitstream = BitstreamConvertInitAVC(m_extradata, m_extrasize); + return true; + } + else + CLog::Log(LOGINFO, "CBitstreamConverter::Open Invalid avcC"); + } + else + { + // valid avcC atom data always starts with the value 1 (version) + if ( in_extradata[0] != 1 ) + { + if ( (in_extradata[0] == 0 && in_extradata[1] == 0 && in_extradata[2] == 0 && in_extradata[3] == 1) || + (in_extradata[0] == 0 && in_extradata[1] == 0 && in_extradata[2] == 1) ) + { + CLog::Log(LOGINFO, "CBitstreamConverter::Open annexb to bitstream init"); + // video content is from x264 or from bytestream h264 (AnnexB format) + // NAL reformating to bitstream format needed + AVIOContext *pb; + if (avio_open_dyn_buf(&pb) < 0) + return false; + m_convert_bytestream = true; + // create a valid avcC atom data from ffmpeg's extradata + isom_write_avcc(pb, in_extradata, in_extrasize); + // unhook from ffmpeg's extradata + in_extradata = NULL; + // extract the avcC atom data into extradata then write it into avcCData for VDADecoder + in_extrasize = avio_close_dyn_buf(pb, &in_extradata); + // make a copy of extradata contents + m_extradata = (uint8_t *)av_malloc(in_extrasize); + memcpy(m_extradata, in_extradata, in_extrasize); + m_extrasize = in_extrasize; + // done with the converted extradata, we MUST free using av_free + av_free(in_extradata); + return true; + } + else + { + CLog::Log(LOGINFO, "CBitstreamConverter::Open invalid avcC atom data"); + return false; + } + } + else + { + if (in_extradata[4] == 0xFE) + { + CLog::Log(LOGINFO, "CBitstreamConverter::Open annexb to bitstream init 3 byte to 4 byte nal"); + // video content is from so silly encoder that think 3 byte NAL sizes + // are valid, setup to convert 3 byte NAL sizes to 4 byte. + in_extradata[4] = 0xFF; + m_convert_3byteTo4byteNALSize = true; + + m_extradata = (uint8_t *)av_malloc(in_extrasize); + memcpy(m_extradata, in_extradata, in_extrasize); + m_extrasize = in_extrasize; + return true; + } + } + // valid avcC atom + m_extradata = (uint8_t*)av_malloc(in_extrasize); + memcpy(m_extradata, in_extradata, in_extrasize); + m_extrasize = in_extrasize; + return true; + } + return false; + break; + case AV_CODEC_ID_HEVC: + if (in_extrasize < 23 || in_extradata == NULL) + { + CLog::Log(LOGERROR, "CBitstreamConverter::Open hvcC data too small or missing"); + return false; + } + // valid hvcC data (bitstream) always starts with the value 1 (version) + if(m_to_annexb) + { + /** + * It seems the extradata is encoded as hvcC format. + * Temporarily, we support configurationVersion==0 until 14496-15 3rd + * is finalized. When finalized, configurationVersion will be 1 and we + * can recognize hvcC by checking if extradata[0]==1 or not. + */ + + if (in_extradata[0] || in_extradata[1] || in_extradata[2] > 1) + { + CLog::Log(LOGINFO, "CBitstreamConverter::Open bitstream to annexb init"); + m_extrasize = in_extrasize; + m_extradata = (uint8_t*)av_malloc(in_extrasize); + memcpy(m_extradata, in_extradata, in_extrasize); + m_convert_bitstream = BitstreamConvertInitHEVC(m_extradata, m_extrasize); + return true; + } + else + CLog::Log(LOGINFO, "CBitstreamConverter::Open Invalid hvcC"); + } + else + { + // valid hvcC atom data always starts with the value 1 (version) + if ( in_extradata[0] != 1 ) + { + if ( (in_extradata[0] == 0 && in_extradata[1] == 0 && in_extradata[2] == 0 && in_extradata[3] == 1) || + (in_extradata[0] == 0 && in_extradata[1] == 0 && in_extradata[2] == 1) ) + { + CLog::Log(LOGINFO, "CBitstreamConverter::Open annexb to bitstream init"); + //! @todo convert annexb to bitstream format + return false; + } + else + { + CLog::Log(LOGINFO, "CBitstreamConverter::Open invalid hvcC atom data"); + return false; + } + } + else + { + if ((in_extradata[4] & 0x3) == 2) + { + CLog::Log(LOGINFO, "CBitstreamConverter::Open annexb to bitstream init 3 byte to 4 byte nal"); + // video content is from so silly encoder that think 3 byte NAL sizes + // are valid, setup to convert 3 byte NAL sizes to 4 byte. + in_extradata[4] |= 0x03; + m_convert_3byteTo4byteNALSize = true; + } + } + // valid hvcC atom + m_extradata = (uint8_t*)av_malloc(in_extrasize); + memcpy(m_extradata, in_extradata, in_extrasize); + m_extrasize = in_extrasize; + return true; + } + return false; + break; + default: + return false; + break; + } + return false; +} + +void CBitstreamConverter::Close(void) +{ + if (m_sps_pps_context.sps_pps_data) + av_free(m_sps_pps_context.sps_pps_data), m_sps_pps_context.sps_pps_data = NULL; + + if (m_convertBuffer) + av_free(m_convertBuffer), m_convertBuffer = NULL; + m_convertSize = 0; + + if (m_extradata) + av_free(m_extradata), m_extradata = NULL; + m_extrasize = 0; + + m_inputSize = 0; + m_inputBuffer = NULL; + + m_convert_bitstream = false; + m_convert_bytestream = false; + m_convert_3byteTo4byteNALSize = false; +} + +bool CBitstreamConverter::Convert(uint8_t *pData, int iSize) +{ + if (m_convertBuffer) + { + av_free(m_convertBuffer); + m_convertBuffer = NULL; + } + m_inputSize = 0; + m_convertSize = 0; + m_inputBuffer = NULL; + + if (pData) + { + if (m_codec == AV_CODEC_ID_H264 || + m_codec == AV_CODEC_ID_HEVC) + { + if (m_to_annexb) + { + int demuxer_bytes = iSize; + uint8_t *demuxer_content = pData; + + if (m_convert_bitstream) + { + // convert demuxer packet from bitstream to bytestream (AnnexB) + int bytestream_size = 0; + uint8_t *bytestream_buff = NULL; + + BitstreamConvert(demuxer_content, demuxer_bytes, &bytestream_buff, &bytestream_size); + if (bytestream_buff && (bytestream_size > 0)) + { + m_convertSize = bytestream_size; + m_convertBuffer = bytestream_buff; + return true; + } + else + { + m_convertSize = 0; + m_convertBuffer = NULL; + CLog::Log(LOGERROR, "CBitstreamConverter::Convert: error converting."); + return false; + } + } + else + { + m_inputSize = iSize; + m_inputBuffer = pData; + return true; + } + } + else + { + m_inputSize = iSize; + m_inputBuffer = pData; + + if (m_convert_bytestream) + { + if(m_convertBuffer) + { + av_free(m_convertBuffer); + m_convertBuffer = NULL; + } + m_convertSize = 0; + + // convert demuxer packet from bytestream (AnnexB) to bitstream + AVIOContext *pb; + + if(avio_open_dyn_buf(&pb) < 0) + { + return false; + } + m_convertSize = avc_parse_nal_units(pb, pData, iSize); + m_convertSize = avio_close_dyn_buf(pb, &m_convertBuffer); + } + else if (m_convert_3byteTo4byteNALSize) + { + if(m_convertBuffer) + { + av_free(m_convertBuffer); + m_convertBuffer = NULL; + } + m_convertSize = 0; + + // convert demuxer packet from 3 byte NAL sizes to 4 byte + AVIOContext *pb; + if (avio_open_dyn_buf(&pb) < 0) + return false; + + uint32_t nal_size; + uint8_t *end = pData + iSize; + uint8_t *nal_start = pData; + while (nal_start < end) + { + nal_size = BS_RB24(nal_start); + avio_wb32(pb, nal_size); + nal_start += 3; + avio_write(pb, nal_start, nal_size); + nal_start += nal_size; + } + + m_convertSize = avio_close_dyn_buf(pb, &m_convertBuffer); + } + return true; + } + } + } + + return false; +} + + +uint8_t *CBitstreamConverter::GetConvertBuffer() const +{ + if((m_convert_bitstream || m_convert_bytestream || m_convert_3byteTo4byteNALSize) && m_convertBuffer != NULL) + return m_convertBuffer; + else + return m_inputBuffer; +} + +int CBitstreamConverter::GetConvertSize() const +{ + if((m_convert_bitstream || m_convert_bytestream || m_convert_3byteTo4byteNALSize) && m_convertBuffer != NULL) + return m_convertSize; + else + return m_inputSize; +} + +uint8_t *CBitstreamConverter::GetExtraData() const +{ + if(m_convert_bitstream) + return m_sps_pps_context.sps_pps_data; + else + return m_extradata; +} +int CBitstreamConverter::GetExtraSize() const +{ + if(m_convert_bitstream) + return m_sps_pps_context.size; + else + return m_extrasize; +} + +void CBitstreamConverter::ResetStartDecode(void) +{ + m_start_decode = false; +} + +bool CBitstreamConverter::CanStartDecode() const +{ + return m_start_decode; +} + +bool CBitstreamConverter::BitstreamConvertInitAVC(void *in_extradata, int in_extrasize) +{ + // based on h264_mp4toannexb_bsf.c (ffmpeg) + // which is Copyright (c) 2007 Benoit Fouet + // and Licensed GPL 2.1 or greater + + m_sps_pps_size = 0; + m_sps_pps_context.sps_pps_data = NULL; + + // nothing to filter + if (!in_extradata || in_extrasize < 6) + return false; + + uint16_t unit_size; + uint32_t total_size = 0; + uint8_t *out = NULL, unit_nb, sps_done = 0, sps_seen = 0, pps_seen = 0; + const uint8_t *extradata = (uint8_t*)in_extradata + 4; + static const uint8_t nalu_header[4] = {0, 0, 0, 1}; + + // retrieve length coded size + m_sps_pps_context.length_size = (*extradata++ & 0x3) + 1; + + // retrieve sps and pps unit(s) + unit_nb = *extradata++ & 0x1f; // number of sps unit(s) + if (!unit_nb) + { + goto pps; + } + else + { + sps_seen = 1; + } + + while (unit_nb--) + { + void *tmp; + + unit_size = extradata[0] << 8 | extradata[1]; + total_size += unit_size + 4; + + if (total_size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE || + (extradata + 2 + unit_size) > ((uint8_t*)in_extradata + in_extrasize)) + { + av_free(out); + return false; + } + tmp = av_realloc(out, total_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!tmp) + { + av_free(out); + return false; + } + out = (uint8_t*)tmp; + memcpy(out + total_size - unit_size - 4, nalu_header, 4); + memcpy(out + total_size - unit_size, extradata + 2, unit_size); + extradata += 2 + unit_size; + +pps: + if (!unit_nb && !sps_done++) + { + unit_nb = *extradata++; // number of pps unit(s) + if (unit_nb) + pps_seen = 1; + } + } + + if (out) + memset(out + total_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + if (!sps_seen) + CLog::Log(LOGDEBUG, "SPS NALU missing or invalid. The resulting stream may not play"); + if (!pps_seen) + CLog::Log(LOGDEBUG, "PPS NALU missing or invalid. The resulting stream may not play"); + + m_sps_pps_context.sps_pps_data = out; + m_sps_pps_context.size = total_size; + m_sps_pps_context.first_idr = 1; + m_sps_pps_context.idr_sps_pps_seen = 0; + + return true; +} + +bool CBitstreamConverter::BitstreamConvertInitHEVC(void *in_extradata, int in_extrasize) +{ + m_sps_pps_size = 0; + m_sps_pps_context.sps_pps_data = NULL; + + // nothing to filter + if (!in_extradata || in_extrasize < 23) + return false; + + uint16_t unit_nb, unit_size; + uint32_t total_size = 0; + uint8_t *out = NULL, array_nb, nal_type, sps_seen = 0, pps_seen = 0; + const uint8_t *extradata = (uint8_t*)in_extradata + 21; + static const uint8_t nalu_header[4] = {0, 0, 0, 1}; + + // retrieve length coded size + m_sps_pps_context.length_size = (*extradata++ & 0x3) + 1; + + array_nb = *extradata++; + while (array_nb--) + { + nal_type = *extradata++ & 0x3f; + unit_nb = extradata[0] << 8 | extradata[1]; + extradata += 2; + + if (nal_type == HEVC_NAL_SPS && unit_nb) + { + sps_seen = 1; + } + else if (nal_type == HEVC_NAL_PPS && unit_nb) + { + pps_seen = 1; + } + while (unit_nb--) + { + void *tmp; + + unit_size = extradata[0] << 8 | extradata[1]; + extradata += 2; + if (nal_type != HEVC_NAL_SPS && + nal_type != HEVC_NAL_PPS && + nal_type != HEVC_NAL_VPS) + { + extradata += unit_size; + continue; + } + total_size += unit_size + 4; + + if (total_size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE || + (extradata + unit_size) > ((uint8_t*)in_extradata + in_extrasize)) + { + av_free(out); + return false; + } + tmp = av_realloc(out, total_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!tmp) + { + av_free(out); + return false; + } + out = (uint8_t*)tmp; + memcpy(out + total_size - unit_size - 4, nalu_header, 4); + memcpy(out + total_size - unit_size, extradata, unit_size); + extradata += unit_size; + } + } + + if (out) + memset(out + total_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + if (!sps_seen) + CLog::Log(LOGDEBUG, "SPS NALU missing or invalid. The resulting stream may not play"); + if (!pps_seen) + CLog::Log(LOGDEBUG, "PPS NALU missing or invalid. The resulting stream may not play"); + + m_sps_pps_context.sps_pps_data = out; + m_sps_pps_context.size = total_size; + m_sps_pps_context.first_idr = 1; + m_sps_pps_context.idr_sps_pps_seen = 0; + + return true; +} + +bool CBitstreamConverter::IsIDR(uint8_t unit_type) +{ + switch (m_codec) + { + case AV_CODEC_ID_H264: + return unit_type == AVC_NAL_IDR_SLICE; + case AV_CODEC_ID_HEVC: + return unit_type == HEVC_NAL_IDR_W_RADL || + unit_type == HEVC_NAL_IDR_N_LP || + unit_type == HEVC_NAL_CRA_NUT; + default: + return false; + } +} + +bool CBitstreamConverter::IsSlice(uint8_t unit_type) +{ + switch (m_codec) + { + case AV_CODEC_ID_H264: + return unit_type == AVC_NAL_SLICE; + case AV_CODEC_ID_HEVC: + return unit_type == HEVC_NAL_TRAIL_R || + unit_type == HEVC_NAL_TRAIL_N || + unit_type == HEVC_NAL_TSA_N || + unit_type == HEVC_NAL_TSA_R || + unit_type == HEVC_NAL_STSA_N || + unit_type == HEVC_NAL_STSA_R || + unit_type == HEVC_NAL_BLA_W_LP || + unit_type == HEVC_NAL_BLA_W_RADL || + unit_type == HEVC_NAL_BLA_N_LP || + unit_type == HEVC_NAL_CRA_NUT || + unit_type == HEVC_NAL_RADL_N || + unit_type == HEVC_NAL_RADL_R || + unit_type == HEVC_NAL_RASL_N || + unit_type == HEVC_NAL_RASL_R; + default: + return false; + } +} + +bool CBitstreamConverter::BitstreamConvert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size) +{ + // based on h264_mp4toannexb_bsf.c (ffmpeg) + // which is Copyright (c) 2007 Benoit Fouet + // and Licensed GPL 2.1 or greater + + int i; + uint8_t *buf = pData; + uint32_t buf_size = iSize; + uint8_t unit_type, nal_sps, nal_pps, nal_sei; + int32_t nal_size; + uint32_t cumul_size = 0; + const uint8_t *buf_end = buf + buf_size; + + switch (m_codec) + { + case AV_CODEC_ID_H264: + nal_sps = AVC_NAL_SPS; + nal_pps = AVC_NAL_PPS; + nal_sei = AVC_NAL_SEI; + break; + case AV_CODEC_ID_HEVC: + nal_sps = HEVC_NAL_SPS; + nal_pps = HEVC_NAL_PPS; + nal_sei = HEVC_NAL_SEI_PREFIX; + break; + default: + return false; + } + + do + { + if (buf + m_sps_pps_context.length_size > buf_end) + goto fail; + + for (nal_size = 0, i = 0; i < m_sps_pps_context.length_size; i++) + nal_size = (nal_size << 8) | buf[i]; + + buf += m_sps_pps_context.length_size; + if (m_codec == AV_CODEC_ID_H264) + { + unit_type = *buf & 0x1f; + } + else + { + unit_type = (*buf >> 1) & 0x3f; + } + + if (buf + nal_size > buf_end || nal_size <= 0) + goto fail; + + // Don't add sps/pps if the unit already contain them + if (m_sps_pps_context.first_idr && (unit_type == nal_sps || unit_type == nal_pps)) + m_sps_pps_context.idr_sps_pps_seen = 1; + + if (!m_start_decode && (unit_type == nal_sps || IsIDR(unit_type) || (unit_type == nal_sei && has_sei_recovery_point(buf, buf + nal_size)))) + m_start_decode = true; + + // prepend only to the first access unit of an IDR picture, if no sps/pps already present + if (m_sps_pps_context.first_idr && IsIDR(unit_type) && !m_sps_pps_context.idr_sps_pps_seen) + { + BitstreamAllocAndCopy(poutbuf, poutbuf_size, + m_sps_pps_context.sps_pps_data, m_sps_pps_context.size, buf, nal_size); + m_sps_pps_context.first_idr = 0; + } + else + { + BitstreamAllocAndCopy(poutbuf, poutbuf_size, NULL, 0, buf, nal_size); + if (!m_sps_pps_context.first_idr && IsSlice(unit_type)) + { + m_sps_pps_context.first_idr = 1; + m_sps_pps_context.idr_sps_pps_seen = 0; + } + } + + buf += nal_size; + cumul_size += nal_size + m_sps_pps_context.length_size; + } while (cumul_size < buf_size); + + return true; + +fail: + av_free(*poutbuf), *poutbuf = NULL; + *poutbuf_size = 0; + return false; +} + +void CBitstreamConverter::BitstreamAllocAndCopy( uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *sps_pps, uint32_t sps_pps_size, const uint8_t *in, uint32_t in_size) +{ + // based on h264_mp4toannexb_bsf.c (ffmpeg) + // which is Copyright (c) 2007 Benoit Fouet + // and Licensed GPL 2.1 or greater + + uint32_t offset = *poutbuf_size; + uint8_t nal_header_size = offset ? 3 : 4; + void *tmp; + + *poutbuf_size += sps_pps_size + in_size + nal_header_size; + tmp = av_realloc(*poutbuf, *poutbuf_size); + if (!tmp) + return; + *poutbuf = (uint8_t*)tmp; + if (sps_pps) + memcpy(*poutbuf + offset, sps_pps, sps_pps_size); + + memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size); + if (!offset) + { + BS_WB32(*poutbuf + sps_pps_size, 1); + } + else + { + (*poutbuf + offset + sps_pps_size)[0] = 0; + (*poutbuf + offset + sps_pps_size)[1] = 0; + (*poutbuf + offset + sps_pps_size)[2] = 1; + } +} + +int CBitstreamConverter::avc_parse_nal_units(AVIOContext *pb, const uint8_t *buf_in, int size) +{ + const uint8_t *p = buf_in; + const uint8_t *end = p + size; + const uint8_t *nal_start, *nal_end; + + size = 0; + nal_start = avc_find_startcode(p, end); + + for (;;) { + while (nal_start < end && !*(nal_start++)); + if (nal_start == end) + break; + + nal_end = avc_find_startcode(nal_start, end); + avio_wb32(pb, nal_end - nal_start); + avio_write(pb, nal_start, nal_end - nal_start); + size += 4 + nal_end - nal_start; + nal_start = nal_end; + } + return size; +} + +int CBitstreamConverter::avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size) +{ + AVIOContext *pb; + int ret = avio_open_dyn_buf(&pb); + if (ret < 0) + return ret; + + avc_parse_nal_units(pb, buf_in, *size); + + av_freep(buf); + *size = avio_close_dyn_buf(pb, buf); + return 0; +} + +int CBitstreamConverter::isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len) +{ + // extradata from bytestream h264, convert to avcC atom data for bitstream + if (len > 6) + { + /* check for h264 start code */ + if (BS_RB32(data) == 0x00000001 || BS_RB24(data) == 0x000001) + { + uint8_t *buf=NULL, *end, *start; + uint32_t sps_size=0, pps_size=0; + uint8_t *sps=0, *pps=0; + + int ret = avc_parse_nal_units_buf(data, &buf, &len); + if (ret < 0) + return ret; + start = buf; + end = buf + len; + + /* look for sps and pps */ + while (end - buf > 4) + { + uint32_t size; + uint8_t nal_type; + size = std::min(BS_RB32(buf), end - buf - 4); + buf += 4; + nal_type = buf[0] & 0x1f; + if (nal_type == 7) /* SPS */ + { + sps = buf; + sps_size = size; + } + else if (nal_type == 8) /* PPS */ + { + pps = buf; + pps_size = size; + } + buf += size; + } + if (!sps || !pps || sps_size < 4 || sps_size > UINT16_MAX || pps_size > UINT16_MAX) + assert(0); + + avio_w8(pb, 1); /* version */ + avio_w8(pb, sps[1]); /* profile */ + avio_w8(pb, sps[2]); /* profile compat */ + avio_w8(pb, sps[3]); /* level */ + avio_w8(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ + avio_w8(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */ + + avio_wb16(pb, sps_size); + avio_write(pb, sps, sps_size); + if (pps) + { + avio_w8(pb, 1); /* number of pps */ + avio_wb16(pb, pps_size); + avio_write(pb, pps, pps_size); + } + av_free(start); + } + else + { + avio_write(pb, data, len); + } + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +bool CBitstreamConverter::mpeg2_sequence_header(const uint8_t *data, const uint32_t size, mpeg2_sequence *sequence) +{ + // parse nal's until a sequence_header_code is found + // and return the width, height, aspect ratio and frame rate if changed. + bool changed = false; + + if (!data) + return changed; + + const uint8_t *p = data; + const uint8_t *end = p + size; + const uint8_t *nal_start, *nal_end; + + nal_start = avc_find_startcode(p, end); + while (nal_start < end) + { + while (!*(nal_start++)); + nal_end = avc_find_startcode(nal_start, end); + if (*nal_start == 0xB3) + { + nal_bitstream bs; + nal_bs_init(&bs, nal_start, end - nal_start); + + // sequence_header_code + nal_bs_read(&bs, 8); + + // width + // nal_start + 12 bits == horizontal_size_value + uint32_t width = nal_bs_read(&bs, 12); + if (width != sequence->width) + { + changed = true; + sequence->width = width; + } + // height + // nal_start + 24 bits == vertical_size_value + uint32_t height = nal_bs_read(&bs, 12); + if (height != sequence->height) + { + changed = true; + sequence->height = height; + } + + // aspect ratio + // nal_start + 28 bits == aspect_ratio_information + float ratio = sequence->ratio; + uint32_t ratio_info = nal_bs_read(&bs, 4); + switch(ratio_info) + { + case 0x01: + ratio = 1.0f; + break; + default: + case 0x02: + ratio = 4.0f/3; + break; + case 0x03: + ratio = 16.0f/9; + break; + case 0x04: + ratio = 2.21f; + break; + } + if (ratio_info != sequence->ratio_info) + { + changed = true; + sequence->ratio = ratio; + sequence->ratio_info = ratio_info; + } + + // frame rate + // nal_start + 32 bits == frame_rate_code + uint32_t fpsrate = sequence->fps_rate; + uint32_t fpsscale = sequence->fps_scale; + uint32_t rate_info = nal_bs_read(&bs, 4); + + switch(rate_info) + { + default: + case 0x01: + fpsrate = 24000; + fpsscale = 1001; + break; + case 0x02: + fpsrate = 24000; + fpsscale = 1000; + break; + case 0x03: + fpsrate = 25000; + fpsscale = 1000; + break; + case 0x04: + fpsrate = 30000; + fpsscale = 1001; + break; + case 0x05: + fpsrate = 30000; + fpsscale = 1000; + break; + case 0x06: + fpsrate = 50000; + fpsscale = 1000; + break; + case 0x07: + fpsrate = 60000; + fpsscale = 1001; + break; + case 0x08: + fpsrate = 60000; + fpsscale = 1000; + break; + } + + if (fpsscale != sequence->fps_scale || fpsrate != sequence->fps_rate) + { + changed = true; + sequence->fps_rate = fpsrate; + sequence->fps_scale = fpsscale; + } + } + nal_start = nal_end; + } + + return changed; +} + diff --git a/xbmc/utils/BitstreamConverter.h b/xbmc/utils/BitstreamConverter.h new file mode 100644 index 0000000..9244870 --- /dev/null +++ b/xbmc/utils/BitstreamConverter.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2010-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +extern "C" { +#include +#include +#include +#include +} + +typedef struct +{ + const uint8_t *data; + const uint8_t *end; + int head; + uint64_t cache; +} nal_bitstream; + +typedef struct mpeg2_sequence +{ + uint32_t width; + uint32_t height; + uint32_t fps_rate; + uint32_t fps_scale; + float ratio; + uint32_t ratio_info; +} mpeg2_sequence; + +typedef struct +{ + int profile_idc; + int level_idc; + int sps_id; + + int chroma_format_idc; + int separate_colour_plane_flag; + int bit_depth_luma_minus8; + int bit_depth_chroma_minus8; + int qpprime_y_zero_transform_bypass_flag; + int seq_scaling_matrix_present_flag; + + int log2_max_frame_num_minus4; + int pic_order_cnt_type; + int log2_max_pic_order_cnt_lsb_minus4; + + int max_num_ref_frames; + int gaps_in_frame_num_value_allowed_flag; + int pic_width_in_mbs_minus1; + int pic_height_in_map_units_minus1; + + int frame_mbs_only_flag; + int mb_adaptive_frame_field_flag; + + int direct_8x8_inference_flag; + + int frame_cropping_flag; + int frame_crop_left_offset; + int frame_crop_right_offset; + int frame_crop_top_offset; + int frame_crop_bottom_offset; +} sps_info_struct; + +class CBitstreamParser +{ +public: + CBitstreamParser(); + ~CBitstreamParser(); + + static bool Open(){ return true; }; + static void Close(); + static bool CanStartDecode(const uint8_t *buf, int buf_size); +}; + +class CBitstreamConverter +{ +public: + CBitstreamConverter(); + ~CBitstreamConverter(); + + bool Open(enum AVCodecID codec, uint8_t *in_extradata, int in_extrasize, bool to_annexb); + void Close(void); + bool NeedConvert(void) const { return m_convert_bitstream; }; + bool Convert(uint8_t *pData, int iSize); + uint8_t* GetConvertBuffer(void) const; + int GetConvertSize() const; + uint8_t* GetExtraData(void) const; + int GetExtraSize() const; + void ResetStartDecode(void); + bool CanStartDecode() const; + + static bool mpeg2_sequence_header(const uint8_t *data, const uint32_t size, mpeg2_sequence *sequence); + +protected: + static int avc_parse_nal_units(AVIOContext *pb, const uint8_t *buf_in, int size); + static int avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size); + int isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len); + // bitstream to bytestream (Annex B) conversion support. + bool IsIDR(uint8_t unit_type); + bool IsSlice(uint8_t unit_type); + bool BitstreamConvertInitAVC(void *in_extradata, int in_extrasize); + bool BitstreamConvertInitHEVC(void *in_extradata, int in_extrasize); + bool BitstreamConvert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size); + static void BitstreamAllocAndCopy(uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *sps_pps, uint32_t sps_pps_size, const uint8_t *in, uint32_t in_size); + + typedef struct omx_bitstream_ctx { + uint8_t length_size; + uint8_t first_idr; + uint8_t idr_sps_pps_seen; + uint8_t *sps_pps_data; + uint32_t size; + } omx_bitstream_ctx; + + uint8_t *m_convertBuffer; + int m_convertSize; + uint8_t *m_inputBuffer; + int m_inputSize; + + uint32_t m_sps_pps_size; + omx_bitstream_ctx m_sps_pps_context; + bool m_convert_bitstream; + bool m_to_annexb; + + uint8_t *m_extradata; + int m_extrasize; + bool m_convert_3byteTo4byteNALSize; + bool m_convert_bytestream; + AVCodecID m_codec; + bool m_start_decode; +}; diff --git a/xbmc/utils/BitstreamReader.cpp b/xbmc/utils/BitstreamReader.cpp new file mode 100644 index 0000000..6f2a7ff --- /dev/null +++ b/xbmc/utils/BitstreamReader.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "BitstreamReader.h" + +CBitstreamReader::CBitstreamReader(const uint8_t *buf, int len) + : buffer(buf) + , start(buf) + , offbits(0) + , length(len) + , oflow(0) +{ +} + +uint32_t CBitstreamReader::ReadBits(int nbits) +{ + uint32_t ret = GetBits(nbits); + + offbits += nbits; + buffer += offbits / 8; + offbits %= 8; + + return ret; +} + +void CBitstreamReader::SkipBits(int nbits) +{ + offbits += nbits; + buffer += offbits / 8; + offbits %= 8; + + if (buffer > (start + length)) + oflow = 1; +} + +uint32_t CBitstreamReader::GetBits(int nbits) +{ + int i, nbytes; + uint32_t ret = 0; + const uint8_t *buf; + + buf = buffer; + nbytes = (offbits + nbits) / 8; + + if (((offbits + nbits) % 8) > 0) + nbytes++; + + if ((buf + nbytes) > (start + length)) + { + oflow = 1; + return 0; + } + for (i = 0; i> i) >> ((nbytes * 8) - nbits - offbits); + + return ret; +} + +const uint8_t* find_start_code(const uint8_t *p, const uint8_t *end, uint32_t *state) +{ + if (p >= end) + return end; + + for (int i = 0; i < 3; i++) + { + uint32_t tmp = *state << 8; + *state = tmp + *(p++); + if (tmp == 0x100 || p == end) + return p; + } + + while (p < end) + { + if (p[-1] > 1) p += 3; + else if (p[-2]) p += 2; + else if (p[-3] | (p[-1] - 1)) p++; + else { + p++; + break; + } + } + + p = (p < end)? p - 4 : end - 4; + *state = BS_RB32(p); + + return p + 4; +} diff --git a/xbmc/utils/BitstreamReader.h b/xbmc/utils/BitstreamReader.h new file mode 100644 index 0000000..89fa2b2 --- /dev/null +++ b/xbmc/utils/BitstreamReader.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +class CBitstreamReader +{ +public: + CBitstreamReader(const uint8_t *buf, int len); + uint32_t ReadBits(int nbits); + void SkipBits(int nbits); + uint32_t GetBits(int nbits); + +private: + const uint8_t *buffer, *start; + int offbits, length, oflow; +}; + +const uint8_t* find_start_code(const uint8_t *p, const uint8_t *end, uint32_t *state); + +//////////////////////////////////////////////////////////////////////////////////////////// +//! @todo refactor this so as not to need these ffmpeg routines. +//! These are not exposed in ffmpeg's API so we dupe them here. + +/* + * AVC helper functions for muxers + * Copyright (c) 2006 Baptiste Coudurier + * This is part of FFmpeg + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * See LICENSES/README.md for more information. + */ +constexpr uint32_t BS_RB24(const uint8_t* x) +{ + return (x[0] << 16) | (x[1] << 8) | x[2]; +} + +constexpr uint32_t BS_RB32(const uint8_t* x) +{ + return (x[1] << 24) | (x[1] << 16) | (x[2] << 8) | x[3]; +} + diff --git a/xbmc/utils/BitstreamStats.cpp b/xbmc/utils/BitstreamStats.cpp new file mode 100644 index 0000000..a35a757 --- /dev/null +++ b/xbmc/utils/BitstreamStats.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "BitstreamStats.h" + +#include "utils/TimeUtils.h" + +int64_t BitstreamStats::m_tmFreq; + +BitstreamStats::BitstreamStats(unsigned int nEstimatedBitrate) +{ + m_dBitrate = 0.0; + m_dMaxBitrate = 0.0; + m_dMinBitrate = -1.0; + + m_nBitCount = 0; + m_nEstimatedBitrate = nEstimatedBitrate; + m_tmStart = 0LL; + + if (m_tmFreq == 0LL) + m_tmFreq = CurrentHostFrequency(); +} + +void BitstreamStats::AddSampleBytes(unsigned int nBytes) +{ + AddSampleBits(nBytes*8); +} + +void BitstreamStats::AddSampleBits(unsigned int nBits) +{ + m_nBitCount += nBits; + if (m_nBitCount >= m_nEstimatedBitrate) + CalculateBitrate(); +} + +void BitstreamStats::Start() +{ + m_nBitCount = 0; + m_tmStart = CurrentHostCounter(); +} + +void BitstreamStats::CalculateBitrate() +{ + int64_t tmNow; + tmNow = CurrentHostCounter(); + + double elapsed = (double)(tmNow - m_tmStart) / (double)m_tmFreq; + // only update once every 2 seconds + if (elapsed >= 2) + { + m_dBitrate = (double)m_nBitCount / elapsed; + + if (m_dBitrate > m_dMaxBitrate) + m_dMaxBitrate = m_dBitrate; + + if (m_dBitrate < m_dMinBitrate || m_dMinBitrate == -1) + m_dMinBitrate = m_dBitrate; + + Start(); + } +} + + + + diff --git a/xbmc/utils/BitstreamStats.h b/xbmc/utils/BitstreamStats.h new file mode 100644 index 0000000..13413c6 --- /dev/null +++ b/xbmc/utils/BitstreamStats.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +class BitstreamStats final +{ +public: + // in order not to cause a performance hit, we should only check the clock when + // we reach m_nEstimatedBitrate bits. + // if this value is 1, we will calculate bitrate on every sample. + explicit BitstreamStats(unsigned int nEstimatedBitrate=(10240*8) /*10Kbit*/); + + void AddSampleBytes(unsigned int nBytes); + void AddSampleBits(unsigned int nBits); + + inline double GetBitrate() const { return m_dBitrate; } + inline double GetMaxBitrate() const { return m_dMaxBitrate; } + inline double GetMinBitrate() const { return m_dMinBitrate; } + + void Start(); + void CalculateBitrate(); + +private: + double m_dBitrate; + double m_dMaxBitrate; + double m_dMinBitrate; + unsigned int m_nBitCount; + unsigned int m_nEstimatedBitrate; // when we reach this amount of bits we check current bitrate. + int64_t m_tmStart; + static int64_t m_tmFreq; +}; + diff --git a/xbmc/utils/BitstreamWriter.cpp b/xbmc/utils/BitstreamWriter.cpp new file mode 100644 index 0000000..43c0788 --- /dev/null +++ b/xbmc/utils/BitstreamWriter.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "BitstreamWriter.h" + +CBitstreamWriter::CBitstreamWriter(uint8_t *buffer, unsigned int buffer_size, int writer_le) + : writer_le(writer_le) + , bit_buf(0) + , bit_left(32) + , buf(buffer) + , buf_ptr(buf) +{ +} + +void CBitstreamWriter::WriteBits(int n, unsigned int value) +{ + // Write up to 32 bits into a bitstream. + unsigned int bit_buf; + int bit_left; + + if (n == 32) + { + // Write exactly 32 bits into a bitstream. + // danger, recursion in play. + int lo = value & 0xffff; + int hi = value >> 16; + if (writer_le) + { + WriteBits(16, lo); + WriteBits(16, hi); + } + else + { + WriteBits(16, hi); + WriteBits(16, lo); + } + return; + } + + bit_buf = this->bit_buf; + bit_left = this->bit_left; + + if (writer_le) + { + bit_buf |= value << (32 - bit_left); + if (n >= bit_left) { + BS_WL32(buf_ptr, bit_buf); + buf_ptr += 4; + bit_buf = (bit_left == 32) ? 0 : value >> bit_left; + bit_left += 32; + } + bit_left -= n; + } + else + { + if (n < bit_left) { + bit_buf = (bit_buf << n) | value; + bit_left -= n; + } + else { + bit_buf <<= bit_left; + bit_buf |= value >> (n - bit_left); + BS_WB32(buf_ptr, bit_buf); + buf_ptr += 4; + bit_left += 32 - n; + bit_buf = value; + } + } + + this->bit_buf = bit_buf; + this->bit_left = bit_left; +} + +void CBitstreamWriter::SkipBits(int n) +{ + // Skip the given number of bits. + // Must only be used if the actual values in the bitstream do not matter. + // If n is 0 the behavior is undefined. + bit_left -= n; + buf_ptr -= 4 * (bit_left >> 5); + bit_left &= 31; +} + +void CBitstreamWriter::FlushBits() +{ + if (!writer_le) + { + if (bit_left < 32) + bit_buf <<= bit_left; + } + while (bit_left < 32) + { + + if (writer_le) + { + *buf_ptr++ = bit_buf; + bit_buf >>= 8; + } + else + { + *buf_ptr++ = bit_buf >> 24; + bit_buf <<= 8; + } + bit_left += 8; + } + bit_left = 32; + bit_buf = 0; +} diff --git a/xbmc/utils/BitstreamWriter.h b/xbmc/utils/BitstreamWriter.h new file mode 100644 index 0000000..91257b2 --- /dev/null +++ b/xbmc/utils/BitstreamWriter.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +class CBitstreamWriter +{ +public: + CBitstreamWriter(uint8_t *buffer, unsigned int buffer_size, int writer_le); + void WriteBits(int n, unsigned int value); + void SkipBits(int n); + void FlushBits(); + +private: + int writer_le; + uint32_t bit_buf; + int bit_left; + uint8_t *buf, *buf_ptr; +}; + +//////////////////////////////////////////////////////////////////////////////////////////// +//! @todo refactor this so as not to need these ffmpeg routines. +//! These are not exposed in ffmpeg's API so we dupe them here. + +/* + * AVC helper functions for muxers + * Copyright (c) 2006 Baptiste Coudurier + * This is part of FFmpeg + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * See LICENSES/README.md for more information. + */ +#define BS_WB32(p, d) { \ + ((uint8_t*)(p))[3] = (d); \ + ((uint8_t*)(p))[2] = (d) >> 8; \ + ((uint8_t*)(p))[1] = (d) >> 16; \ + ((uint8_t*)(p))[0] = (d) >> 24; } + +#define BS_WL32(p, d) { \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d) >> 8; \ + ((uint8_t*)(p))[2] = (d) >> 16; \ + ((uint8_t*)(p))[3] = (d) >> 24; } diff --git a/xbmc/utils/BooleanLogic.cpp b/xbmc/utils/BooleanLogic.cpp new file mode 100644 index 0000000..c6be261 --- /dev/null +++ b/xbmc/utils/BooleanLogic.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "BooleanLogic.h" + +#include "utils/StringUtils.h" +#include "utils/XBMCTinyXML.h" +#include "utils/log.h" + +bool CBooleanLogicValue::Deserialize(const TiXmlNode *node) +{ + if (node == NULL) + return false; + + const TiXmlElement *elem = node->ToElement(); + if (elem == NULL) + return false; + + if (node->FirstChild() != NULL && node->FirstChild()->Type() == TiXmlNode::TINYXML_TEXT) + m_value = node->FirstChild()->ValueStr(); + + m_negated = false; + const char *strNegated = elem->Attribute("negated"); + if (strNegated != NULL) + { + if (StringUtils::EqualsNoCase(strNegated, "true")) + m_negated = true; + else if (!StringUtils::EqualsNoCase(strNegated, "false")) + { + CLog::Log(LOGDEBUG, "CBooleanLogicValue: invalid negated value \"%s\"", strNegated); + return false; + } + } + + return true; +} + +bool CBooleanLogicOperation::Deserialize(const TiXmlNode *node) +{ + if (node == NULL) + return false; + + // check if this is a simple operation with a single value directly expressed + // in the parent tag + if (node->FirstChild() == NULL || node->FirstChild()->Type() == TiXmlNode::TINYXML_TEXT) + { + CBooleanLogicValuePtr value = CBooleanLogicValuePtr(newValue()); + if (value == NULL || !value->Deserialize(node)) + { + CLog::Log(LOGDEBUG, "CBooleanLogicOperation: failed to deserialize implicit boolean value definition"); + return false; + } + + m_values.push_back(value); + return true; + } + + const TiXmlNode *operationNode = node->FirstChild(); + while (operationNode != NULL) + { + std::string tag = operationNode->ValueStr(); + if (StringUtils::EqualsNoCase(tag, "and") || StringUtils::EqualsNoCase(tag, "or")) + { + CBooleanLogicOperationPtr operation = CBooleanLogicOperationPtr(newOperation()); + if (operation == NULL) + return false; + + operation->SetOperation(StringUtils::EqualsNoCase(tag, "and") ? BooleanLogicOperationAnd : BooleanLogicOperationOr); + if (!operation->Deserialize(operationNode)) + { + CLog::Log(LOGDEBUG, "CBooleanLogicOperation: failed to deserialize <%s> definition", tag.c_str()); + return false; + } + + m_operations.push_back(operation); + } + else + { + CBooleanLogicValuePtr value = CBooleanLogicValuePtr(newValue()); + if (value == NULL) + return false; + + if (StringUtils::EqualsNoCase(tag, value->GetTag())) + { + if (!value->Deserialize(operationNode)) + { + CLog::Log(LOGDEBUG, "CBooleanLogicOperation: failed to deserialize <%s> definition", tag.c_str()); + return false; + } + + m_values.push_back(value); + } + else if (operationNode->Type() == TiXmlNode::TINYXML_ELEMENT) + CLog::Log(LOGDEBUG, "CBooleanLogicOperation: unknown <%s> definition encountered", tag.c_str()); + } + + operationNode = operationNode->NextSibling(); + } + + return true; +} + +bool CBooleanLogic::Deserialize(const TiXmlNode *node) +{ + if (node == NULL) + return false; + + if (m_operation == NULL) + { + m_operation = CBooleanLogicOperationPtr(new CBooleanLogicOperation()); + + if (m_operation == NULL) + return false; + } + + return m_operation->Deserialize(node); +} diff --git a/xbmc/utils/BooleanLogic.h b/xbmc/utils/BooleanLogic.h new file mode 100644 index 0000000..0355134 --- /dev/null +++ b/xbmc/utils/BooleanLogic.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/IXmlDeserializable.h" + +#include +#include +#include + +typedef enum { + BooleanLogicOperationOr = 0, + BooleanLogicOperationAnd +} BooleanLogicOperation; + +class CBooleanLogicValue : public IXmlDeserializable +{ +public: + CBooleanLogicValue(const std::string &value = "", bool negated = false) + : m_value(value), m_negated(negated) + { } + ~CBooleanLogicValue() override = default; + + bool Deserialize(const TiXmlNode *node) override; + + virtual const std::string& GetValue() const { return m_value; } + virtual bool IsNegated() const { return m_negated; } + virtual const char* GetTag() const { return "value"; } + + virtual void SetValue(const std::string &value) { m_value = value; } + virtual void SetNegated(bool negated) { m_negated = negated; } + +protected: + std::string m_value; + bool m_negated; +}; + +typedef std::shared_ptr CBooleanLogicValuePtr; +typedef std::vector CBooleanLogicValues; + +class CBooleanLogicOperation; +typedef std::shared_ptr CBooleanLogicOperationPtr; +typedef std::vector CBooleanLogicOperations; + +class CBooleanLogicOperation : public IXmlDeserializable +{ +public: + explicit CBooleanLogicOperation(BooleanLogicOperation op = BooleanLogicOperationAnd) + : m_operation(op) + { } + ~CBooleanLogicOperation() override = default; + + bool Deserialize(const TiXmlNode *node) override; + + virtual BooleanLogicOperation GetOperation() const { return m_operation; } + virtual const CBooleanLogicOperations& GetOperations() const { return m_operations; } + virtual const CBooleanLogicValues& GetValues() const { return m_values; } + + virtual void SetOperation(BooleanLogicOperation op) { m_operation = op; } + +protected: + virtual CBooleanLogicOperation* newOperation() { return new CBooleanLogicOperation(); } + virtual CBooleanLogicValue* newValue() { return new CBooleanLogicValue(); } + + BooleanLogicOperation m_operation; + CBooleanLogicOperations m_operations; + CBooleanLogicValues m_values; +}; + +class CBooleanLogic : public IXmlDeserializable +{ +protected: + /* make sure nobody deletes a pointer to this class */ + ~CBooleanLogic() override = default; + +public: + bool Deserialize(const TiXmlNode *node) override; + + const CBooleanLogicOperationPtr& Get() const { return m_operation; } + CBooleanLogicOperationPtr Get() { return m_operation; } + +protected: + CBooleanLogicOperationPtr m_operation; +}; diff --git a/xbmc/utils/BufferObject.cpp b/xbmc/utils/BufferObject.cpp new file mode 100644 index 0000000..1bf338e --- /dev/null +++ b/xbmc/utils/BufferObject.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "BufferObject.h" + +#include "BufferObjectFactory.h" +#include "utils/log.h" + +#if defined(HAVE_LINUX_DMA_BUF) +#include +#include +#endif + +std::unique_ptr CBufferObject::GetBufferObject(bool needsCreateBySize) +{ + return CBufferObjectFactory::CreateBufferObject(needsCreateBySize); +} + +int CBufferObject::GetFd() +{ + return m_fd; +} + +uint32_t CBufferObject::GetStride() +{ + return m_stride; +} + +uint64_t CBufferObject::GetModifier() +{ + return 0; // linear +} + +void CBufferObject::SyncStart() +{ +#if defined(HAVE_LINUX_DMA_BUF) + struct dma_buf_sync sync; + sync.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW; + + int ret = ioctl(m_fd, DMA_BUF_IOCTL_SYNC, &sync); + if (ret < 0) + CLog::LogF(LOGERROR, "ioctl DMA_BUF_IOCTL_SYNC failed, ret={} errno={}", ret, strerror(errno)); +#endif +} + +void CBufferObject::SyncEnd() +{ +#if defined(HAVE_LINUX_DMA_BUF) + struct dma_buf_sync sync; + sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW; + + int ret = ioctl(m_fd, DMA_BUF_IOCTL_SYNC, &sync); + if (ret < 0) + CLog::LogF(LOGERROR, "ioctl DMA_BUF_IOCTL_SYNC failed, ret={} errno={}", ret, strerror(errno)); +#endif +} diff --git a/xbmc/utils/BufferObject.h b/xbmc/utils/BufferObject.h new file mode 100644 index 0000000..11d0a06 --- /dev/null +++ b/xbmc/utils/BufferObject.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "IBufferObject.h" + +#include +#include + +/** + * @brief base class for using the IBufferObject interface. Derived classes + * should be based on this class. + * + */ +class CBufferObject : public IBufferObject +{ +public: + /** + * @brief Get a BufferObject from CBufferObjectFactory + * + * @return std::unique_ptr + */ + static std::unique_ptr GetBufferObject(bool needsCreateBySize); + + virtual bool CreateBufferObject(uint64_t size) override { return false; } + + virtual int GetFd() override; + virtual uint32_t GetStride() override; + virtual uint64_t GetModifier() override; + + void SyncStart() override; + void SyncEnd() override; + +protected: + int m_fd{-1}; + uint32_t m_stride{0}; +}; diff --git a/xbmc/utils/BufferObjectFactory.cpp b/xbmc/utils/BufferObjectFactory.cpp new file mode 100644 index 0000000..eb1ec7e --- /dev/null +++ b/xbmc/utils/BufferObjectFactory.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "BufferObjectFactory.h" + +std::list()>> CBufferObjectFactory::m_bufferObjects; + +std::unique_ptr CBufferObjectFactory::CreateBufferObject(bool needsCreateBySize) +{ + for (const auto bufferObject : m_bufferObjects) + { + auto bo = bufferObject(); + + if (needsCreateBySize) + { + if (!bo->CreateBufferObject(1)) + continue; + + bo->DestroyBufferObject(); + } + + return bo; + } + + return nullptr; +} + +void CBufferObjectFactory::RegisterBufferObject( + std::function()> createFunc) +{ + m_bufferObjects.emplace_front(createFunc); +} + +void CBufferObjectFactory::ClearBufferObjects() +{ + m_bufferObjects.clear(); +} diff --git a/xbmc/utils/BufferObjectFactory.h b/xbmc/utils/BufferObjectFactory.h new file mode 100644 index 0000000..a466e84 --- /dev/null +++ b/xbmc/utils/BufferObjectFactory.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "BufferObject.h" + +#include +#include +#include + +/** + * @brief Factory that provides CBufferObject registration and creation + * + */ +class CBufferObjectFactory +{ +public: + /** + * @brief Create a CBufferObject from the registered BufferObject types. + * In the future this may include some criteria for selecting a specific + * CBufferObject derived type. Currently it returns the CBufferObject + * implementation that was registered last. + * + * @return std::unique_ptr + */ + static std::unique_ptr CreateBufferObject(bool needsCreateBySize); + + /** + * @brief Registers a CBufferObject class to class to the factory. + * + */ + static void RegisterBufferObject(std::function()>); + + /** + * @brief Clears the list of registered CBufferObject types + * + */ + static void ClearBufferObjects(); + +protected: + static std::list()>> m_bufferObjects; +}; diff --git a/xbmc/utils/CMakeLists.txt b/xbmc/utils/CMakeLists.txt new file mode 100644 index 0000000..a04870e --- /dev/null +++ b/xbmc/utils/CMakeLists.txt @@ -0,0 +1,227 @@ +set(SOURCES ActorProtocol.cpp + AlarmClock.cpp + AliasShortcutUtils.cpp + Archive.cpp + auto_buffer.cpp + Base64.cpp + BitstreamConverter.cpp + BitstreamReader.cpp + BitstreamStats.cpp + BitstreamWriter.cpp + BooleanLogic.cpp + CharsetConverter.cpp + CharsetDetection.cpp + ColorUtils.cpp + CPUInfo.cpp + Crc32.cpp + CryptThreading.cpp + DatabaseUtils.cpp + Digest.cpp + EndianSwap.cpp + EmbeddedArt.cpp + FileExtensionProvider.cpp + Fanart.cpp + FileOperationJob.cpp + FileUtils.cpp + GroupUtils.cpp + HTMLUtil.cpp + HttpHeader.cpp + HttpParser.cpp + HttpRangeUtils.cpp + HttpResponse.cpp + InfoLoader.cpp + JobManager.cpp + JSONVariantParser.cpp + JSONVariantWriter.cpp + LabelFormatter.cpp + LangCodeExpander.cpp + LegacyPathTranslation.cpp + Locale.cpp + log.cpp + Mime.cpp + Observer.cpp + POUtils.cpp + RecentlyAddedJob.cpp + RegExp.cpp + rfft.cpp + RingBuffer.cpp + RssManager.cpp + RssReader.cpp + ProgressJob.cpp + SaveFileStateJob.cpp + ScraperParser.cpp + ScraperUrl.cpp + Screenshot.cpp + SortUtils.cpp + Speed.cpp + StaticLoggerBase.cpp + Stopwatch.cpp + StreamDetails.cpp + StreamUtils.cpp + StringUtils.cpp + StringValidation.cpp + SystemInfo.cpp + Temperature.cpp + TextSearch.cpp + TimeUtils.cpp + URIUtils.cpp + UrlOptions.cpp + Utf8Utils.cpp + Variant.cpp + VC1BitstreamParser.cpp + Vector.cpp + XBMCTinyXML.cpp + XMLUtils.cpp) + +set(HEADERS ActorProtocol.h + AlarmClock.h + AliasShortcutUtils.h + Archive.h + auto_buffer.h + Base64.h + BitstreamConverter.h + BitstreamReader.h + BitstreamStats.h + BitstreamWriter.h + BooleanLogic.h + CharsetConverter.h + CharsetDetection.h + CPUInfo.h + Color.h + ColorUtils.h + Crc32.h + CryptThreading.h + DatabaseUtils.h + Digest.h + EndianSwap.h + EventStream.h + EventStreamDetail.h + FileExtensionProvider.h + Fanart.h + FileOperationJob.h + FileUtils.h + Geometry.h + GlobalsHandling.h + GroupUtils.h + HTMLUtil.h + HttpHeader.h + HttpParser.h + HttpRangeUtils.h + HttpResponse.h + IArchivable.h + IBufferObject.h + ILocalizer.h + InfoLoader.h + IPlatformLog.h + IRssObserver.h + IScreenshotSurface.h + ISerializable.h + ISortable.h + IXmlDeserializable.h + Job.h + JobManager.h + JSONVariantParser.h + JSONVariantWriter.h + LabelFormatter.h + LangCodeExpander.h + LegacyPathTranslation.h + Locale.h + log.h + logtypes.h + MathUtils.h + MemUtils.h + Mime.h + Observer.h + params_check_macros.h + POUtils.h + ProgressJob.h + RecentlyAddedJob.h + RegExp.h + rfft.h + RingBuffer.h + RssManager.h + RssReader.h + SaveFileStateJob.h + ScopeGuard.h + ScraperParser.h + ScraperUrl.h + Screenshot.h + SortUtils.h + Speed.h + StaticLoggerBase.h + Stopwatch.h + StreamDetails.h + StreamUtils.h + StringUtils.h + StringValidation.h + SystemInfo.h + Temperature.h + TextSearch.h + TimeUtils.h + TransformMatrix.h + URIUtils.h + UrlOptions.h + Utf8Utils.h + Variant.h + VC1BitstreamParser.h + Vector.h + XBMCTinyXML.h + XMLUtils.h) + +if(XSLT_FOUND) + list(APPEND SOURCES XSLTUtils.cpp) + list(APPEND HEADERS XSLTUtils.h) +endif() +if(EGL_FOUND) + list(APPEND SOURCES EGLUtils.cpp + EGLFence.cpp) + list(APPEND HEADERS EGLUtils.h + EGLFence.h) +endif() + +# The large map trips the clang optimizer +if(CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set_source_files_properties(Mime.cpp PROPERTIES COMPILE_FLAGS -O0) +endif() + +if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) + list(APPEND SOURCES GLUtils.cpp) + list(APPEND HEADERS GLUtils.h) +endif() + +if(CORE_PLATFORM_NAME_LC STREQUAL gbm OR CORE_PLATFORM_NAME_LC STREQUAL wayland) + list(APPEND SOURCES BufferObject.cpp + BufferObjectFactory.cpp + EGLImage.cpp) + list(APPEND HEADERS BufferObject.h + BufferObjectFactory.h + EGLImage.h) + + if(CORE_PLATFORM_NAME_LC STREQUAL gbm) + list(APPEND SOURCES DumbBufferObject.cpp) + list(APPEND SOURCES DumbBufferObject.h) + endif() + + if(HAVE_LINUX_MEMFD AND HAVE_LINUX_UDMABUF) + list(APPEND SOURCES UDMABufferObject.cpp) + list(APPEND HEADERS UDMABufferObject.h) + endif() + + if(HAVE_LINUX_DMA_HEAP) + list(APPEND SOURCES DMAHeapBufferObject.cpp) + list(APPEND HEADERS DMAHeapBufferObject.h) + endif() + + if(GBM_HAS_BO_MAP) + list(APPEND SOURCES GBMBufferObject.cpp) + list(APPEND HEADERS GBMBufferObject.h) + endif() +endif() + +core_add_library(utils) + +if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) + if(HAVE_SSE2) + target_compile_options(${CORE_LIBRARY} PRIVATE -msse2) + endif() +endif() diff --git a/xbmc/utils/CPUInfo.cpp b/xbmc/utils/CPUInfo.cpp new file mode 100644 index 0000000..d816d1e --- /dev/null +++ b/xbmc/utils/CPUInfo.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "CPUInfo.h" + +#include "utils/StringUtils.h" + +bool CCPUInfo::HasCoreId(int coreId) const +{ + for (const auto& core : m_cores) + { + if (core.m_id == coreId) + return true; + } + + return false; +} + +const CoreInfo CCPUInfo::GetCoreInfo(int coreId) +{ + CoreInfo coreInfo; + + for (auto& core : m_cores) + { + if (core.m_id == coreId) + coreInfo = core; + } + + return coreInfo; +} + +std::string CCPUInfo::GetCoresUsageString() const +{ + std::string strCores; + + if (SupportsCPUUsage()) + { + if (!m_cores.empty()) + { + for (const auto& core : m_cores) + { + if (!strCores.empty()) + strCores += ' '; + if (core.m_usagePercent < 10.0) + strCores += StringUtils::Format("#%d: %1.1f%%", core.m_id, core.m_usagePercent); + else + strCores += StringUtils::Format("#%d: %3.0f%%", core.m_id, core.m_usagePercent); + } + } + else + { + strCores += StringUtils::Format("%3.0f%%", static_cast(m_lastUsedPercentage)); + } + } + + return strCores; +} diff --git a/xbmc/utils/CPUInfo.h b/xbmc/utils/CPUInfo.h new file mode 100644 index 0000000..473402d --- /dev/null +++ b/xbmc/utils/CPUInfo.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "threads/SystemClock.h" +#include "utils/Temperature.h" + +#include +#include +#include + +enum CpuFeature +{ + CPU_FEATURE_MMX = 1 << 0, + CPU_FEATURE_MMX2 = 1 << 1, + CPU_FEATURE_SSE = 1 << 2, + CPU_FEATURE_SSE2 = 1 << 3, + CPU_FEATURE_SSE3 = 1 << 4, + CPU_FEATURE_SSSE3 = 1 << 5, + CPU_FEATURE_SSE4 = 1 << 6, + CPU_FEATURE_SSE42 = 1 << 7, + CPU_FEATURE_3DNOW = 1 << 8, + CPU_FEATURE_3DNOWEXT = 1 << 9, + CPU_FEATURE_ALTIVEC = 1 << 10, + CPU_FEATURE_NEON = 1 << 11, +}; + +struct CoreInfo +{ + int m_id = 0; + double m_usagePercent = 0.0; + std::size_t m_activeTime = 0; + std::size_t m_idleTime = 0; + std::size_t m_totalTime = 0; +}; + +class CCPUInfo +{ +public: + // Defines to help with calls to CPUID + const unsigned int CPUID_INFOTYPE_MANUFACTURER = 0x00000000; + const unsigned int CPUID_INFOTYPE_STANDARD = 0x00000001; + const unsigned int CPUID_INFOTYPE_EXTENDED_IMPLEMENTED = 0x80000000; + const unsigned int CPUID_INFOTYPE_EXTENDED = 0x80000001; + const unsigned int CPUID_INFOTYPE_PROCESSOR_1 = 0x80000002; + const unsigned int CPUID_INFOTYPE_PROCESSOR_2 = 0x80000003; + const unsigned int CPUID_INFOTYPE_PROCESSOR_3 = 0x80000004; + + // Standard Features + // Bitmasks for the values returned by a call to cpuid with eax=0x00000001 + const unsigned int CPUID_00000001_ECX_SSE3 = (1 << 0); + const unsigned int CPUID_00000001_ECX_SSSE3 = (1 << 9); + const unsigned int CPUID_00000001_ECX_SSE4 = (1 << 19); + const unsigned int CPUID_00000001_ECX_SSE42 = (1 << 20); + + const unsigned int CPUID_00000001_EDX_MMX = (1 << 23); + const unsigned int CPUID_00000001_EDX_SSE = (1 << 25); + const unsigned int CPUID_00000001_EDX_SSE2 = (1 << 26); + + // Extended Features + // Bitmasks for the values returned by a call to cpuid with eax=0x80000001 + const unsigned int CPUID_80000001_EDX_MMX2 = (1 << 22); + const unsigned int CPUID_80000001_EDX_MMX = (1 << 23); + const unsigned int CPUID_80000001_EDX_3DNOWEXT = (1 << 30); + const unsigned int CPUID_80000001_EDX_3DNOW = (1 << 31); + + // In milliseconds + const int MINIMUM_TIME_BETWEEN_READS{500}; + + static std::shared_ptr GetCPUInfo(); + + virtual bool SupportsCPUUsage() const { return true; } + + virtual int GetUsedPercentage() = 0; + virtual float GetCPUFrequency() = 0; + virtual bool GetTemperature(CTemperature& temperature) = 0; + + bool HasCoreId(int coreId) const; + const CoreInfo GetCoreInfo(int coreId); + std::string GetCoresUsageString() const; + + unsigned int GetCPUFeatures() const { return m_cpuFeatures; } + int GetCPUCount() const { return m_cpuCount; } + std::string GetCPUModel() { return m_cpuModel; } + std::string GetCPUBogoMips() { return m_cpuBogoMips; } + std::string GetCPUSoC() { return m_cpuSoC; } + std::string GetCPUHardware() { return m_cpuHardware; } + std::string GetCPURevision() { return m_cpuRevision; } + std::string GetCPUSerial() { return m_cpuSerial; } + +protected: + CCPUInfo() = default; + virtual ~CCPUInfo() = default; + + int m_lastUsedPercentage; + XbmcThreads::EndTime m_nextUsedReadTime; + std::string m_cpuVendor; + std::string m_cpuModel; + std::string m_cpuBogoMips; + std::string m_cpuSoC; + std::string m_cpuHardware; + std::string m_cpuRevision; + std::string m_cpuSerial; + + double m_usagePercent{0.0}; + std::size_t m_activeTime{0}; + std::size_t m_idleTime{0}; + std::size_t m_totalTime{0}; + + int m_cpuCount; + unsigned int m_cpuFeatures; + + std::vector m_cores; +}; diff --git a/xbmc/utils/CharsetConverter.cpp b/xbmc/utils/CharsetConverter.cpp new file mode 100644 index 0000000..8dffd65 --- /dev/null +++ b/xbmc/utils/CharsetConverter.cpp @@ -0,0 +1,871 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "CharsetConverter.h" + +#include "LangInfo.h" +#include "guilib/LocalizeStrings.h" +#include "log.h" +#include "settings/Settings.h" +#include "settings/lib/Setting.h" +#include "settings/lib/SettingDefinitions.h" +#include "utils/StringUtils.h" +#include "utils/Utf8Utils.h" + +#include + +#include +#include + +#ifdef WORDS_BIGENDIAN + #define ENDIAN_SUFFIX "BE" +#else + #define ENDIAN_SUFFIX "LE" +#endif + +#if defined(TARGET_DARWIN) + #define WCHAR_IS_UCS_4 1 + #define UTF16_CHARSET "UTF-16" ENDIAN_SUFFIX + #define UTF32_CHARSET "UTF-32" ENDIAN_SUFFIX + #define UTF8_SOURCE "UTF-8-MAC" + #define WCHAR_CHARSET UTF32_CHARSET +#elif defined(TARGET_WINDOWS) + #define WCHAR_IS_UTF16 1 + #define UTF16_CHARSET "UTF-16" ENDIAN_SUFFIX + #define UTF32_CHARSET "UTF-32" ENDIAN_SUFFIX + #define UTF8_SOURCE "UTF-8" + #define WCHAR_CHARSET UTF16_CHARSET +#elif defined(TARGET_FREEBSD) + #define WCHAR_IS_UCS_4 1 + #define UTF16_CHARSET "UTF-16" ENDIAN_SUFFIX + #define UTF32_CHARSET "UTF-32" ENDIAN_SUFFIX + #define UTF8_SOURCE "UTF-8" + #define WCHAR_CHARSET UTF32_CHARSET +#elif defined(TARGET_ANDROID) + #define WCHAR_IS_UCS_4 1 + #define UTF16_CHARSET "UTF-16" ENDIAN_SUFFIX + #define UTF32_CHARSET "UTF-32" ENDIAN_SUFFIX + #define UTF8_SOURCE "UTF-8" + #define WCHAR_CHARSET UTF32_CHARSET +#else + #define UTF16_CHARSET "UTF-16" ENDIAN_SUFFIX + #define UTF32_CHARSET "UTF-32" ENDIAN_SUFFIX + #define UTF8_SOURCE "UTF-8" + #define WCHAR_CHARSET "WCHAR_T" + #if __STDC_ISO_10646__ + #ifdef SIZEOF_WCHAR_T + #if SIZEOF_WCHAR_T == 4 + #define WCHAR_IS_UCS_4 1 + #elif SIZEOF_WCHAR_T == 2 + #define WCHAR_IS_UCS_2 1 + #endif + #endif + #endif +#endif + +#define NO_ICONV ((iconv_t)-1) + +enum SpecialCharset +{ + NotSpecialCharset = 0, + SystemCharset, + UserCharset /* locale.charset */, + SubtitleCharset /* subtitles.charset */, +}; + +class CConverterType : public CCriticalSection +{ +public: + CConverterType(const std::string& sourceCharset, const std::string& targetCharset, unsigned int targetSingleCharMaxLen = 1); + CConverterType(enum SpecialCharset sourceSpecialCharset, const std::string& targetCharset, unsigned int targetSingleCharMaxLen = 1); + CConverterType(const std::string& sourceCharset, enum SpecialCharset targetSpecialCharset, unsigned int targetSingleCharMaxLen = 1); + CConverterType(enum SpecialCharset sourceSpecialCharset, enum SpecialCharset targetSpecialCharset, unsigned int targetSingleCharMaxLen = 1); + CConverterType(const CConverterType& other); + ~CConverterType(); + + iconv_t GetConverter(CSingleLock& converterLock); + + void Reset(void); + void ReinitTo(const std::string& sourceCharset, const std::string& targetCharset, unsigned int targetSingleCharMaxLen = 1); + std::string GetSourceCharset(void) const { return m_sourceCharset; } + std::string GetTargetCharset(void) const { return m_targetCharset; } + unsigned int GetTargetSingleCharMaxLen(void) const { return m_targetSingleCharMaxLen; } + +private: + static std::string ResolveSpecialCharset(enum SpecialCharset charset); + + enum SpecialCharset m_sourceSpecialCharset; + std::string m_sourceCharset; + enum SpecialCharset m_targetSpecialCharset; + std::string m_targetCharset; + iconv_t m_iconv; + unsigned int m_targetSingleCharMaxLen; +}; + +CConverterType::CConverterType(const std::string& sourceCharset, const std::string& targetCharset, unsigned int targetSingleCharMaxLen /*= 1*/) : CCriticalSection(), + m_sourceSpecialCharset(NotSpecialCharset), + m_sourceCharset(sourceCharset), + m_targetSpecialCharset(NotSpecialCharset), + m_targetCharset(targetCharset), + m_iconv(NO_ICONV), + m_targetSingleCharMaxLen(targetSingleCharMaxLen) +{ +} + +CConverterType::CConverterType(enum SpecialCharset sourceSpecialCharset, const std::string& targetCharset, unsigned int targetSingleCharMaxLen /*= 1*/) : CCriticalSection(), + m_sourceSpecialCharset(sourceSpecialCharset), + m_sourceCharset(), + m_targetSpecialCharset(NotSpecialCharset), + m_targetCharset(targetCharset), + m_iconv(NO_ICONV), + m_targetSingleCharMaxLen(targetSingleCharMaxLen) +{ +} + +CConverterType::CConverterType(const std::string& sourceCharset, enum SpecialCharset targetSpecialCharset, unsigned int targetSingleCharMaxLen /*= 1*/) : CCriticalSection(), + m_sourceSpecialCharset(NotSpecialCharset), + m_sourceCharset(sourceCharset), + m_targetSpecialCharset(targetSpecialCharset), + m_targetCharset(), + m_iconv(NO_ICONV), + m_targetSingleCharMaxLen(targetSingleCharMaxLen) +{ +} + +CConverterType::CConverterType(enum SpecialCharset sourceSpecialCharset, enum SpecialCharset targetSpecialCharset, unsigned int targetSingleCharMaxLen /*= 1*/) : CCriticalSection(), + m_sourceSpecialCharset(sourceSpecialCharset), + m_sourceCharset(), + m_targetSpecialCharset(targetSpecialCharset), + m_targetCharset(), + m_iconv(NO_ICONV), + m_targetSingleCharMaxLen(targetSingleCharMaxLen) +{ +} + +CConverterType::CConverterType(const CConverterType& other) : CCriticalSection(), + m_sourceSpecialCharset(other.m_sourceSpecialCharset), + m_sourceCharset(other.m_sourceCharset), + m_targetSpecialCharset(other.m_targetSpecialCharset), + m_targetCharset(other.m_targetCharset), + m_iconv(NO_ICONV), + m_targetSingleCharMaxLen(other.m_targetSingleCharMaxLen) +{ +} + +CConverterType::~CConverterType() +{ + CSingleLock lock(*this); + if (m_iconv != NO_ICONV) + iconv_close(m_iconv); + lock.Leave(); // ensure unlocking before final destruction +} + +iconv_t CConverterType::GetConverter(CSingleLock& converterLock) +{ + // ensure that this unique instance is locked externally + if (&converterLock.get_underlying() != this) + return NO_ICONV; + + if (m_iconv == NO_ICONV) + { + if (m_sourceSpecialCharset) + m_sourceCharset = ResolveSpecialCharset(m_sourceSpecialCharset); + if (m_targetSpecialCharset) + m_targetCharset = ResolveSpecialCharset(m_targetSpecialCharset); + + m_iconv = iconv_open(m_targetCharset.c_str(), m_sourceCharset.c_str()); + + if (m_iconv == NO_ICONV) + CLog::Log(LOGERROR, "%s: iconv_open() for \"%s\" -> \"%s\" failed, errno = %d (%s)", + __FUNCTION__, m_sourceCharset.c_str(), m_targetCharset.c_str(), errno, strerror(errno)); + } + + return m_iconv; +} + +void CConverterType::Reset(void) +{ + CSingleLock lock(*this); + if (m_iconv != NO_ICONV) + { + iconv_close(m_iconv); + m_iconv = NO_ICONV; + } + + if (m_sourceSpecialCharset) + m_sourceCharset.clear(); + if (m_targetSpecialCharset) + m_targetCharset.clear(); + +} + +void CConverterType::ReinitTo(const std::string& sourceCharset, const std::string& targetCharset, unsigned int targetSingleCharMaxLen /*= 1*/) +{ + CSingleLock lock(*this); + if (sourceCharset != m_sourceCharset || targetCharset != m_targetCharset) + { + if (m_iconv != NO_ICONV) + { + iconv_close(m_iconv); + m_iconv = NO_ICONV; + } + + m_sourceSpecialCharset = NotSpecialCharset; + m_sourceCharset = sourceCharset; + m_targetSpecialCharset = NotSpecialCharset; + m_targetCharset = targetCharset; + m_targetSingleCharMaxLen = targetSingleCharMaxLen; + } +} + +std::string CConverterType::ResolveSpecialCharset(enum SpecialCharset charset) +{ + switch (charset) + { + case SystemCharset: + return ""; + case UserCharset: + return g_langInfo.GetGuiCharSet(); + case SubtitleCharset: + return g_langInfo.GetSubtitleCharSet(); + case NotSpecialCharset: + default: + return "UTF-8"; /* dummy value */ + } +} + +enum StdConversionType /* Keep it in sync with CCharsetConverter::CInnerConverter::m_stdConversion */ +{ + NoConversion = -1, + Utf8ToUtf32 = 0, + Utf32ToUtf8, + Utf32ToW, + WToUtf32, + SubtitleCharsetToUtf8, + Utf8ToUserCharset, + UserCharsetToUtf8, + Utf32ToUserCharset, + WtoUtf8, + Utf16LEtoW, + Utf16BEtoUtf8, + Utf16LEtoUtf8, + Utf8toW, + Utf8ToSystem, + SystemToUtf8, + Ucs2CharsetToUtf8, + NumberOfStdConversionTypes /* Dummy sentinel entry */ +}; + +/* We don't want to pollute header file with many additional includes and definitions, so put + here all staff that require usage of types defined in this file or in additional headers */ +class CCharsetConverter::CInnerConverter +{ +public: + static bool logicalToVisualBiDi(const std::u32string& stringSrc, + std::u32string& stringDst, + FriBidiCharType base = FRIBIDI_TYPE_LTR, + const bool failOnBadString = false, + int* visualToLogicalMap = nullptr); + + template + static bool stdConvert(StdConversionType convertType, const INPUT& strSource, OUTPUT& strDest, bool failOnInvalidChar = false); + template + static bool customConvert(const std::string& sourceCharset, const std::string& targetCharset, const INPUT& strSource, OUTPUT& strDest, bool failOnInvalidChar = false); + + template + static bool convert(iconv_t type, int multiplier, const INPUT& strSource, OUTPUT& strDest, bool failOnInvalidChar = false); + + static CConverterType m_stdConversion[NumberOfStdConversionTypes]; + static CCriticalSection m_critSectionFriBiDi; +}; + +/* single symbol sizes in chars */ +const int CCharsetConverter::m_Utf8CharMinSize = 1; +const int CCharsetConverter::m_Utf8CharMaxSize = 4; + +CConverterType CCharsetConverter::CInnerConverter::m_stdConversion[NumberOfStdConversionTypes] = /* keep it in sync with enum StdConversionType */ +{ + /* Utf8ToUtf32 */ CConverterType(UTF8_SOURCE, UTF32_CHARSET), + /* Utf32ToUtf8 */ CConverterType(UTF32_CHARSET, "UTF-8", CCharsetConverter::m_Utf8CharMaxSize), + /* Utf32ToW */ CConverterType(UTF32_CHARSET, WCHAR_CHARSET), + /* WToUtf32 */ CConverterType(WCHAR_CHARSET, UTF32_CHARSET), + /* SubtitleCharsetToUtf8*/CConverterType(SubtitleCharset, "UTF-8", CCharsetConverter::m_Utf8CharMaxSize), + /* Utf8ToUserCharset */ CConverterType(UTF8_SOURCE, UserCharset), + /* UserCharsetToUtf8 */ CConverterType(UserCharset, "UTF-8", CCharsetConverter::m_Utf8CharMaxSize), + /* Utf32ToUserCharset */ CConverterType(UTF32_CHARSET, UserCharset), + /* WtoUtf8 */ CConverterType(WCHAR_CHARSET, "UTF-8", CCharsetConverter::m_Utf8CharMaxSize), + /* Utf16LEtoW */ CConverterType("UTF-16LE", WCHAR_CHARSET), + /* Utf16BEtoUtf8 */ CConverterType("UTF-16BE", "UTF-8", CCharsetConverter::m_Utf8CharMaxSize), + /* Utf16LEtoUtf8 */ CConverterType("UTF-16LE", "UTF-8", CCharsetConverter::m_Utf8CharMaxSize), + /* Utf8toW */ CConverterType(UTF8_SOURCE, WCHAR_CHARSET), + /* Utf8ToSystem */ CConverterType(UTF8_SOURCE, SystemCharset), + /* SystemToUtf8 */ CConverterType(SystemCharset, UTF8_SOURCE), + /* Ucs2CharsetToUtf8 */ CConverterType("UCS-2LE", "UTF-8", CCharsetConverter::m_Utf8CharMaxSize) +}; + +CCriticalSection CCharsetConverter::CInnerConverter::m_critSectionFriBiDi; + +template +bool CCharsetConverter::CInnerConverter::stdConvert(StdConversionType convertType, const INPUT& strSource, OUTPUT& strDest, bool failOnInvalidChar /*= false*/) +{ + strDest.clear(); + if (strSource.empty()) + return true; + + if (convertType < 0 || convertType >= NumberOfStdConversionTypes) + return false; + + CConverterType& convType = m_stdConversion[convertType]; + CSingleLock converterLock(convType); + + return convert(convType.GetConverter(converterLock), convType.GetTargetSingleCharMaxLen(), strSource, strDest, failOnInvalidChar); +} + +template +bool CCharsetConverter::CInnerConverter::customConvert(const std::string& sourceCharset, const std::string& targetCharset, const INPUT& strSource, OUTPUT& strDest, bool failOnInvalidChar /*= false*/) +{ + strDest.clear(); + if (strSource.empty()) + return true; + + iconv_t conv = iconv_open(targetCharset.c_str(), sourceCharset.c_str()); + if (conv == NO_ICONV) + { + CLog::Log(LOGERROR, "%s: iconv_open() for \"%s\" -> \"%s\" failed, errno = %d (%s)", + __FUNCTION__, sourceCharset.c_str(), targetCharset.c_str(), errno, strerror(errno)); + return false; + } + const int dstMultp = (targetCharset.compare(0, 5, "UTF-8") == 0) ? CCharsetConverter::m_Utf8CharMaxSize : 1; + const bool result = convert(conv, dstMultp, strSource, strDest, failOnInvalidChar); + iconv_close(conv); + + return result; +} + +/* iconv may declare inbuf to be char** rather than const char** depending on platform and version, + so provide a wrapper that handles both */ +struct charPtrPtrAdapter +{ + const char** pointer; + explicit charPtrPtrAdapter(const char** p) : + pointer(p) { } + operator char**() + { return const_cast(pointer); } + operator const char**() + { return pointer; } +}; + +template +bool CCharsetConverter::CInnerConverter::convert(iconv_t type, int multiplier, const INPUT& strSource, OUTPUT& strDest, bool failOnInvalidChar /*= false*/) +{ + if (type == NO_ICONV) + return false; + + //input buffer for iconv() is the buffer from strSource + size_t inBufSize = (strSource.length() + 1) * sizeof(typename INPUT::value_type); + const char* inBuf = (const char*)strSource.c_str(); + + //allocate output buffer for iconv() + size_t outBufSize = (strSource.length() + 1) * sizeof(typename OUTPUT::value_type) * multiplier; + char* outBuf = (char*)malloc(outBufSize); + if (outBuf == NULL) + { + CLog::Log(LOGFATAL, "%s: malloc failed", __FUNCTION__); + return false; + } + + size_t inBytesAvail = inBufSize; //how many bytes iconv() can read + size_t outBytesAvail = outBufSize; //how many bytes iconv() can write + const char* inBufStart = inBuf; //where in our input buffer iconv() should start reading + char* outBufStart = outBuf; //where in out output buffer iconv() should start writing + + size_t returnV; + while(true) + { + //iconv() will update inBufStart, inBytesAvail, outBufStart and outBytesAvail + returnV = iconv(type, charPtrPtrAdapter(&inBufStart), &inBytesAvail, &outBufStart, &outBytesAvail); + + if (returnV == (size_t)-1) + { + if (errno == E2BIG) //output buffer is not big enough + { + //save where iconv() ended converting, realloc might make outBufStart invalid + size_t bytesConverted = outBufSize - outBytesAvail; + + //make buffer twice as big + outBufSize *= 2; + char* newBuf = (char*)realloc(outBuf, outBufSize); + if (!newBuf) + { + CLog::Log(LOGFATAL, "%s realloc failed with errno=%d(%s)", __FUNCTION__, errno, + strerror(errno)); + break; + } + outBuf = newBuf; + + //update the buffer pointer and counter + outBufStart = outBuf + bytesConverted; + outBytesAvail = outBufSize - bytesConverted; + + //continue in the loop and convert the rest + continue; + } + else if (errno == EILSEQ) //An invalid multibyte sequence has been encountered in the input + { + if (failOnInvalidChar) + break; + + //skip invalid byte + inBufStart++; + inBytesAvail--; + //continue in the loop and convert the rest + continue; + } + else if (errno == EINVAL) /* Invalid sequence at the end of input buffer */ + { + if (!failOnInvalidChar) + returnV = 0; /* reset error status to use converted part */ + + break; + } + else //iconv() had some other error + { + CLog::Log(LOGERROR, "%s: iconv() failed, errno=%d (%s)", + __FUNCTION__, errno, strerror(errno)); + } + } + break; + } + + //complete the conversion (reset buffers), otherwise the current data will prefix the data on the next call + if (iconv(type, NULL, NULL, &outBufStart, &outBytesAvail) == (size_t)-1) + CLog::Log(LOGERROR, "%s failed cleanup errno=%d(%s)", __FUNCTION__, errno, strerror(errno)); + + if (returnV == (size_t)-1) + { + free(outBuf); + return false; + } + //we're done + + const typename OUTPUT::size_type sizeInChars = (typename OUTPUT::size_type) (outBufSize - outBytesAvail) / sizeof(typename OUTPUT::value_type); + typename OUTPUT::const_pointer strPtr = (typename OUTPUT::const_pointer) outBuf; + /* Make sure that all buffer is assigned and string is stopped at end of buffer */ + if (strPtr[sizeInChars-1] == 0 && strSource[strSource.length()-1] != 0) + strDest.assign(strPtr, sizeInChars-1); + else + strDest.assign(strPtr, sizeInChars); + + free(outBuf); + + return true; +} + +bool CCharsetConverter::CInnerConverter::logicalToVisualBiDi( + const std::u32string& stringSrc, + std::u32string& stringDst, + FriBidiCharType base /*= FRIBIDI_TYPE_LTR*/, + const bool failOnBadString /*= false*/, + int* visualToLogicalMap /*= nullptr*/) +{ + stringDst.clear(); + + const size_t srcLen = stringSrc.length(); + if (srcLen == 0) + return true; + + stringDst.reserve(srcLen); + size_t lineStart = 0; + + // libfribidi is not threadsafe, so make sure we make it so + CSingleLock lock(m_critSectionFriBiDi); + do + { + size_t lineEnd = stringSrc.find('\n', lineStart); + if (lineEnd >= srcLen) // equal to 'lineEnd == std::string::npos' + lineEnd = srcLen; + else + lineEnd++; // include '\n' + + const size_t lineLen = lineEnd - lineStart; + + FriBidiChar* visual = (FriBidiChar*) malloc((lineLen + 1) * sizeof(FriBidiChar)); + if (visual == NULL) + { + free(visual); + CLog::Log(LOGFATAL, "%s: can't allocate memory", __FUNCTION__); + return false; + } + + bool bidiFailed = false; + FriBidiCharType baseCopy = base; // preserve same value for all lines, required because fribidi_log2vis will modify parameter value + if (fribidi_log2vis(reinterpret_cast(stringSrc.c_str() + lineStart), + lineLen, &baseCopy, visual, nullptr, + !visualToLogicalMap ? nullptr : visualToLogicalMap + lineStart, nullptr)) + { + // Removes bidirectional marks + const int newLen = fribidi_remove_bidi_marks( + visual, lineLen, nullptr, !visualToLogicalMap ? nullptr : visualToLogicalMap + lineStart, + nullptr); + if (newLen > 0) + stringDst.append((const char32_t*)visual, (size_t)newLen); + else if (newLen < 0) + bidiFailed = failOnBadString; + } + else + bidiFailed = failOnBadString; + + free(visual); + + if (bidiFailed) + return false; + + lineStart = lineEnd; + } while (lineStart < srcLen); + + return !stringDst.empty(); +} + +static struct SCharsetMapping +{ + const char* charset; + const char* caption; +} g_charsets[] = { + { "ISO-8859-1", "Western Europe (ISO)" } + , { "ISO-8859-2", "Central Europe (ISO)" } + , { "ISO-8859-3", "South Europe (ISO)" } + , { "ISO-8859-4", "Baltic (ISO)" } + , { "ISO-8859-5", "Cyrillic (ISO)" } + , { "ISO-8859-6", "Arabic (ISO)" } + , { "ISO-8859-7", "Greek (ISO)" } + , { "ISO-8859-8", "Hebrew (ISO)" } + , { "ISO-8859-9", "Turkish (ISO)" } + , { "CP1250", "Central Europe (Windows)" } + , { "CP1251", "Cyrillic (Windows)" } + , { "CP1252", "Western Europe (Windows)" } + , { "CP1253", "Greek (Windows)" } + , { "CP1254", "Turkish (Windows)" } + , { "CP1255", "Hebrew (Windows)" } + , { "CP1256", "Arabic (Windows)" } + , { "CP1257", "Baltic (Windows)" } + , { "CP1258", "Vietnamese (Windows)" } + , { "CP874", "Thai (Windows)" } + , { "BIG5", "Chinese Traditional (Big5)" } + , { "GBK", "Chinese Simplified (GBK)" } + , { "SHIFT_JIS", "Japanese (Shift-JIS)" } + , { "CP949", "Korean" } + , { "BIG5-HKSCS", "Hong Kong (Big5-HKSCS)" } + , { NULL, NULL } +}; + +CCharsetConverter::CCharsetConverter() = default; + +void CCharsetConverter::OnSettingChanged(std::shared_ptr setting) +{ + if (setting == NULL) + return; + + const std::string& settingId = setting->GetId(); + if (settingId == CSettings::SETTING_LOCALE_CHARSET) + resetUserCharset(); + else if (settingId == CSettings::SETTING_SUBTITLES_CHARSET) + resetSubtitleCharset(); +} + +void CCharsetConverter::clear() +{ +} + +std::vector CCharsetConverter::getCharsetLabels() +{ + std::vector lab; + for(SCharsetMapping* c = g_charsets; c->charset; c++) + lab.emplace_back(c->caption); + + return lab; +} + +std::string CCharsetConverter::getCharsetLabelByName(const std::string& charsetName) +{ + for(SCharsetMapping* c = g_charsets; c->charset; c++) + { + if (StringUtils::EqualsNoCase(charsetName,c->charset)) + return c->caption; + } + + return ""; +} + +std::string CCharsetConverter::getCharsetNameByLabel(const std::string& charsetLabel) +{ + for(SCharsetMapping* c = g_charsets; c->charset; c++) + { + if (StringUtils::EqualsNoCase(charsetLabel, c->caption)) + return c->charset; + } + + return ""; +} + +void CCharsetConverter::reset(void) +{ + for (CConverterType& conversion : CInnerConverter::m_stdConversion) + conversion.Reset(); +} + +void CCharsetConverter::resetSystemCharset(void) +{ + CInnerConverter::m_stdConversion[Utf8ToSystem].Reset(); + CInnerConverter::m_stdConversion[SystemToUtf8].Reset(); +} + +void CCharsetConverter::resetUserCharset(void) +{ + CInnerConverter::m_stdConversion[UserCharsetToUtf8].Reset(); + CInnerConverter::m_stdConversion[UserCharsetToUtf8].Reset(); + CInnerConverter::m_stdConversion[Utf32ToUserCharset].Reset(); + resetSubtitleCharset(); +} + +void CCharsetConverter::resetSubtitleCharset(void) +{ + CInnerConverter::m_stdConversion[SubtitleCharsetToUtf8].Reset(); +} + +void CCharsetConverter::reinitCharsetsFromSettings(void) +{ + resetUserCharset(); // this will also reinit Subtitle charsets +} + +bool CCharsetConverter::utf8ToUtf32(const std::string& utf8StringSrc, std::u32string& utf32StringDst, bool failOnBadChar /*= true*/) +{ + return CInnerConverter::stdConvert(Utf8ToUtf32, utf8StringSrc, utf32StringDst, failOnBadChar); +} + +std::u32string CCharsetConverter::utf8ToUtf32(const std::string& utf8StringSrc, bool failOnBadChar /*= true*/) +{ + std::u32string converted; + utf8ToUtf32(utf8StringSrc, converted, failOnBadChar); + return converted; +} + +bool CCharsetConverter::utf8ToUtf32Visual(const std::string& utf8StringSrc, std::u32string& utf32StringDst, bool bVisualBiDiFlip /*= false*/, bool forceLTRReadingOrder /*= false*/, bool failOnBadChar /*= false*/) +{ + if (bVisualBiDiFlip) + { + std::u32string converted; + if (!CInnerConverter::stdConvert(Utf8ToUtf32, utf8StringSrc, converted, failOnBadChar)) + return false; + + return CInnerConverter::logicalToVisualBiDi(converted, utf32StringDst, forceLTRReadingOrder ? FRIBIDI_TYPE_LTR : FRIBIDI_TYPE_PDF, failOnBadChar); + } + return CInnerConverter::stdConvert(Utf8ToUtf32, utf8StringSrc, utf32StringDst, failOnBadChar); +} + +bool CCharsetConverter::utf32ToUtf8(const std::u32string& utf32StringSrc, std::string& utf8StringDst, bool failOnBadChar /*= true*/) +{ + return CInnerConverter::stdConvert(Utf32ToUtf8, utf32StringSrc, utf8StringDst, failOnBadChar); +} + +std::string CCharsetConverter::utf32ToUtf8(const std::u32string& utf32StringSrc, bool failOnBadChar /*= false*/) +{ + std::string converted; + utf32ToUtf8(utf32StringSrc, converted, failOnBadChar); + return converted; +} + +bool CCharsetConverter::utf32ToW(const std::u32string& utf32StringSrc, std::wstring& wStringDst, bool failOnBadChar /*= true*/) +{ +#ifdef WCHAR_IS_UCS_4 + wStringDst.assign((const wchar_t*)utf32StringSrc.c_str(), utf32StringSrc.length()); + return true; +#else // !WCHAR_IS_UCS_4 + return CInnerConverter::stdConvert(Utf32ToW, utf32StringSrc, wStringDst, failOnBadChar); +#endif // !WCHAR_IS_UCS_4 +} + +bool CCharsetConverter::utf32logicalToVisualBiDi(const std::u32string& logicalStringSrc, + std::u32string& visualStringDst, + bool forceLTRReadingOrder /*= false*/, + bool failOnBadString /*= false*/, + int* visualToLogicalMap /*= nullptr*/) +{ + return CInnerConverter::logicalToVisualBiDi( + logicalStringSrc, visualStringDst, forceLTRReadingOrder ? FRIBIDI_TYPE_LTR : FRIBIDI_TYPE_PDF, + failOnBadString, visualToLogicalMap); +} + +bool CCharsetConverter::wToUtf32(const std::wstring& wStringSrc, std::u32string& utf32StringDst, bool failOnBadChar /*= true*/) +{ +#ifdef WCHAR_IS_UCS_4 + /* UCS-4 is almost equal to UTF-32, but UTF-32 has strict limits on possible values, while UCS-4 is usually unchecked. + * With this "conversion" we ensure that output will be valid UTF-32 string. */ +#endif + return CInnerConverter::stdConvert(WToUtf32, wStringSrc, utf32StringDst, failOnBadChar); +} + +// The bVisualBiDiFlip forces a flip of characters for hebrew/arabic languages, only set to false if the flipping +// of the string is already made or the string is not displayed in the GUI +bool CCharsetConverter::utf8ToW(const std::string& utf8StringSrc, std::wstring& wStringDst, bool bVisualBiDiFlip /*= true*/, + bool forceLTRReadingOrder /*= false*/, bool failOnBadChar /*= false*/) +{ + // Try to flip hebrew/arabic characters, if any + if (bVisualBiDiFlip) + { + wStringDst.clear(); + std::u32string utf32str; + if (!CInnerConverter::stdConvert(Utf8ToUtf32, utf8StringSrc, utf32str, failOnBadChar)) + return false; + + std::u32string utf32flipped; + const bool bidiResult = CInnerConverter::logicalToVisualBiDi(utf32str, utf32flipped, forceLTRReadingOrder ? FRIBIDI_TYPE_LTR : FRIBIDI_TYPE_PDF, failOnBadChar); + + return CInnerConverter::stdConvert(Utf32ToW, utf32flipped, wStringDst, failOnBadChar) && bidiResult; + } + + return CInnerConverter::stdConvert(Utf8toW, utf8StringSrc, wStringDst, failOnBadChar); +} + +bool CCharsetConverter::subtitleCharsetToUtf8(const std::string& stringSrc, std::string& utf8StringDst) +{ + return CInnerConverter::stdConvert(SubtitleCharsetToUtf8, stringSrc, utf8StringDst, false); +} + +bool CCharsetConverter::fromW(const std::wstring& wStringSrc, + std::string& stringDst, const std::string& enc) +{ + return CInnerConverter::customConvert(WCHAR_CHARSET, enc, wStringSrc, stringDst); +} + +bool CCharsetConverter::toW(const std::string& stringSrc, + std::wstring& wStringDst, const std::string& enc) +{ + return CInnerConverter::customConvert(enc, WCHAR_CHARSET, stringSrc, wStringDst); +} + +bool CCharsetConverter::utf8ToStringCharset(const std::string& utf8StringSrc, std::string& stringDst) +{ + return CInnerConverter::stdConvert(Utf8ToUserCharset, utf8StringSrc, stringDst); +} + +bool CCharsetConverter::utf8ToStringCharset(std::string& stringSrcDst) +{ + std::string strSrc(stringSrcDst); + return utf8ToStringCharset(strSrc, stringSrcDst); +} + +bool CCharsetConverter::ToUtf8(const std::string& strSourceCharset, const std::string& stringSrc, std::string& utf8StringDst, bool failOnBadChar /*= false*/) +{ + if (strSourceCharset == "UTF-8") + { // simple case - no conversion necessary + utf8StringDst = stringSrc; + return true; + } + + return CInnerConverter::customConvert(strSourceCharset, "UTF-8", stringSrc, utf8StringDst, failOnBadChar); +} + +bool CCharsetConverter::utf8To(const std::string& strDestCharset, const std::string& utf8StringSrc, std::string& stringDst) +{ + if (strDestCharset == "UTF-8") + { // simple case - no conversion necessary + stringDst = utf8StringSrc; + return true; + } + + return CInnerConverter::customConvert(UTF8_SOURCE, strDestCharset, utf8StringSrc, stringDst); +} + +bool CCharsetConverter::utf8To(const std::string& strDestCharset, const std::string& utf8StringSrc, std::u16string& utf16StringDst) +{ + return CInnerConverter::customConvert(UTF8_SOURCE, strDestCharset, utf8StringSrc, utf16StringDst); +} + +bool CCharsetConverter::utf8To(const std::string& strDestCharset, const std::string& utf8StringSrc, std::u32string& utf32StringDst) +{ + return CInnerConverter::customConvert(UTF8_SOURCE, strDestCharset, utf8StringSrc, utf32StringDst); +} + +bool CCharsetConverter::unknownToUTF8(std::string& stringSrcDst) +{ + std::string source(stringSrcDst); + return unknownToUTF8(source, stringSrcDst); +} + +bool CCharsetConverter::unknownToUTF8(const std::string& stringSrc, std::string& utf8StringDst, bool failOnBadChar /*= false*/) +{ + // checks whether it's utf8 already, and if not converts using the sourceCharset if given, else the string charset + if (CUtf8Utils::isValidUtf8(stringSrc)) + { + utf8StringDst = stringSrc; + return true; + } + return CInnerConverter::stdConvert(UserCharsetToUtf8, stringSrc, utf8StringDst, failOnBadChar); +} + +bool CCharsetConverter::wToUTF8(const std::wstring& wStringSrc, std::string& utf8StringDst, bool failOnBadChar /*= false*/) +{ + return CInnerConverter::stdConvert(WtoUtf8, wStringSrc, utf8StringDst, failOnBadChar); +} + +bool CCharsetConverter::utf16BEtoUTF8(const std::u16string& utf16StringSrc, std::string& utf8StringDst) +{ + return CInnerConverter::stdConvert(Utf16BEtoUtf8, utf16StringSrc, utf8StringDst); +} + +bool CCharsetConverter::utf16LEtoUTF8(const std::u16string& utf16StringSrc, + std::string& utf8StringDst) +{ + return CInnerConverter::stdConvert(Utf16LEtoUtf8, utf16StringSrc, utf8StringDst); +} + +bool CCharsetConverter::ucs2ToUTF8(const std::u16string& ucs2StringSrc, std::string& utf8StringDst) +{ + return CInnerConverter::stdConvert(Ucs2CharsetToUtf8, ucs2StringSrc,utf8StringDst); +} + +bool CCharsetConverter::utf16LEtoW(const std::u16string& utf16String, std::wstring& wString) +{ + return CInnerConverter::stdConvert(Utf16LEtoW, utf16String, wString); +} + +bool CCharsetConverter::utf32ToStringCharset(const std::u32string& utf32StringSrc, std::string& stringDst) +{ + return CInnerConverter::stdConvert(Utf32ToUserCharset, utf32StringSrc, stringDst); +} + +bool CCharsetConverter::utf8ToSystem(std::string& stringSrcDst, bool failOnBadChar /*= false*/) +{ + std::string strSrc(stringSrcDst); + return CInnerConverter::stdConvert(Utf8ToSystem, strSrc, stringSrcDst, failOnBadChar); +} + +bool CCharsetConverter::systemToUtf8(const std::string& sysStringSrc, std::string& utf8StringDst, bool failOnBadChar /*= false*/) +{ + return CInnerConverter::stdConvert(SystemToUtf8, sysStringSrc, utf8StringDst, failOnBadChar); +} + +bool CCharsetConverter::utf8logicalToVisualBiDi(const std::string& utf8StringSrc, std::string& utf8StringDst, bool failOnBadString /*= false*/) +{ + utf8StringDst.clear(); + std::u32string utf32flipped; + if (!utf8ToUtf32Visual(utf8StringSrc, utf32flipped, true, true, failOnBadString)) + return false; + + return CInnerConverter::stdConvert(Utf32ToUtf8, utf32flipped, utf8StringDst, failOnBadString); +} + +void CCharsetConverter::SettingOptionsCharsetsFiller(SettingConstPtr setting, std::vector& list, std::string& current, void *data) +{ + std::vector vecCharsets = g_charsetConverter.getCharsetLabels(); + sort(vecCharsets.begin(), vecCharsets.end(), sortstringbyname()); + + list.emplace_back(g_localizeStrings.Get(13278), "DEFAULT"); // "Default" + for (int i = 0; i < (int) vecCharsets.size(); ++i) + list.emplace_back(vecCharsets[i], g_charsetConverter.getCharsetNameByLabel(vecCharsets[i])); +} diff --git a/xbmc/utils/CharsetConverter.h b/xbmc/utils/CharsetConverter.h new file mode 100644 index 0000000..1c7e014 --- /dev/null +++ b/xbmc/utils/CharsetConverter.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "settings/lib/ISettingCallback.h" +#include "utils/GlobalsHandling.h" + +#include +#include +#include + +class CSetting; +struct StringSettingOption; + +class CCharsetConverter : public ISettingCallback +{ +public: + CCharsetConverter(); + + void OnSettingChanged(std::shared_ptr setting) override; + + static void reset(); + static void resetSystemCharset(); + static void reinitCharsetsFromSettings(void); + + static void clear(); + + /** + * Convert UTF-8 string to UTF-32 string. + * No RTL logical-visual transformation is performed. + * @param utf8StringSrc is source UTF-8 string to convert + * @param utf32StringDst is output UTF-32 string, empty on any error + * @param failOnBadChar if set to true function will fail on invalid character, + * otherwise invalid character will be skipped + * @return true on successful conversion, false on any error + */ + static bool utf8ToUtf32(const std::string& utf8StringSrc, std::u32string& utf32StringDst, bool failOnBadChar = true); + /** + * Convert UTF-8 string to UTF-32 string. + * No RTL logical-visual transformation is performed. + * @param utf8StringSrc is source UTF-8 string to convert + * @param failOnBadChar if set to true function will fail on invalid character, + * otherwise invalid character will be skipped + * @return converted string on successful conversion, empty string on any error + */ + static std::u32string utf8ToUtf32(const std::string& utf8StringSrc, bool failOnBadChar = true); + /** + * Convert UTF-8 string to UTF-32 string. + * RTL logical-visual transformation is optionally performed. + * Use it for readable text, GUI strings etc. + * @param utf8StringSrc is source UTF-8 string to convert + * @param utf32StringDst is output UTF-32 string, empty on any error + * @param bVisualBiDiFlip allow RTL visual-logical transformation if set to true, must be set + * to false is logical-visual transformation is already done + * @param forceLTRReadingOrder force LTR reading order + * @param failOnBadChar if set to true function will fail on invalid character, + * otherwise invalid character will be skipped + * @return true on successful conversion, false on any error + */ + static bool utf8ToUtf32Visual(const std::string& utf8StringSrc, std::u32string& utf32StringDst, bool bVisualBiDiFlip = false, bool forceLTRReadingOrder = false, bool failOnBadChar = false); + /** + * Convert UTF-32 string to UTF-8 string. + * No RTL visual-logical transformation is performed. + * @param utf32StringSrc is source UTF-32 string to convert + * @param utf8StringDst is output UTF-8 string, empty on any error + * @param failOnBadChar if set to true function will fail on invalid character, + * otherwise invalid character will be skipped + * @return true on successful conversion, false on any error + */ + static bool utf32ToUtf8(const std::u32string& utf32StringSrc, std::string& utf8StringDst, bool failOnBadChar = false); + /** + * Convert UTF-32 string to UTF-8 string. + * No RTL visual-logical transformation is performed. + * @param utf32StringSrc is source UTF-32 string to convert + * @param failOnBadChar if set to true function will fail on invalid character, + * otherwise invalid character will be skipped + * @return converted string on successful conversion, empty string on any error + */ + static std::string utf32ToUtf8(const std::u32string& utf32StringSrc, bool failOnBadChar = false); + /** + * Convert UTF-32 string to wchar_t string (wstring). + * No RTL visual-logical transformation is performed. + * @param utf32StringSrc is source UTF-32 string to convert + * @param wStringDst is output wchar_t string, empty on any error + * @param failOnBadChar if set to true function will fail on invalid character, + * otherwise invalid character will be skipped + * @return true on successful conversion, false on any error + */ + static bool utf32ToW(const std::u32string& utf32StringSrc, std::wstring& wStringDst, bool failOnBadChar = false); + /** + * Perform logical to visual flip. + * @param logicalStringSrc is source string with logical characters order + * @param visualStringDst is output string with visual characters order, empty on any error + * @param forceLTRReadingOrder force LTR reading order + * @param visualToLogicalMap is output mapping of positions in the visual string to the logical string + * @return true on success, false otherwise + */ + static bool utf32logicalToVisualBiDi(const std::u32string& logicalStringSrc, + std::u32string& visualStringDst, + bool forceLTRReadingOrder = false, + bool failOnBadString = false, + int* visualToLogicalMap = nullptr); + /** + * Strictly convert wchar_t string (wstring) to UTF-32 string. + * No RTL visual-logical transformation is performed. + * @param wStringSrc is source wchar_t string to convert + * @param utf32StringDst is output UTF-32 string, empty on any error + * @param failOnBadChar if set to true function will fail on invalid character, + * otherwise invalid character will be skipped + * @return true on successful conversion, false on any error + */ + static bool wToUtf32(const std::wstring& wStringSrc, std::u32string& utf32StringDst, bool failOnBadChar = false); + + static bool utf8ToW(const std::string& utf8StringSrc, std::wstring& wStringDst, + bool bVisualBiDiFlip = true, bool forceLTRReadingOrder = false, + bool failOnBadChar = false); + + static bool utf16LEtoW(const std::u16string& utf16String, std::wstring& wString); + + static bool subtitleCharsetToUtf8(const std::string& stringSrc, std::string& utf8StringDst); + + static bool utf8ToStringCharset(const std::string& utf8StringSrc, std::string& stringDst); + + static bool utf8ToStringCharset(std::string& stringSrcDst); + static bool utf8ToSystem(std::string& stringSrcDst, bool failOnBadChar = false); + static bool systemToUtf8(const std::string& sysStringSrc, std::string& utf8StringDst, bool failOnBadChar = false); + + static bool utf8To(const std::string& strDestCharset, const std::string& utf8StringSrc, std::string& stringDst); + static bool utf8To(const std::string& strDestCharset, const std::string& utf8StringSrc, std::u16string& utf16StringDst); + static bool utf8To(const std::string& strDestCharset, const std::string& utf8StringSrc, std::u32string& utf32StringDst); + + static bool ToUtf8(const std::string& strSourceCharset, const std::string& stringSrc, std::string& utf8StringDst, bool failOnBadChar = false); + + static bool wToUTF8(const std::wstring& wStringSrc, std::string& utf8StringDst, bool failOnBadChar = false); + static bool utf16BEtoUTF8(const std::u16string& utf16StringSrc, std::string& utf8StringDst); + static bool utf16LEtoUTF8(const std::u16string& utf16StringSrc, std::string& utf8StringDst); + static bool ucs2ToUTF8(const std::u16string& ucs2StringSrc, std::string& utf8StringDst); + + static bool utf8logicalToVisualBiDi(const std::string& utf8StringSrc, std::string& utf8StringDst, bool failOnBadString = false); + + static bool utf32ToStringCharset(const std::u32string& utf32StringSrc, std::string& stringDst); + + static std::vector getCharsetLabels(); + static std::string getCharsetLabelByName(const std::string& charsetName); + static std::string getCharsetNameByLabel(const std::string& charsetLabel); + + static bool unknownToUTF8(std::string& stringSrcDst); + static bool unknownToUTF8(const std::string& stringSrc, std::string& utf8StringDst, bool failOnBadChar = false); + + static bool toW(const std::string& stringSrc, std::wstring& wStringDst, const std::string& enc); + static bool fromW(const std::wstring& wStringSrc, std::string& stringDst, const std::string& enc); + + static void SettingOptionsCharsetsFiller(std::shared_ptr setting, std::vector& list, std::string& current, void *data); +private: + static void resetUserCharset(void); + static void resetSubtitleCharset(void); + + static const int m_Utf8CharMinSize, m_Utf8CharMaxSize; + class CInnerConverter; +}; + +XBMC_GLOBAL_REF(CCharsetConverter,g_charsetConverter); +#define g_charsetConverter XBMC_GLOBAL_USE(CCharsetConverter) diff --git a/xbmc/utils/CharsetDetection.cpp b/xbmc/utils/CharsetDetection.cpp new file mode 100644 index 0000000..06a0416 --- /dev/null +++ b/xbmc/utils/CharsetDetection.cpp @@ -0,0 +1,639 @@ +/* + * Copyright (C) 2013-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "CharsetDetection.h" + +#include "LangInfo.h" +#include "utils/CharsetConverter.h" +#include "utils/StringUtils.h" +#include "utils/Utf8Utils.h" +#include "utils/log.h" + +#include + +/* XML declaration can be virtually any size (with many-many whitespaces) + * but for in real world we don't need to process megabytes of data + * so limit search for XML declaration to reasonable value */ +const size_t CCharsetDetection::m_XmlDeclarationMaxLength = 250; + +/* According to http://www.w3.org/TR/2013/CR-html5-20130806/single-page.html#charset + * encoding must be placed in first 1024 bytes of document */ +const size_t CCharsetDetection::m_HtmlCharsetEndSearchPos = 1024; + +/* According to http://www.w3.org/TR/2013/CR-html5-20130806/single-page.html#space-character + * tab, LF, FF, CR or space can be used as whitespace */ +const std::string CCharsetDetection::m_HtmlWhitespaceChars("\x09\x0A\x0C\x0D\x20"); // tab, LF, FF, CR and space + +std::string CCharsetDetection::GetBomEncoding(const char* const content, const size_t contentLength) +{ + if (contentLength < 2) + return ""; + if (content[0] == (char)0xFE && content[1] == (char)0xFF) + return "UTF-16BE"; + if (contentLength >= 4 && content[0] == (char)0xFF && content[1] == (char)0xFE && content[2] == (char)0x00 && content[3] == (char)0x00) + return "UTF-32LE"; /* first two bytes are same for UTF-16LE and UTF-32LE, so first check for full UTF-32LE mark */ + if (content[0] == (char)0xFF && content[1] == (char)0xFE) + return "UTF-16LE"; + if (contentLength < 3) + return ""; + if (content[0] == (char)0xEF && content[1] == (char)0xBB && content[2] == (char)0xBF) + return "UTF-8"; + if (contentLength < 4) + return ""; + if (content[0] == (char)0x00 && content[1] == (char)0x00 && content[2] == (char)0xFE && content[3] == (char)0xFF) + return "UTF-32BE"; + if (contentLength >= 5 && content[0] == (char)0x2B && content[1] == (char)0x2F && content[2] == (char)0x76 && + (content[4] == (char)0x32 || content[4] == (char)0x39 || content[4] == (char)0x2B || content[4] == (char)0x2F)) + return "UTF-7"; + if (content[0] == (char)0x84 && content[1] == (char)0x31 && content[2] == (char)0x95 && content[3] == (char)0x33) + return "GB18030"; + + return ""; +} + +bool CCharsetDetection::DetectXmlEncoding(const char* const xmlContent, const size_t contentLength, std::string& detectedEncoding) +{ + detectedEncoding.clear(); + + if (contentLength < 2) + return false; // too short for any detection + + /* Byte Order Mark has priority over "encoding=" parameter */ + detectedEncoding = GetBomEncoding(xmlContent, contentLength); + if (!detectedEncoding.empty()) + return true; + + /* try to read encoding from XML declaration */ + if (GetXmlEncodingFromDeclaration(xmlContent, contentLength, detectedEncoding)) + { + StringUtils::ToUpper(detectedEncoding); + + /* make some safety checks */ + if (detectedEncoding == "UTF-8") + return true; // fast track for most common case + + if (StringUtils::StartsWith(detectedEncoding, "UCS-") || StringUtils::StartsWith(detectedEncoding, "UTF-")) + { + if (detectedEncoding == "UTF-7") + return true; + + /* XML declaration was detected in UTF-8 mode (by 'GetXmlEncodingFromDeclaration') so we know + * that text in single byte encoding, but declaration itself wrongly specify multibyte encoding */ + detectedEncoding.clear(); + return false; + } + return true; + } + + /* try to detect basic encoding */ + std::string guessedEncoding; + if (!GuessXmlEncoding(xmlContent, contentLength, guessedEncoding)) + return false; /* can't detect any encoding */ + + /* have some guessed encoding, try to use it */ + std::string convertedXml; + /* use 'm_XmlDeclarationMaxLength * 4' below for UTF-32-like encodings */ + if (!g_charsetConverter.ToUtf8(guessedEncoding, std::string(xmlContent, std::min(contentLength, m_XmlDeclarationMaxLength * 4)), convertedXml) + || convertedXml.empty()) + return false; /* can't convert, guessed encoding is wrong */ + + /* text converted, hopefully at least XML declaration is in UTF-8 now */ + std::string declaredEncoding; + /* try to read real encoding from converted XML declaration */ + if (!GetXmlEncodingFromDeclaration(convertedXml.c_str(), convertedXml.length(), declaredEncoding)) + { /* did not find real encoding in XML declaration, use guessed encoding */ + detectedEncoding = guessedEncoding; + return true; + } + + /* found encoding in converted XML declaration, we know correct endianness and number of bytes per char */ + /* make some safety checks */ + StringUtils::ToUpper(declaredEncoding); + if (declaredEncoding == guessedEncoding) + return true; + + if (StringUtils::StartsWith(guessedEncoding, "UCS-4")) + { + if (declaredEncoding.length() < 5 || + (!StringUtils::StartsWith(declaredEncoding, "UTF-32") && !StringUtils::StartsWith(declaredEncoding, "UCS-4"))) + { /* Guessed encoding was correct because we can convert and read XML declaration, but declaration itself is wrong (not 4-bytes encoding) */ + detectedEncoding = guessedEncoding; + return true; + } + } + else if (StringUtils::StartsWith(guessedEncoding, "UTF-16")) + { + if (declaredEncoding.length() < 5 || + (!StringUtils::StartsWith(declaredEncoding, "UTF-16") && !StringUtils::StartsWith(declaredEncoding, "UCS-2"))) + { /* Guessed encoding was correct because we can read XML declaration, but declaration is wrong (not 2-bytes encoding) */ + detectedEncoding = guessedEncoding; + return true; + } + } + + if (StringUtils::StartsWith(guessedEncoding, "UCS-4") || StringUtils::StartsWith(guessedEncoding, "UTF-16")) + { + /* Check endianness in declared encoding. We already know correct endianness as XML declaration was detected after conversion. */ + /* Guessed UTF/UCS encoding always ends with endianness */ + std::string guessedEndianness(guessedEncoding, guessedEncoding.length() - 2); + + if (!StringUtils::EndsWith(declaredEncoding, "BE") && !StringUtils::EndsWith(declaredEncoding, "LE")) /* Declared encoding without endianness */ + detectedEncoding = declaredEncoding + guessedEndianness; /* add guessed endianness */ + else if (!StringUtils::EndsWith(declaredEncoding, guessedEndianness)) /* Wrong endianness in declared encoding */ + detectedEncoding = declaredEncoding.substr(0, declaredEncoding.length() - 2) + guessedEndianness; /* replace endianness by guessed endianness */ + else + detectedEncoding = declaredEncoding; /* declared encoding with correct endianness */ + + return true; + } + else if (StringUtils::StartsWith(guessedEncoding, "EBCDIC")) + { + if (declaredEncoding.find("EBCDIC") != std::string::npos) + detectedEncoding = declaredEncoding; /* Declared encoding is some specific EBCDIC encoding */ + else + detectedEncoding = guessedEncoding; + + return true; + } + + /* should be unreachable */ + return false; +} + +bool CCharsetDetection::GetXmlEncodingFromDeclaration(const char* const xmlContent, const size_t contentLength, std::string& declaredEncoding) +{ + // following code is std::string-processing analog of regular expression-processing + // regular expression: "<\\?xml([ \n\r\t]+[^ \n\t\r>]+)*[ \n\r\t]+encoding[ \n\r\t]*=[ \n\r\t]*('[^ \n\t\r>']+'|\"[^ \n\t\r>\"]+\")" + // on win32 x86 machine regular expression is slower that std::string 20-40 times and can slowdown XML processing for several times + // seems that this regular expression is too slow due to many variable length parts, regexp for '&'-fixing is much faster + + declaredEncoding.clear(); + + // avoid extra large search + std::string strXml(xmlContent, std::min(contentLength, m_XmlDeclarationMaxLength)); + + size_t pos = strXml.find(" strXml.length() || pos > strXml.find('<')) + return false; // no "', pos) - pos); + const std::string xmlDecl(xmlContent + pos, declLength); + const char* const xmlDeclC = xmlDecl.c_str(); // for faster processing of [] and for null-termination + + static const char* const whiteSpaceChars = " \n\r\t"; // according to W3C Recommendation for XML, any of them can be used as separator + pos = 0; + + while (pos + 12 <= declLength) // 12 is minimal length of "encoding='x'" + { + pos = xmlDecl.find_first_of(whiteSpaceChars, pos); + if (pos == std::string::npos) + return false; // no " encoding=" in declaration + + pos = xmlDecl.find_first_not_of(whiteSpaceChars, pos); + if (pos == std::string::npos) + return false; // no "encoding=" in declaration + + if (xmlDecl.compare(pos, 8, "encoding", 8) != 0) + continue; // not "encoding" parameter + pos += 8; // length of "encoding" + + if (xmlDeclC[pos] == ' ' || xmlDeclC[pos] == '\n' || xmlDeclC[pos] == '\r' || xmlDeclC[pos] == '\t') // no buffer overrun as string is null-terminated + { + pos = xmlDecl.find_first_not_of(whiteSpaceChars, pos); + if (pos == std::string::npos) + return false; // this " encoding" is incomplete, only whitespace chars remains + } + if (xmlDeclC[pos] != '=') + { // "encoding" without "=", try to find other + pos--; // step back to whitespace + continue; + } + + pos++; // skip '=' + if (xmlDeclC[pos] == ' ' || xmlDeclC[pos] == '\n' || xmlDeclC[pos] == '\r' || xmlDeclC[pos] == '\t') // no buffer overrun as string is null-terminated + { + pos = xmlDecl.find_first_not_of(whiteSpaceChars, pos); + if (pos == std::string::npos) + return false; // this " encoding" is incomplete, only whitespace chars remains + } + size_t encNameEndPos; + if (xmlDeclC[pos] == '"') + encNameEndPos = xmlDecl.find('"', ++pos); + else if (xmlDeclC[pos] == '\'') + encNameEndPos = xmlDecl.find('\'', ++pos); + else + continue; // no quote or double quote after 'encoding=', try to find other + + if (encNameEndPos != std::string::npos) + { + declaredEncoding.assign(xmlDecl, pos, encNameEndPos - pos); + return true; + } + // no closing quote or double quote after 'encoding="x', try to find other + } + + return false; +} + +bool CCharsetDetection::GuessXmlEncoding(const char* const xmlContent, const size_t contentLength, std::string& supposedEncoding) +{ + supposedEncoding.clear(); + if (contentLength < 4) + return false; // too little data to guess + + if (xmlContent[0] == 0 && xmlContent[1] == 0 && xmlContent[2] == 0 && xmlContent[3] == (char)0x3C) // '<' == '00 00 00 3C' in UCS-4 (UTF-32) big-endian + supposedEncoding = "UCS-4BE"; // use UCS-4 according to W3C recommendation + else if (xmlContent[0] == (char)0x3C && xmlContent[1] == 0 && xmlContent[2] == 0 && xmlContent[3] == 0) // '<' == '3C 00 00 00' in UCS-4 (UTF-32) little-endian + supposedEncoding = "UCS-4LE"; // use UCS-4 according to W3C recommendation + else if (xmlContent[0] == 0 && xmlContent[1] == (char)0x3C && xmlContent[2] == 0 && xmlContent[3] == (char)0x3F) // " 2 * m_HtmlCharsetEndSearchPos) + smallerHtmlContent.assign(htmlContent, 0, 2 * m_HtmlCharsetEndSearchPos); // use twice more bytes to search for charset for safety + + const std::string& html = smallerHtmlContent.empty() ? htmlContent : smallerHtmlContent; // limit search + const char* const htmlC = html.c_str(); // for null-termination + const size_t len = html.length(); + + // this is an implementation of http://www.w3.org/TR/2013/CR-html5-20130806/single-page.html#prescan-a-byte-stream-to-determine-its-encoding + // labels in comments correspond to the labels in HTML5 standard + // note: opposite to standard, everything is converted to uppercase instead of lower case + size_t pos = 0; + while (pos < len) // "loop" label + { + if (html.compare(pos, 4, "", pos + 2); + if (pos == std::string::npos) + return ""; + pos += 2; + } + else if (htmlC[pos] == '<' && (htmlC[pos + 1] == 'm' || htmlC[pos + 1] == 'M') && (htmlC[pos + 2] == 'e' || htmlC[pos + 2] == 'E') + && (htmlC[pos + 3] == 't' || htmlC[pos + 3] == 'T') && (htmlC[pos + 4] == 'a' || htmlC[pos + 4] == 'A') + && (htmlC[pos + 5] == 0x09 || htmlC[pos + 5] == 0x0A || htmlC[pos + 5] == 0x0C || htmlC[pos + 5] == 0x0D || htmlC[pos + 5] == 0x20 || htmlC[pos + 5] == 0x2F)) + { // this is case insensitive "= 'A' && htmlC[pos + 1] <= 'Z') || (htmlC[pos + 1] >= 'a' && htmlC[pos + 1] <= 'z'))) + { + pos = html.find_first_of("\x09\x0A\x0C\x0D >", pos); // tab, LF, FF, CR, space or '>' + std::string attrName, attrValue; + do + { + pos = GetHtmlAttribute(html, pos, attrName, attrValue); + } while (pos < len && !attrName.empty()); + } + else if (html.compare(pos, 2, "', pos); + + if (pos == std::string::npos) + return ""; + + // "next byte" label + pos++; + } + + return ""; // no charset was found +} + +size_t CCharsetDetection::GetHtmlAttribute(const std::string& htmlContent, size_t pos, std::string& attrName, std::string& attrValue) +{ + attrName.clear(); + attrValue.clear(); + static const char* const htmlWhitespaceSlash = "\x09\x0A\x0C\x0D\x20\x2F"; // tab, LF, FF, CR, space or slash + const char* const htmlC = htmlContent.c_str(); + const size_t len = htmlContent.length(); + + // this is an implementation of http://www.w3.org/TR/2013/CR-html5-20130806/single-page.html#concept-get-attributes-when-sniffing + // labels in comments correspond to the labels in HTML5 standard + // note: opposite to standard, everything is converted to uppercase instead of lower case + pos = htmlContent.find_first_not_of(htmlWhitespaceSlash, pos); + if (pos == std::string::npos || htmlC[pos] == '>') + return pos; // only white spaces or slashes up to the end of the htmlContent or no more attributes + + while (pos < len && htmlC[pos] != '=') + { + const char chr = htmlC[pos]; + if (chr == '/' || chr == '>') + return pos; // no attributes or empty attribute value + else if (m_HtmlWhitespaceChars.find(chr) != std::string::npos) // chr is one of whitespaces + { + pos = htmlContent.find_first_not_of(m_HtmlWhitespaceChars, pos); // "spaces" label + if (pos == std::string::npos || htmlC[pos] != '=') + return pos; // only white spaces up to the end or no attribute value + break; + } + else + appendCharAsAsciiUpperCase(attrName, chr); + + pos++; + } + + if (pos >= len) + return std::string::npos; // no '=', '/' or '>' were found up to the end of htmlContent + + pos++; // advance pos to character after '=' + + pos = htmlContent.find_first_not_of(m_HtmlWhitespaceChars, pos); // "value" label + if (pos == std::string::npos) + return pos; // only white spaces remain in htmlContent + + if (htmlC[pos] == '>') + return pos; // empty attribute value + else if (htmlC[pos] == '"' || htmlC[pos] == '\'') + { + const char qChr = htmlC[pos]; + // "quote loop" label + while (++pos < len) + { + const char chr = htmlC[pos]; + if (chr == qChr) + return pos + 1; + else + appendCharAsAsciiUpperCase(attrValue, chr); + } + return std::string::npos; // no closing quote is found + } + + appendCharAsAsciiUpperCase(attrValue, htmlC[pos]); + pos++; + + while (pos < len) + { + const char chr = htmlC[pos]; + if (m_HtmlWhitespaceChars.find(chr) != std::string::npos || chr == '>') + return pos; + else + appendCharAsAsciiUpperCase(attrValue, chr); + + pos++; + } + + return std::string::npos; // rest of htmlContent was attribute value +} + +std::string CCharsetDetection::ExtractEncodingFromHtmlMeta(std::string metaContent, size_t pos /*= 0*/) +{ + size_t len = metaContent.length(); + if (pos >= len) + return ""; + + const char* const metaContentC = metaContent.c_str(); + + // this is an implementation of http://www.w3.org/TR/2013/CR-html5-20130806/single-page.html#algorithm-for-extracting-a-character-encoding-from-a-meta-element + // labels in comments correspond to the labels in HTML5 standard + // note: opposite to standard, case sensitive match is used as argument is always in uppercase + std::string charset; + do + { + // "loop" label + pos = metaContent.find("CHARSET", pos); + if (pos == std::string::npos) + return ""; + + pos = metaContent.find_first_not_of(m_HtmlWhitespaceChars, pos + 7); // '7' is the length of 'CHARSET' + if (pos != std::string::npos && metaContentC[pos] == '=') + { + pos = metaContent.find_first_not_of(m_HtmlWhitespaceChars, pos + 1); + if (pos != std::string::npos) + { + if (metaContentC[pos] == '\'' || metaContentC[pos] == '"') + { + const char qChr = metaContentC[pos]; + pos++; + const size_t closeQpos = metaContent.find(qChr, pos); + if (closeQpos != std::string::npos) + charset.assign(metaContent, pos, closeQpos - pos); + } + else + charset.assign(metaContent, pos, metaContent.find("\x09\x0A\x0C\x0D ;", pos) - pos); // assign content up to the next tab, LF, FF, CR, space, semicolon or end of string + } + break; + } + } while (pos < len); + + static const char* const htmlWhitespaceCharsC = m_HtmlWhitespaceChars.c_str(); + StringUtils::Trim(charset, htmlWhitespaceCharsC); + + return charset; +} + +inline void CCharsetDetection::appendCharAsAsciiUpperCase(std::string& str, const char chr) +{ + if (chr >= 'a' && chr <= 'z') + str.push_back(chr - ('a' - 'A')); // convert to upper case + else + str.push_back(chr); +} diff --git a/xbmc/utils/CharsetDetection.h b/xbmc/utils/CharsetDetection.h new file mode 100644 index 0000000..1ff3905 --- /dev/null +++ b/xbmc/utils/CharsetDetection.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2013-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + + +class CCharsetDetection +{ +public: + /** + * Detect text encoding by Byte Order Mark + * Multibyte encodings (UTF-16/32) always ends with explicit endianness (LE/BE) + * @param content pointer to text to analyze + * @param contentLength length of text + * @return detected encoding or empty string if BOM not detected + */ + static std::string GetBomEncoding(const char* const content, const size_t contentLength); + /** + * Detect text encoding by Byte Order Mark + * Multibyte encodings (UTF-16/32) always ends with explicit endianness (LE/BE) + * @param content the text to analyze + * @return detected encoding or empty string if BOM not detected + */ + static inline std::string GetBomEncoding(const std::string& content) + { return GetBomEncoding(content.c_str(), content.length()); } + + static inline bool DetectXmlEncoding(const std::string& xmlContent, std::string& detectedEncoding) + { return DetectXmlEncoding(xmlContent.c_str(), xmlContent.length(), detectedEncoding); } + + static bool DetectXmlEncoding(const char* const xmlContent, const size_t contentLength, std::string& detectedEncoding); + + /** + * Detect HTML charset and HTML convert to UTF-8 + * @param htmlContent content of HTML file + * @param converted receive result of conversion + * @param serverReportedCharset charset from HTTP header or from other out-of-band source, empty if unknown or unset + * @return true if charset is properly detected and HTML is correctly converted, false if charset is only guessed + */ + static inline bool ConvertHtmlToUtf8(const std::string& htmlContent, std::string& converted, const std::string& serverReportedCharset = "") + { + std::string usedHtmlCharset; + return ConvertHtmlToUtf8(htmlContent, converted, serverReportedCharset, usedHtmlCharset); + } + /** + * Detect HTML charset and HTML convert to UTF-8 + * @param htmlContent content of HTML file + * @param converted receive result of conversion + * @param serverReportedCharset charset from HTTP header or from other out-of-band source, empty if unknown or unset + * @param usedHtmlCharset receive charset used for conversion + * @return true if charset is properly detected and HTML is correctly converted, false if charset is only guessed + */ + static bool ConvertHtmlToUtf8(const std::string& htmlContent, std::string& converted, const std::string& serverReportedCharset, std::string& usedHtmlCharset); + + /** + * Try to convert plain text to UTF-8 using best suitable charset + * @param textContent text to convert + * @param converted receive result of conversion + * @param serverReportedCharset charset from HTTP header or from other out-of-band source, empty if unknown or unset + * @param usedCharset receive charset used for conversion + * @return true if converted without errors, false otherwise + */ + static bool ConvertPlainTextToUtf8(const std::string& textContent, std::string& converted, const std::string& serverReportedCharset, std::string& usedCharset); + +private: + static bool GetXmlEncodingFromDeclaration(const char* const xmlContent, const size_t contentLength, std::string& declaredEncoding); + /** + * Try to guess text encoding by searching for ' + +namespace UTILS +{ + + typedef uint32_t Color; + +namespace COLOR +{ + static const Color NONE = 0x00000000; + static const Color BLACK = 0xFF000000; + static const Color YELLOW = 0xFFFFFF00; + static const Color WHITE = 0xFFFFFFFF; + static const Color LIGHTGREY = 0xFFE5E5E5; + static const Color GREY = 0xFFC0C0C0; + static const Color BLUE = 0xFF0099FF; + static const Color BRIGHTGREEN = 0xFF00FF00; + static const Color YELLOWGREEN = 0xFFCCFF00; + static const Color CYAN = 0xFF00FFFF; + static const Color DARKGREY = 0xFF808080; +} // namespace COLOR +} // namespace UTILS diff --git a/xbmc/utils/ColorUtils.cpp b/xbmc/utils/ColorUtils.cpp new file mode 100644 index 0000000..80319a0 --- /dev/null +++ b/xbmc/utils/ColorUtils.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ColorUtils.h" + +#include "Color.h" + +#include + +UTILS::Color ColorUtils::ChangeOpacity(const UTILS::Color color, const float opacity) +{ + int newAlpha = ceil( ((color >> 24) & 0xff) * opacity); + return (color & 0x00FFFFFF) | (newAlpha << 24); +}; diff --git a/xbmc/utils/ColorUtils.h b/xbmc/utils/ColorUtils.h new file mode 100644 index 0000000..9522a76 --- /dev/null +++ b/xbmc/utils/ColorUtils.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "Color.h" + +class ColorUtils +{ + public: + /*! \brief Change the opacity of a given color + + \param color The original color + \param opacity The opacity value as a float + \return the original color with the changed opacity/alpha value + */ + static UTILS::Color ChangeOpacity(const UTILS::Color color, const float opacity); +}; diff --git a/xbmc/utils/Crc32.cpp b/xbmc/utils/Crc32.cpp new file mode 100644 index 0000000..4e002b4 --- /dev/null +++ b/xbmc/utils/Crc32.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Crc32.h" + +#include "utils/StringUtils.h" + +uint32_t crc_tab[256] = +{ + 0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L, + 0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L, + 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L, + 0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL, + 0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L, + 0x5F15ADACL, 0x5BD4B01BL, 0x569796C2L, 0x52568B75L, + 0x6A1936C8L, 0x6ED82B7FL, 0x639B0DA6L, 0x675A1011L, + 0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL, 0x745E66CDL, + 0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L, + 0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L, + 0xBE2B5B58L, 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L, + 0xAD2F2D84L, 0xA9EE3033L, 0xA4AD16EAL, 0xA06C0B5DL, + 0xD4326D90L, 0xD0F37027L, 0xDDB056FEL, 0xD9714B49L, + 0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L, + 0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L, + 0xE13EF6F4L, 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL, + 0x34867077L, 0x30476DC0L, 0x3D044B19L, 0x39C556AEL, + 0x278206ABL, 0x23431B1CL, 0x2E003DC5L, 0x2AC12072L, + 0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L, + 0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL, + 0x7897AB07L, 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL, + 0x6B93DDDBL, 0x6F52C06CL, 0x6211E6B5L, 0x66D0FB02L, + 0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L, 0x53DC6066L, + 0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL, + 0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL, + 0xBFA1B04BL, 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L, + 0x8AAD2B2FL, 0x8E6C3698L, 0x832F1041L, 0x87EE0DF6L, + 0x99A95DF3L, 0x9D684044L, 0x902B669DL, 0x94EA7B2AL, + 0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL, + 0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L, + 0xC6BCF05FL, 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L, + 0xD5B88683L, 0xD1799B34L, 0xDC3ABDEDL, 0xD8FBA05AL, + 0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L, 0x644FC637L, + 0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL, + 0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL, + 0x5C007B8AL, 0x58C1663DL, 0x558240E4L, 0x51435D53L, + 0x251D3B9EL, 0x21DC2629L, 0x2C9F00F0L, 0x285E1D47L, + 0x36194D42L, 0x32D850F5L, 0x3F9B762CL, 0x3B5A6B9BL, + 0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL, + 0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L, + 0xF12F560EL, 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L, + 0xE22B20D2L, 0xE6EA3D65L, 0xEBA91BBCL, 0xEF68060BL, + 0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L, 0xDA649D6FL, + 0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L, + 0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L, + 0xAE3AFBA2L, 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL, + 0x9B3660C6L, 0x9FF77D71L, 0x92B45BA8L, 0x9675461FL, + 0x8832161AL, 0x8CF30BADL, 0x81B02D74L, 0x857130C3L, + 0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L, + 0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL, + 0x7B827D21L, 0x7F436096L, 0x7200464FL, 0x76C15BF8L, + 0x68860BFDL, 0x6C47164AL, 0x61043093L, 0x65C52D24L, + 0x119B4BE9L, 0x155A565EL, 0x18197087L, 0x1CD86D30L, + 0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL, + 0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L, + 0x2497D08DL, 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L, + 0xC5A92679L, 0xC1683BCEL, 0xCC2B1D17L, 0xC8EA00A0L, + 0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL, 0xDBEE767CL, + 0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L, + 0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L, + 0x89B8FD09L, 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L, + 0x9ABC8BD5L, 0x9E7D9662L, 0x933EB0BBL, 0x97FFAD0CL, + 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L, + 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L +}; + +Crc32::Crc32() +{ + Reset(); +} + +void Crc32::Reset() +{ + m_crc = 0xFFFFFFFF; +} + +void Crc32::Compute(const char* buffer, size_t count) +{ + while (count--) + m_crc = (m_crc << 8) ^ crc_tab[((m_crc >> 24) ^ *buffer++) & 0xFF]; +} + +uint32_t Crc32::Compute(const std::string& strValue) +{ + Crc32 crc; + crc.Compute(strValue.c_str(), strValue.size()); + return crc; +} + +uint32_t Crc32::ComputeFromLowerCase(const std::string& strValue) +{ + std::string strLower = strValue; + StringUtils::ToLower(strLower); + return Compute(strLower.c_str()); +} + diff --git a/xbmc/utils/Crc32.h b/xbmc/utils/Crc32.h new file mode 100644 index 0000000..f4a3588 --- /dev/null +++ b/xbmc/utils/Crc32.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include + +class Crc32 +{ +public: + Crc32(); + void Reset(); + void Compute(const char* buffer, size_t count); + static uint32_t Compute(const std::string& strValue); + static uint32_t ComputeFromLowerCase(const std::string& strValue); + + operator uint32_t () const + { + return m_crc; + } + +private: + uint32_t m_crc; +}; + diff --git a/xbmc/utils/CryptThreading.cpp b/xbmc/utils/CryptThreading.cpp new file mode 100644 index 0000000..3484635 --- /dev/null +++ b/xbmc/utils/CryptThreading.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "CryptThreading.h" +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) + +#include "threads/Thread.h" +#include "utils/log.h" + +#include + +namespace +{ + +CCriticalSection* getlock(int index) +{ + return g_cryptThreadingInitializer.GetLock(index); +} + +void lock_callback(int mode, int type, const char* file, int line) +{ + if (mode & CRYPTO_LOCK) + getlock(type)->lock(); + else + getlock(type)->unlock(); +} + +unsigned long GetCryptThreadId() +{ + static std::atomic tidSequence{0}; + static thread_local unsigned long tidTl{0}; + + if (tidTl == 0) + tidTl = ++tidSequence; + return tidTl; +} + +void thread_id(CRYPTO_THREADID* tid) +{ + // C-style cast required due to vastly differing native ID return types + CRYPTO_THREADID_set_numeric(tid, GetCryptThreadId()); +} + +} + +CryptThreadingInitializer::CryptThreadingInitializer() +{ + // OpenSSL < 1.1 needs integration code to support multi-threading + // This is absolutely required for libcurl if it uses the OpenSSL backend + m_locks.resize(CRYPTO_num_locks()); + CRYPTO_THREADID_set_callback(thread_id); + CRYPTO_set_locking_callback(lock_callback); +} + +CryptThreadingInitializer::~CryptThreadingInitializer() +{ + CSingleLock l(m_locksLock); + CRYPTO_set_locking_callback(nullptr); + m_locks.clear(); +} + +CCriticalSection* CryptThreadingInitializer::GetLock(int index) +{ + CSingleLock l(m_locksLock); + auto& curlock = m_locks[index]; + if (!curlock) + { + curlock.reset(new CCriticalSection()); + } + + return curlock.get(); +} + +unsigned long CryptThreadingInitializer::GetCurrentCryptThreadId() +{ + return GetCryptThreadId(); +} + +#endif diff --git a/xbmc/utils/CryptThreading.h b/xbmc/utils/CryptThreading.h new file mode 100644 index 0000000..85ec044 --- /dev/null +++ b/xbmc/utils/CryptThreading.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +//! @todo - once we're at OpenSSL 1.1 this class and its .cpp file should be deleted. +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) + +#include +#include +#include "utils/GlobalsHandling.h" +#include "threads/CriticalSection.h" + +class CryptThreadingInitializer +{ + std::vector> m_locks; + CCriticalSection m_locksLock; + +public: + CryptThreadingInitializer(); + ~CryptThreadingInitializer(); + + CCriticalSection* GetLock(int index); + + /** + * This is so testing can reach the thread id generation. + */ + unsigned long GetCurrentCryptThreadId(); + +private: + CryptThreadingInitializer(const CryptThreadingInitializer &rhs) = delete; + CryptThreadingInitializer& operator=(const CryptThreadingInitializer&) = delete; +}; + +XBMC_GLOBAL_REF(CryptThreadingInitializer,g_cryptThreadingInitializer); +#define g_cryptThreadingInitializer XBMC_GLOBAL_USE(CryptThreadingInitializer) + +#endif diff --git a/xbmc/utils/DMAHeapBufferObject.cpp b/xbmc/utils/DMAHeapBufferObject.cpp new file mode 100644 index 0000000..c9beeb5 --- /dev/null +++ b/xbmc/utils/DMAHeapBufferObject.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "DMAHeapBufferObject.h" + +#include "ServiceBroker.h" +#include "utils/BufferObjectFactory.h" +#include "utils/log.h" + +#include + +#include +#include +#include +#include + +namespace +{ + +std::array DMA_HEAP_PATHS = { + "/dev/dma_heap/reserved", + "/dev/dma_heap/linux,cma", + "/dev/dma_heap/system", +}; + +static const char* DMA_HEAP_PATH; + +} // namespace + +std::unique_ptr CDMAHeapBufferObject::Create() +{ + return std::make_unique(); +} + +void CDMAHeapBufferObject::Register() +{ + for (auto path : DMA_HEAP_PATHS) + { + int fd = open(path, O_RDWR); + if (fd < 0) + { + CLog::Log(LOGDEBUG, "CDMAHeapBufferObject::{} unable to open {}: {}", __FUNCTION__, path, + strerror(errno)); + continue; + } + + close(fd); + DMA_HEAP_PATH = path; + break; + } + + if (!DMA_HEAP_PATH) + return; + + CLog::Log(LOGDEBUG, "CDMAHeapBufferObject::{} - using {}", __FUNCTION__, DMA_HEAP_PATH); + + CBufferObjectFactory::RegisterBufferObject(CDMAHeapBufferObject::Create); +} + +CDMAHeapBufferObject::~CDMAHeapBufferObject() +{ + ReleaseMemory(); + DestroyBufferObject(); + + close(m_dmaheapfd); + m_dmaheapfd = -1; +} + +bool CDMAHeapBufferObject::CreateBufferObject(uint32_t format, uint32_t width, uint32_t height) +{ + if (m_fd >= 0) + return true; + + uint32_t bpp{1}; + + switch (format) + { + case DRM_FORMAT_ARGB8888: + bpp = 4; + break; + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_RGB565: + bpp = 2; + break; + default: + throw std::runtime_error("CDMAHeapBufferObject: pixel format not implemented"); + } + + m_stride = width * bpp; + + return CreateBufferObject(width * height * bpp); +} + +bool CDMAHeapBufferObject::CreateBufferObject(uint64_t size) +{ + m_size = size; + + if (m_dmaheapfd < 0) + { + m_dmaheapfd = open(DMA_HEAP_PATH, O_RDWR); + if (m_dmaheapfd < 0) + { + CLog::LogF(LOGERROR, "failed to open {}:", DMA_HEAP_PATH, strerror(errno)); + return false; + } + } + + struct dma_heap_allocation_data allocData = { + .len = m_size, .fd_flags = (O_CLOEXEC | O_RDWR), .heap_flags = 0}; + + int ret = ioctl(m_dmaheapfd, DMA_HEAP_IOCTL_ALLOC, &allocData); + if (ret < 0) + { + CLog::Log(LOGERROR, "CDMAHeapBufferObject::{} - ioctl DMA_HEAP_IOCTL_ALLOC failed, errno={}", + __FUNCTION__, strerror(errno)); + return false; + } + + m_fd = allocData.fd; + m_size = allocData.len; + + if (m_fd < 0 || m_size <= 0) + { + CLog::Log(LOGERROR, "CDMAHeapBufferObject::{} - invalid allocation data: fd={} len={}", + __FUNCTION__, m_fd, m_size); + return false; + } + + return true; +} + +void CDMAHeapBufferObject::DestroyBufferObject() +{ + if (m_fd < 0) + return; + + int ret = close(m_fd); + if (ret < 0) + CLog::Log(LOGERROR, "CDMAHeapBufferObject::{} - close failed, errno={}", __FUNCTION__, + strerror(errno)); + + m_fd = -1; + m_stride = 0; + m_size = 0; +} + +uint8_t* CDMAHeapBufferObject::GetMemory() +{ + if (m_fd < 0) + return nullptr; + + if (m_map) + { + CLog::Log(LOGDEBUG, "CDMAHeapBufferObject::{} - already mapped fd={} map={}", __FUNCTION__, + m_fd, fmt::ptr(m_map)); + return m_map; + } + + m_map = static_cast(mmap(nullptr, m_size, PROT_WRITE, MAP_SHARED, m_fd, 0)); + if (m_map == MAP_FAILED) + { + CLog::Log(LOGERROR, "CDMAHeapBufferObject::{} - mmap failed, errno={}", __FUNCTION__, + strerror(errno)); + return nullptr; + } + + return m_map; +} + +void CDMAHeapBufferObject::ReleaseMemory() +{ + if (!m_map) + return; + + int ret = munmap(m_map, m_size); + if (ret < 0) + CLog::Log(LOGERROR, "CDMAHeapBufferObject::{} - munmap failed, errno={}", __FUNCTION__, + strerror(errno)); + + m_map = nullptr; +} diff --git a/xbmc/utils/DMAHeapBufferObject.h b/xbmc/utils/DMAHeapBufferObject.h new file mode 100644 index 0000000..eb7a6fe --- /dev/null +++ b/xbmc/utils/DMAHeapBufferObject.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/BufferObject.h" + +#include +#include + +class CDMAHeapBufferObject : public CBufferObject +{ +public: + CDMAHeapBufferObject() = default; + virtual ~CDMAHeapBufferObject() override; + + // Registration + static std::unique_ptr Create(); + static void Register(); + + // IBufferObject overrides via CBufferObject + bool CreateBufferObject(uint32_t format, uint32_t width, uint32_t height) override; + bool CreateBufferObject(uint64_t size) override; + void DestroyBufferObject() override; + uint8_t* GetMemory() override; + void ReleaseMemory() override; + std::string GetName() const override { return "CDMAHeapBufferObject"; } + +private: + int m_dmaheapfd{-1}; + uint64_t m_size{0}; + uint8_t* m_map{nullptr}; +}; diff --git a/xbmc/utils/DatabaseUtils.cpp b/xbmc/utils/DatabaseUtils.cpp new file mode 100644 index 0000000..fdff052 --- /dev/null +++ b/xbmc/utils/DatabaseUtils.cpp @@ -0,0 +1,745 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "DatabaseUtils.h" + +#include "dbwrappers/dataset.h" +#include "music/MusicDatabase.h" +#include "utils/StringUtils.h" +#include "utils/Variant.h" +#include "utils/log.h" +#include "video/VideoDatabase.h" + +#include + +MediaType DatabaseUtils::MediaTypeFromVideoContentType(int videoContentType) +{ + VIDEODB_CONTENT_TYPE type = (VIDEODB_CONTENT_TYPE)videoContentType; + switch (type) + { + case VIDEODB_CONTENT_MOVIES: + return MediaTypeMovie; + + case VIDEODB_CONTENT_MOVIE_SETS: + return MediaTypeVideoCollection; + + case VIDEODB_CONTENT_TVSHOWS: + return MediaTypeTvShow; + + case VIDEODB_CONTENT_EPISODES: + return MediaTypeEpisode; + + case VIDEODB_CONTENT_MUSICVIDEOS: + return MediaTypeMusicVideo; + + default: + break; + } + + return MediaTypeNone; +} + +std::string DatabaseUtils::GetField(Field field, const MediaType &mediaType, DatabaseQueryPart queryPart) +{ + if (field == FieldNone || mediaType == MediaTypeNone) + return ""; + + if (mediaType == MediaTypeAlbum) + { + if (field == FieldId) return "albumview.idAlbum"; + else if (field == FieldAlbum) return "albumview.strAlbum"; + else if (field == FieldArtist || field == FieldAlbumArtist) return "albumview.strArtists"; + else if (field == FieldGenre) + return "albumview.strGenres"; + else if (field == FieldYear) + return "albumview.strReleaseDate"; + else if (field == FieldOrigYear || field == FieldOrigDate) + return "albumview.strOrigReleaseDate"; + else if (field == FieldMoods) return "albumview.strMoods"; + else if (field == FieldStyles) return "albumview.strStyles"; + else if (field == FieldThemes) return "albumview.strThemes"; + else if (field == FieldReview) return "albumview.strReview"; + else if (field == FieldMusicLabel) return "albumview.strLabel"; + else if (field == FieldAlbumType) return "albumview.strType"; + else if (field == FieldCompilation) return "albumview.bCompilation"; + else if (field == FieldRating) return "albumview.fRating"; + else if (field == FieldVotes) return "albumview.iVotes"; + else if (field == FieldUserRating) return "albumview.iUserrating"; + else if (field == FieldDateAdded) return "albumview.dateAdded"; + else if (field == FieldDateNew) return "albumview.dateNew"; + else if (field == FieldDateModified) return "albumview.dateModified"; + else if (field == FieldPlaycount) return "albumview.iTimesPlayed"; + else if (field == FieldLastPlayed) return "albumview.lastPlayed"; + else if (field == FieldTotalDiscs) + return "albumview.iDiscTotal"; + else if (field == FieldAlbumStatus) + return "albumview.strReleaseStatus"; + } + else if (mediaType == MediaTypeSong) + { + if (field == FieldId) return "songview.idSong"; + else if (field == FieldTitle) return "songview.strTitle"; + else if (field == FieldTrackNumber) return "songview.iTrack"; + else if (field == FieldTime) return "songview.iDuration"; + else if (field == FieldYear) + return "songview.strReleaseDate"; + else if (field == FieldOrigYear || field == FieldOrigDate) + return "songview.strOrigReleaseDate"; + else if (field == FieldFilename) return "songview.strFilename"; + else if (field == FieldPlaycount) return "songview.iTimesPlayed"; + else if (field == FieldStartOffset) return "songview.iStartOffset"; + else if (field == FieldEndOffset) return "songview.iEndOffset"; + else if (field == FieldLastPlayed) return "songview.lastPlayed"; + else if (field == FieldRating) return "songview.rating"; + else if (field == FieldVotes) return "songview.votes"; + else if (field == FieldUserRating) return "songview.userrating"; + else if (field == FieldComment) return "songview.comment"; + else if (field == FieldMoods) return "songview.mood"; + else if (field == FieldAlbum) return "songview.strAlbum"; + else if (field == FieldPath) return "songview.strPath"; + else if (field == FieldArtist || field == FieldAlbumArtist) return "songview.strArtists"; + else if (field == FieldGenre) + return "songview.strGenres"; + else if (field == FieldDateAdded) return "songview.dateAdded"; + else if (field == FieldDateNew) return "songview.dateNew"; + else if (field == FieldDateModified) return "songview.dateModified"; + + else if (field == FieldDiscTitle) + return "songview.strDiscSubtitle"; + else if (field == FieldBPM) + return "songview.iBPM"; + else if (field == FieldMusicBitRate) + return "songview.iBitRate"; + else if (field == FieldSampleRate) + return "songview.iSampleRate"; + else if (field == FieldNoOfChannels) + return "songview.iChannels"; + } + else if (mediaType == MediaTypeArtist) + { + if (field == FieldId) return "artistview.idArtist"; + else if (field == FieldArtistSort) return "artistview.strSortName"; + else if (field == FieldArtist) return "artistview.strArtist"; + else if (field == FieldArtistType) return "artistview.strType"; + else if (field == FieldGender) return "artistview.strGender"; + else if (field == FieldDisambiguation) return "artistview.strDisambiguation"; + else if (field == FieldGenre) return "artistview.strGenres"; + else if (field == FieldMoods) return "artistview.strMoods"; + else if (field == FieldStyles) return "artistview.strStyles"; + else if (field == FieldInstruments) return "artistview.strInstruments"; + else if (field == FieldBiography) return "artistview.strBiography"; + else if (field == FieldBorn) return "artistview.strBorn"; + else if (field == FieldBandFormed) return "artistview.strFormed"; + else if (field == FieldDisbanded) return "artistview.strDisbanded"; + else if (field == FieldDied) return "artistview.strDied"; + else if (field == FieldDateAdded) return "artistview.dateAdded"; + else if (field == FieldDateNew) return "artistview.dateNew"; + else if (field == FieldDateModified) return "artistview.dateModified"; + } + else if (mediaType == MediaTypeMusicVideo) + { + std::string result; + if (field == FieldId) return "musicvideo_view.idMVideo"; + else if (field == FieldTitle) result = StringUtils::Format("musicvideo_view.c%02d",VIDEODB_ID_MUSICVIDEO_TITLE); + else if (field == FieldTime) result = StringUtils::Format("musicvideo_view.c%02d", VIDEODB_ID_MUSICVIDEO_RUNTIME); + else if (field == FieldDirector) result = StringUtils::Format("musicvideo_view.c%02d", VIDEODB_ID_MUSICVIDEO_DIRECTOR); + else if (field == FieldStudio) result = StringUtils::Format("musicvideo_view.c%02d", VIDEODB_ID_MUSICVIDEO_STUDIOS); + else if (field == FieldYear) return "musicvideo_view.premiered"; + else if (field == FieldPlot) result = StringUtils::Format("musicvideo_view.c%02d", VIDEODB_ID_MUSICVIDEO_PLOT); + else if (field == FieldAlbum) result = StringUtils::Format("musicvideo_view.c%02d",VIDEODB_ID_MUSICVIDEO_ALBUM); + else if (field == FieldArtist) result = StringUtils::Format("musicvideo_view.c%02d", VIDEODB_ID_MUSICVIDEO_ARTIST); + else if (field == FieldGenre) result = StringUtils::Format("musicvideo_view.c%02d", VIDEODB_ID_MUSICVIDEO_GENRE); + else if (field == FieldTrackNumber) result = StringUtils::Format("musicvideo_view.c%02d", VIDEODB_ID_MUSICVIDEO_TRACK); + else if (field == FieldFilename) return "musicvideo_view.strFilename"; + else if (field == FieldPath) return "musicvideo_view.strPath"; + else if (field == FieldPlaycount) return "musicvideo_view.playCount"; + else if (field == FieldLastPlayed) return "musicvideo_view.lastPlayed"; + else if (field == FieldDateAdded) return "musicvideo_view.dateAdded"; + else if (field == FieldUserRating) return "musicvideo_view.userrating"; + + if (!result.empty()) + return result; + } + else if (mediaType == MediaTypeMovie) + { + std::string result; + if (field == FieldId) return "movie_view.idMovie"; + else if (field == FieldTitle) + { + // We need some extra logic to get the title value if sorttitle isn't set + if (queryPart == DatabaseQueryPartOrderBy) + result = StringUtils::Format("CASE WHEN length(movie_view.c%02d) > 0 THEN movie_view.c%02d ELSE movie_view.c%02d END", VIDEODB_ID_SORTTITLE, VIDEODB_ID_SORTTITLE, VIDEODB_ID_TITLE); + else + result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_TITLE); + } + else if (field == FieldPlot) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_PLOT); + else if (field == FieldPlotOutline) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_PLOTOUTLINE); + else if (field == FieldTagline) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_TAGLINE); + else if (field == FieldVotes) return "movie_view.votes"; + else if (field == FieldRating) return "movie_view.rating"; + else if (field == FieldWriter) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_CREDITS); + else if (field == FieldYear) return "movie_view.premiered"; + else if (field == FieldSortTitle) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_SORTTITLE); + else if (field == FieldOriginalTitle) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_ORIGINALTITLE); + else if (field == FieldTime) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_RUNTIME); + else if (field == FieldMPAA) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_MPAA); + else if (field == FieldTop250) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_TOP250); + else if (field == FieldSet) return "movie_view.strSet"; + else if (field == FieldGenre) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_GENRE); + else if (field == FieldDirector) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_DIRECTOR); + else if (field == FieldStudio) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_STUDIOS); + else if (field == FieldTrailer) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_TRAILER); + else if (field == FieldCountry) result = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_COUNTRY); + else if (field == FieldFilename) return "movie_view.strFilename"; + else if (field == FieldPath) return "movie_view.strPath"; + else if (field == FieldPlaycount) return "movie_view.playCount"; + else if (field == FieldLastPlayed) return "movie_view.lastPlayed"; + else if (field == FieldDateAdded) return "movie_view.dateAdded"; + else if (field == FieldUserRating) return "movie_view.userrating"; + + if (!result.empty()) + return result; + } + else if (mediaType == MediaTypeTvShow) + { + std::string result; + if (field == FieldId) return "tvshow_view.idShow"; + else if (field == FieldTitle) + { + // We need some extra logic to get the title value if sorttitle isn't set + if (queryPart == DatabaseQueryPartOrderBy) + result = StringUtils::Format("CASE WHEN length(tvshow_view.c%02d) > 0 THEN tvshow_view.c%02d ELSE tvshow_view.c%02d END", VIDEODB_ID_TV_SORTTITLE, VIDEODB_ID_TV_SORTTITLE, VIDEODB_ID_TV_TITLE); + else + result = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_TITLE); + } + else if (field == FieldPlot) result = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_PLOT); + else if (field == FieldTvShowStatus) result = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_STATUS); + else if (field == FieldVotes) return "tvshow_view.votes"; + else if (field == FieldRating) return "tvshow_view.rating"; + else if (field == FieldYear) result = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_PREMIERED); + else if (field == FieldGenre) result = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_GENRE); + else if (field == FieldMPAA) result = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_MPAA); + else if (field == FieldStudio) result = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_STUDIOS); + else if (field == FieldSortTitle) result = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_SORTTITLE); + else if (field == FieldOriginalTitle) result = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_ORIGINALTITLE); + else if (field == FieldPath) return "tvshow_view.strPath"; + else if (field == FieldDateAdded) return "tvshow_view.dateAdded"; + else if (field == FieldLastPlayed) return "tvshow_view.lastPlayed"; + else if (field == FieldSeason) return "tvshow_view.totalSeasons"; + else if (field == FieldNumberOfEpisodes) return "tvshow_view.totalCount"; + else if (field == FieldNumberOfWatchedEpisodes) return "tvshow_view.watchedcount"; + else if (field == FieldUserRating) return "tvshow_view.userrating"; + + if (!result.empty()) + return result; + } + else if (mediaType == MediaTypeEpisode) + { + std::string result; + if (field == FieldId) return "episode_view.idEpisode"; + else if (field == FieldTitle) result = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_TITLE); + else if (field == FieldPlot) result = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_PLOT); + else if (field == FieldVotes) return "episode_view.votes"; + else if (field == FieldRating) return "episode_view.rating"; + else if (field == FieldWriter) result = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_CREDITS); + else if (field == FieldAirDate) result = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_AIRED); + else if (field == FieldTime) result = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_RUNTIME); + else if (field == FieldDirector) result = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_DIRECTOR); + else if (field == FieldSeason) result = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_SEASON); + else if (field == FieldEpisodeNumber) result = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_EPISODE); + else if (field == FieldUniqueId) result = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_IDENT_ID); + else if (field == FieldEpisodeNumberSpecialSort) result = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_SORTEPISODE); + else if (field == FieldSeasonSpecialSort) result = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_SORTSEASON); + else if (field == FieldFilename) return "episode_view.strFilename"; + else if (field == FieldPath) return "episode_view.strPath"; + else if (field == FieldPlaycount) return "episode_view.playCount"; + else if (field == FieldLastPlayed) return "episode_view.lastPlayed"; + else if (field == FieldDateAdded) return "episode_view.dateAdded"; + else if (field == FieldTvShowTitle) return "episode_view.strTitle"; + else if (field == FieldYear) return "episode_view.premiered"; + else if (field == FieldMPAA) return "episode_view.mpaa"; + else if (field == FieldStudio) return "episode_view.strStudio"; + else if (field == FieldUserRating) return "episode_view.userrating"; + + if (!result.empty()) + return result; + } + + if (field == FieldRandom && queryPart == DatabaseQueryPartOrderBy) + return "RANDOM()"; + + return ""; +} + +int DatabaseUtils::GetField(Field field, const MediaType &mediaType) +{ + if (field == FieldNone || mediaType == MediaTypeNone) + return -1; + + return GetField(field, mediaType, false); +} + +int DatabaseUtils::GetFieldIndex(Field field, const MediaType &mediaType) +{ + if (field == FieldNone || mediaType == MediaTypeNone) + return -1; + + return GetField(field, mediaType, true); +} + +bool DatabaseUtils::GetSelectFields(const Fields &fields, const MediaType &mediaType, FieldList &selectFields) +{ + if (mediaType == MediaTypeNone || fields.empty()) + return false; + + Fields sortFields = fields; + + // add necessary fields to create the label + if (mediaType == MediaTypeSong || mediaType == MediaTypeVideo || mediaType == MediaTypeVideoCollection || + mediaType == MediaTypeMusicVideo || mediaType == MediaTypeMovie || mediaType == MediaTypeTvShow || mediaType == MediaTypeEpisode) + sortFields.insert(FieldTitle); + if (mediaType == MediaTypeEpisode) + { + sortFields.insert(FieldSeason); + sortFields.insert(FieldEpisodeNumber); + } + else if (mediaType == MediaTypeAlbum) + sortFields.insert(FieldAlbum); + else if (mediaType == MediaTypeSong) + sortFields.insert(FieldTrackNumber); + else if (mediaType == MediaTypeArtist) + sortFields.insert(FieldArtist); + + selectFields.clear(); + for (Fields::const_iterator it = sortFields.begin(); it != sortFields.end(); ++it) + { + // ignore FieldLabel because it needs special handling (see further up) + if (*it == FieldLabel) + continue; + + if (GetField(*it, mediaType, DatabaseQueryPartSelect).empty()) + { + CLog::Log(LOGDEBUG, "DatabaseUtils::GetSortFieldList: unknown field %d", *it); + continue; + } + selectFields.push_back(*it); + } + + return !selectFields.empty(); +} + +bool DatabaseUtils::GetFieldValue(const dbiplus::field_value &fieldValue, CVariant &variantValue) +{ + if (fieldValue.get_isNull()) + { + variantValue = CVariant::ConstNullVariant; + return true; + } + + switch (fieldValue.get_fType()) + { + case dbiplus::ft_String: + case dbiplus::ft_WideString: + case dbiplus::ft_Object: + variantValue = fieldValue.get_asString(); + return true; + case dbiplus::ft_Char: + case dbiplus::ft_WChar: + variantValue = fieldValue.get_asChar(); + return true; + case dbiplus::ft_Boolean: + variantValue = fieldValue.get_asBool(); + return true; + case dbiplus::ft_Short: + variantValue = fieldValue.get_asShort(); + return true; + case dbiplus::ft_UShort: + variantValue = fieldValue.get_asShort(); + return true; + case dbiplus::ft_Int: + variantValue = fieldValue.get_asInt(); + return true; + case dbiplus::ft_UInt: + variantValue = fieldValue.get_asUInt(); + return true; + case dbiplus::ft_Float: + variantValue = fieldValue.get_asFloat(); + return true; + case dbiplus::ft_Double: + case dbiplus::ft_LongDouble: + variantValue = fieldValue.get_asDouble(); + return true; + case dbiplus::ft_Int64: + variantValue = fieldValue.get_asInt64(); + return true; + } + + return false; +} + +bool DatabaseUtils::GetDatabaseResults(const MediaType &mediaType, const FieldList &fields, const std::unique_ptr &dataset, DatabaseResults &results) +{ + if (dataset->num_rows() == 0) + return true; + + const dbiplus::result_set &resultSet = dataset->get_result_set(); + unsigned int offset = results.size(); + + if (fields.empty()) + { + DatabaseResult result; + for (unsigned int index = 0; index < resultSet.records.size(); index++) + { + result[FieldRow] = index + offset; + results.push_back(result); + } + + return true; + } + + if (resultSet.record_header.size() < fields.size()) + return false; + + std::vector fieldIndexLookup; + fieldIndexLookup.reserve(fields.size()); + for (FieldList::const_iterator it = fields.begin(); it != fields.end(); ++it) + fieldIndexLookup.push_back(GetFieldIndex(*it, mediaType)); + + results.reserve(resultSet.records.size() + offset); + for (unsigned int index = 0; index < resultSet.records.size(); index++) + { + DatabaseResult result; + result[FieldRow] = index + offset; + + unsigned int lookupIndex = 0; + for (FieldList::const_iterator it = fields.begin(); it != fields.end(); ++it) + { + int fieldIndex = fieldIndexLookup[lookupIndex++]; + if (fieldIndex < 0) + return false; + + std::pair value; + value.first = *it; + if (!GetFieldValue(resultSet.records[index]->at(fieldIndex), value.second)) + CLog::Log(LOGWARNING, "GetDatabaseResults: unable to retrieve value of field %s", resultSet.record_header[fieldIndex].name.c_str()); + + if (value.first == FieldYear && + (mediaType == MediaTypeTvShow || mediaType == MediaTypeEpisode)) + { + CDateTime dateTime; + dateTime.SetFromDBDate(value.second.asString()); + if (dateTime.IsValid()) + { + value.second.clear(); + value.second = dateTime.GetYear(); + } + } + + result.insert(value); + } + + result[FieldMediaType] = mediaType; + if (mediaType == MediaTypeMovie || mediaType == MediaTypeVideoCollection || + mediaType == MediaTypeTvShow || mediaType == MediaTypeMusicVideo) + result[FieldLabel] = result.at(FieldTitle).asString(); + else if (mediaType == MediaTypeEpisode) + { + std::ostringstream label; + label << (int)(result.at(FieldSeason).asInteger() * 100 + result.at(FieldEpisodeNumber).asInteger()); + label << ". "; + label << result.at(FieldTitle).asString(); + result[FieldLabel] = label.str(); + } + else if (mediaType == MediaTypeAlbum) + result[FieldLabel] = result.at(FieldAlbum).asString(); + else if (mediaType == MediaTypeSong) + { + std::ostringstream label; + label << (int)result.at(FieldTrackNumber).asInteger(); + label << ". "; + label << result.at(FieldTitle).asString(); + result[FieldLabel] = label.str(); + } + else if (mediaType == MediaTypeArtist) + result[FieldLabel] = result.at(FieldArtist).asString(); + + results.push_back(result); + } + + return true; +} + +std::string DatabaseUtils::BuildLimitClause(int end, int start /* = 0 */) +{ + return " LIMIT " + BuildLimitClauseOnly(end, start); +} + +std::string DatabaseUtils::BuildLimitClauseOnly(int end, int start /* = 0 */) +{ + std::ostringstream sql; + if (start > 0) + { + if (end > 0) + { + end = end - start; + if (end < 0) + end = 0; + } + + sql << start << "," << end; + } + else + sql << end; + + return sql.str(); +} + +size_t DatabaseUtils::GetLimitCount(int end, int start) +{ + if (start > 0) + { + if (end - start < 0) + return 0; + else + return static_cast(end - start); + } + else if (end > 0) + return static_cast(end); + return 0; +} + +int DatabaseUtils::GetField(Field field, const MediaType &mediaType, bool asIndex) +{ + if (field == FieldNone || mediaType == MediaTypeNone) + return -1; + + int index = -1; + + if (mediaType == MediaTypeAlbum) + { + if (field == FieldId) return CMusicDatabase::album_idAlbum; + else if (field == FieldAlbum) return CMusicDatabase::album_strAlbum; + else if (field == FieldArtist || field == FieldAlbumArtist) return CMusicDatabase::album_strArtists; + else if (field == FieldGenre) return CMusicDatabase::album_strGenres; + else if (field == FieldYear) return CMusicDatabase::album_strReleaseDate; + else if (field == FieldMoods) return CMusicDatabase::album_strMoods; + else if (field == FieldStyles) return CMusicDatabase::album_strStyles; + else if (field == FieldThemes) return CMusicDatabase::album_strThemes; + else if (field == FieldReview) return CMusicDatabase::album_strReview; + else if (field == FieldMusicLabel) return CMusicDatabase::album_strLabel; + else if (field == FieldAlbumType) return CMusicDatabase::album_strType; + else if (field == FieldRating) return CMusicDatabase::album_fRating; + else if (field == FieldVotes) return CMusicDatabase::album_iVotes; + else if (field == FieldUserRating) return CMusicDatabase::album_iUserrating; + else if (field == FieldPlaycount) return CMusicDatabase::album_iTimesPlayed; + else if (field == FieldLastPlayed) return CMusicDatabase::album_dtLastPlayed; + else if (field == FieldDateAdded) return CMusicDatabase::album_dateAdded; + else if (field == FieldDateNew) return CMusicDatabase::album_dateNew; + else if (field == FieldDateModified) return CMusicDatabase::album_dateModified; + else if (field == FieldTotalDiscs) + return CMusicDatabase::album_iTotalDiscs; + else if (field == FieldOrigYear || field == FieldOrigDate) + return CMusicDatabase::album_strOrigReleaseDate; + else if (field == FieldAlbumStatus) + return CMusicDatabase::album_strReleaseStatus; + } + else if (mediaType == MediaTypeSong) + { + if (field == FieldId) return CMusicDatabase::song_idSong; + else if (field == FieldTitle) return CMusicDatabase::song_strTitle; + else if (field == FieldTrackNumber) return CMusicDatabase::song_iTrack; + else if (field == FieldTime) return CMusicDatabase::song_iDuration; + else if (field == FieldYear) return CMusicDatabase::song_strReleaseDate; + else if (field == FieldFilename) return CMusicDatabase::song_strFileName; + else if (field == FieldPlaycount) return CMusicDatabase::song_iTimesPlayed; + else if (field == FieldStartOffset) return CMusicDatabase::song_iStartOffset; + else if (field == FieldEndOffset) return CMusicDatabase::song_iEndOffset; + else if (field == FieldLastPlayed) return CMusicDatabase::song_lastplayed; + else if (field == FieldRating) return CMusicDatabase::song_rating; + else if (field == FieldUserRating) return CMusicDatabase::song_userrating; + else if (field == FieldVotes) return CMusicDatabase::song_votes; + else if (field == FieldComment) return CMusicDatabase::song_comment; + else if (field == FieldMoods) return CMusicDatabase::song_mood; + else if (field == FieldAlbum) return CMusicDatabase::song_strAlbum; + else if (field == FieldPath) return CMusicDatabase::song_strPath; + else if (field == FieldGenre) return CMusicDatabase::song_strGenres; + else if (field == FieldArtist || field == FieldAlbumArtist) return CMusicDatabase::song_strArtists; + else if (field == FieldDateAdded) return CMusicDatabase::song_dateAdded; + else if (field == FieldDateNew) return CMusicDatabase::song_dateNew; + else if (field == FieldDateModified) return CMusicDatabase::song_dateModified; + else if (field == FieldBPM) + return CMusicDatabase::song_iBPM; + else if (field == FieldMusicBitRate) + return CMusicDatabase::song_iBitRate; + else if (field == FieldSampleRate) + return CMusicDatabase::song_iSampleRate; + else if (field == FieldNoOfChannels) + return CMusicDatabase::song_iChannels; + } + else if (mediaType == MediaTypeArtist) + { + if (field == FieldId) return CMusicDatabase::artist_idArtist; + else if (field == FieldArtist) return CMusicDatabase::artist_strArtist; + else if (field == FieldArtistSort) return CMusicDatabase::artist_strSortName; + else if (field == FieldArtistType) return CMusicDatabase::artist_strType; + else if (field == FieldGender) return CMusicDatabase::artist_strGender; + else if (field == FieldDisambiguation) return CMusicDatabase::artist_strDisambiguation; + else if (field == FieldGenre) return CMusicDatabase::artist_strGenres; + else if (field == FieldMoods) return CMusicDatabase::artist_strMoods; + else if (field == FieldStyles) return CMusicDatabase::artist_strStyles; + else if (field == FieldInstruments) return CMusicDatabase::artist_strInstruments; + else if (field == FieldBiography) return CMusicDatabase::artist_strBiography; + else if (field == FieldBorn) return CMusicDatabase::artist_strBorn; + else if (field == FieldBandFormed) return CMusicDatabase::artist_strFormed; + else if (field == FieldDisbanded) return CMusicDatabase::artist_strDisbanded; + else if (field == FieldDied) return CMusicDatabase::artist_strDied; + else if (field == FieldDateAdded) return CMusicDatabase::artist_dateAdded; + else if (field == FieldDateNew) return CMusicDatabase::artist_dateNew; + else if (field == FieldDateModified) return CMusicDatabase::artist_dateModified; + } + else if (mediaType == MediaTypeMusicVideo) + { + if (field == FieldId) return 0; + else if (field == FieldTitle) index = VIDEODB_ID_MUSICVIDEO_TITLE; + else if (field == FieldTime) index = VIDEODB_ID_MUSICVIDEO_RUNTIME; + else if (field == FieldDirector) index = VIDEODB_ID_MUSICVIDEO_DIRECTOR; + else if (field == FieldStudio) index = VIDEODB_ID_MUSICVIDEO_STUDIOS; + else if (field == FieldYear) return VIDEODB_DETAILS_MUSICVIDEO_PREMIERED; + else if (field == FieldPlot) index = VIDEODB_ID_MUSICVIDEO_PLOT; + else if (field == FieldAlbum) index = VIDEODB_ID_MUSICVIDEO_ALBUM; + else if (field == FieldArtist) index = VIDEODB_ID_MUSICVIDEO_ARTIST; + else if (field == FieldGenre) index = VIDEODB_ID_MUSICVIDEO_GENRE; + else if (field == FieldTrackNumber) index = VIDEODB_ID_MUSICVIDEO_TRACK; + else if (field == FieldFilename) return VIDEODB_DETAILS_MUSICVIDEO_FILE; + else if (field == FieldPath) return VIDEODB_DETAILS_MUSICVIDEO_PATH; + else if (field == FieldPlaycount) return VIDEODB_DETAILS_MUSICVIDEO_PLAYCOUNT; + else if (field == FieldLastPlayed) return VIDEODB_DETAILS_MUSICVIDEO_LASTPLAYED; + else if (field == FieldDateAdded) return VIDEODB_DETAILS_MUSICVIDEO_DATEADDED; + else if (field == FieldUserRating) return VIDEODB_DETAILS_MUSICVIDEO_USER_RATING; + + if (index < 0) + return index; + + if (asIndex) + { + // see VideoDatabase.h + // the first field is the item's ID and the second is the item's file ID + index += 2; + } + } + else if (mediaType == MediaTypeMovie) + { + if (field == FieldId) return 0; + else if (field == FieldTitle) index = VIDEODB_ID_TITLE; + else if (field == FieldSortTitle) index = VIDEODB_ID_SORTTITLE; + else if (field == FieldOriginalTitle) index = VIDEODB_ID_ORIGINALTITLE; + else if (field == FieldPlot) index = VIDEODB_ID_PLOT; + else if (field == FieldPlotOutline) index = VIDEODB_ID_PLOTOUTLINE; + else if (field == FieldTagline) index = VIDEODB_ID_TAGLINE; + else if (field == FieldVotes) return VIDEODB_DETAILS_MOVIE_VOTES; + else if (field == FieldRating) return VIDEODB_DETAILS_MOVIE_RATING; + else if (field == FieldWriter) index = VIDEODB_ID_CREDITS; + else if (field == FieldYear) return VIDEODB_DETAILS_MOVIE_PREMIERED; + else if (field == FieldTime) index = VIDEODB_ID_RUNTIME; + else if (field == FieldMPAA) index = VIDEODB_ID_MPAA; + else if (field == FieldTop250) index = VIDEODB_ID_TOP250; + else if (field == FieldSet) return VIDEODB_DETAILS_MOVIE_SET_NAME; + else if (field == FieldGenre) index = VIDEODB_ID_GENRE; + else if (field == FieldDirector) index = VIDEODB_ID_DIRECTOR; + else if (field == FieldStudio) index = VIDEODB_ID_STUDIOS; + else if (field == FieldTrailer) index = VIDEODB_ID_TRAILER; + else if (field == FieldCountry) index = VIDEODB_ID_COUNTRY; + else if (field == FieldFilename) index = VIDEODB_DETAILS_MOVIE_FILE; + else if (field == FieldPath) return VIDEODB_DETAILS_MOVIE_PATH; + else if (field == FieldPlaycount) return VIDEODB_DETAILS_MOVIE_PLAYCOUNT; + else if (field == FieldLastPlayed) return VIDEODB_DETAILS_MOVIE_LASTPLAYED; + else if (field == FieldDateAdded) return VIDEODB_DETAILS_MOVIE_DATEADDED; + else if (field == FieldUserRating) return VIDEODB_DETAILS_MOVIE_USER_RATING; + + if (index < 0) + return index; + + if (asIndex) + { + // see VideoDatabase.h + // the first field is the item's ID and the second is the item's file ID + index += 2; + } + } + else if (mediaType == MediaTypeTvShow) + { + if (field == FieldId) return 0; + else if (field == FieldTitle) index = VIDEODB_ID_TV_TITLE; + else if (field == FieldSortTitle) index = VIDEODB_ID_TV_SORTTITLE; + else if (field == FieldOriginalTitle) index = VIDEODB_ID_TV_ORIGINALTITLE; + else if (field == FieldPlot) index = VIDEODB_ID_TV_PLOT; + else if (field == FieldTvShowStatus) index = VIDEODB_ID_TV_STATUS; + else if (field == FieldVotes) return VIDEODB_DETAILS_TVSHOW_VOTES; + else if (field == FieldRating) return VIDEODB_DETAILS_TVSHOW_RATING; + else if (field == FieldYear) index = VIDEODB_ID_TV_PREMIERED; + else if (field == FieldGenre) index = VIDEODB_ID_TV_GENRE; + else if (field == FieldMPAA) index = VIDEODB_ID_TV_MPAA; + else if (field == FieldStudio) index = VIDEODB_ID_TV_STUDIOS; + else if (field == FieldPath) return VIDEODB_DETAILS_TVSHOW_PATH; + else if (field == FieldDateAdded) return VIDEODB_DETAILS_TVSHOW_DATEADDED; + else if (field == FieldLastPlayed) return VIDEODB_DETAILS_TVSHOW_LASTPLAYED; + else if (field == FieldNumberOfEpisodes) return VIDEODB_DETAILS_TVSHOW_NUM_EPISODES; + else if (field == FieldNumberOfWatchedEpisodes) return VIDEODB_DETAILS_TVSHOW_NUM_WATCHED; + else if (field == FieldSeason) return VIDEODB_DETAILS_TVSHOW_NUM_SEASONS; + else if (field == FieldUserRating) return VIDEODB_DETAILS_TVSHOW_USER_RATING; + + if (index < 0) + return index; + + if (asIndex) + { + // see VideoDatabase.h + // the first field is the item's ID + index += 1; + } + } + else if (mediaType == MediaTypeEpisode) + { + if (field == FieldId) return 0; + else if (field == FieldTitle) index = VIDEODB_ID_EPISODE_TITLE; + else if (field == FieldPlot) index = VIDEODB_ID_EPISODE_PLOT; + else if (field == FieldVotes) return VIDEODB_DETAILS_EPISODE_VOTES; + else if (field == FieldRating) return VIDEODB_DETAILS_EPISODE_RATING; + else if (field == FieldWriter) index = VIDEODB_ID_EPISODE_CREDITS; + else if (field == FieldAirDate) index = VIDEODB_ID_EPISODE_AIRED; + else if (field == FieldTime) index = VIDEODB_ID_EPISODE_RUNTIME; + else if (field == FieldDirector) index = VIDEODB_ID_EPISODE_DIRECTOR; + else if (field == FieldSeason) index = VIDEODB_ID_EPISODE_SEASON; + else if (field == FieldEpisodeNumber) index = VIDEODB_ID_EPISODE_EPISODE; + else if (field == FieldUniqueId) index = VIDEODB_ID_EPISODE_IDENT_ID; + else if (field == FieldEpisodeNumberSpecialSort) index = VIDEODB_ID_EPISODE_SORTEPISODE; + else if (field == FieldSeasonSpecialSort) index = VIDEODB_ID_EPISODE_SORTSEASON; + else if (field == FieldFilename) return VIDEODB_DETAILS_EPISODE_FILE; + else if (field == FieldPath) return VIDEODB_DETAILS_EPISODE_PATH; + else if (field == FieldPlaycount) return VIDEODB_DETAILS_EPISODE_PLAYCOUNT; + else if (field == FieldLastPlayed) return VIDEODB_DETAILS_EPISODE_LASTPLAYED; + else if (field == FieldDateAdded) return VIDEODB_DETAILS_EPISODE_DATEADDED; + else if (field == FieldTvShowTitle) return VIDEODB_DETAILS_EPISODE_TVSHOW_NAME; + else if (field == FieldStudio) return VIDEODB_DETAILS_EPISODE_TVSHOW_STUDIO; + else if (field == FieldYear) return VIDEODB_DETAILS_EPISODE_TVSHOW_AIRED; + else if (field == FieldMPAA) return VIDEODB_DETAILS_EPISODE_TVSHOW_MPAA; + else if (field == FieldUserRating) return VIDEODB_DETAILS_EPISODE_USER_RATING; + + if (index < 0) + return index; + + if (asIndex) + { + // see VideoDatabase.h + // the first field is the item's ID and the second is the item's file ID + index += 2; + } + } + + return index; +} diff --git a/xbmc/utils/DatabaseUtils.h b/xbmc/utils/DatabaseUtils.h new file mode 100644 index 0000000..98761db --- /dev/null +++ b/xbmc/utils/DatabaseUtils.h @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "media/MediaType.h" + +#include +#include +#include +#include +#include + +class CVariant; + +namespace dbiplus +{ + class Dataset; + class field_value; +} + +typedef enum { + // special fields used during sorting + FieldUnknown = -1, + FieldNone = 0, + FieldSort, // used to store the string to use for sorting + FieldSortSpecial, // whether the item needs special handling (0 = no, 1 = sort on top, 2 = sort on bottom) + FieldLabel, + FieldFolder, + FieldMediaType, + FieldRow, // the row number in a dataset + + // special fields not retrieved from the database + FieldSize, + FieldDate, + FieldDriveType, + FieldStartOffset, + FieldEndOffset, + FieldProgramCount, + FieldBitrate, + FieldListeners, + FieldPlaylist, + FieldVirtualFolder, + FieldRandom, + FieldDateTaken, + FieldAudioCount, + FieldSubtitleCount, + + FieldInstallDate, + FieldLastUpdated, + FieldLastUsed, + + // fields retrievable from the database + FieldId, + FieldGenre, + FieldAlbum, + FieldDiscTitle, + FieldIsBoxset, + FieldTotalDiscs, + FieldOrigYear, + FieldOrigDate, + FieldArtist, + FieldArtistSort, + FieldAlbumArtist, + FieldTitle, + FieldSortTitle, + FieldOriginalTitle, + FieldYear, + FieldTime, + FieldTrackNumber, + FieldFilename, + FieldPath, + FieldPlaycount, + FieldLastPlayed, + FieldInProgress, + FieldRating, + FieldComment, + FieldRole, + FieldDateAdded, + FieldDateModified, + FieldDateNew, + FieldTvShowTitle, + FieldPlot, + FieldPlotOutline, + FieldTagline, + FieldTvShowStatus, + FieldVotes, + FieldDirector, + FieldActor, + FieldStudio, + FieldCountry, + FieldMPAA, + FieldTop250, + FieldSet, + FieldNumberOfEpisodes, + FieldNumberOfWatchedEpisodes, + FieldWriter, + FieldAirDate, + FieldEpisodeNumber, + FieldUniqueId, + FieldSeason, + FieldEpisodeNumberSpecialSort, + FieldSeasonSpecialSort, + FieldReview, + FieldThemes, + FieldMoods, + FieldStyles, + FieldAlbumType, + FieldMusicLabel, + FieldCompilation, + FieldSource, + FieldTrailer, + FieldVideoResolution, + FieldVideoAspectRatio, + FieldVideoCodec, + FieldAudioChannels, + FieldAudioCodec, + FieldAudioLanguage, + FieldSubtitleLanguage, + FieldProductionCode, + FieldTag, + FieldChannelName, + FieldChannelNumber, + FieldInstruments, + FieldBiography, + FieldArtistType, + FieldGender, + FieldDisambiguation, + FieldBorn, + FieldBandFormed, + FieldDisbanded, + FieldDied, + FieldStereoMode, + FieldUserRating, + FieldRelevance, // Used for actors' appearances + FieldClientChannelOrder, + FieldBPM, + FieldMusicBitRate, + FieldSampleRate, + FieldNoOfChannels, + FieldAlbumStatus, + FieldMax +} Field; + +typedef std::set Fields; +typedef std::vector FieldList; + +typedef enum { + DatabaseQueryPartSelect, + DatabaseQueryPartWhere, + DatabaseQueryPartOrderBy, +} DatabaseQueryPart; + +typedef std::map DatabaseResult; +typedef std::vector DatabaseResults; + +class DatabaseUtils +{ +public: + static MediaType MediaTypeFromVideoContentType(int videoContentType); + + static std::string GetField(Field field, const MediaType &mediaType, DatabaseQueryPart queryPart); + static int GetField(Field field, const MediaType &mediaType); + static int GetFieldIndex(Field field, const MediaType &mediaType); + static bool GetSelectFields(const Fields &fields, const MediaType &mediaType, FieldList &selectFields); + + static bool GetFieldValue(const dbiplus::field_value &fieldValue, CVariant &variantValue); + static bool GetDatabaseResults(const MediaType &mediaType, const FieldList &fields, const std::unique_ptr &dataset, DatabaseResults &results); + + static std::string BuildLimitClause(int end, int start = 0); + static std::string BuildLimitClauseOnly(int end, int start = 0); + static size_t GetLimitCount(int end, int start); + +private: + static int GetField(Field field, const MediaType &mediaType, bool asIndex); +}; diff --git a/xbmc/utils/Digest.cpp b/xbmc/utils/Digest.cpp new file mode 100644 index 0000000..445a755 --- /dev/null +++ b/xbmc/utils/Digest.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Digest.h" + +#include "StringUtils.h" + +#include +#include + +#include + +namespace KODI +{ +namespace UTILITY +{ + +namespace +{ + +EVP_MD const * TypeToEVPMD(CDigest::Type type) +{ + switch (type) + { + case CDigest::Type::MD5: + return EVP_md5(); + case CDigest::Type::SHA1: + return EVP_sha1(); + case CDigest::Type::SHA256: + return EVP_sha256(); + case CDigest::Type::SHA512: + return EVP_sha512(); + default: + throw std::invalid_argument("Unknown digest type"); + } +} + +} + +std::ostream& operator<<(std::ostream& os, TypedDigest const& digest) +{ + return os << "{" << CDigest::TypeToString(digest.type) << "}" << digest.value; +} + +std::string CDigest::TypeToString(Type type) +{ + switch (type) + { + case Type::MD5: + return "md5"; + case Type::SHA1: + return "sha1"; + case Type::SHA256: + return "sha256"; + case Type::SHA512: + return "sha512"; + case Type::INVALID: + return "invalid"; + default: + throw std::invalid_argument("Unknown digest type"); + } +} + +CDigest::Type CDigest::TypeFromString(std::string const& type) +{ + std::string typeLower{type}; + StringUtils::ToLower(typeLower); + if (type == "md5") + { + return Type::MD5; + } + else if (type == "sha1") + { + return Type::SHA1; + } + else if (type == "sha256") + { + return Type::SHA256; + } + else if (type == "sha512") + { + return Type::SHA512; + } + else + { + throw std::invalid_argument(std::string("Unknown digest type \"") + type + "\""); + } +} + +void CDigest::MdCtxDeleter::operator()(EVP_MD_CTX* context) +{ + EVP_MD_CTX_destroy(context); +} + +CDigest::CDigest(Type type) +: m_context{EVP_MD_CTX_create()}, m_md(TypeToEVPMD(type)) +{ + if (1 != EVP_DigestInit_ex(m_context.get(), m_md, nullptr)) + { + throw std::runtime_error("EVP_DigestInit_ex failed"); + } +} + +void CDigest::Update(std::string const& data) +{ + Update(data.c_str(), data.size()); +} + +void CDigest::Update(void const* data, std::size_t size) +{ + if (m_finalized) + { + throw std::logic_error("Finalized digest cannot be updated any more"); + } + + if (1 != EVP_DigestUpdate(m_context.get(), data, size)) + { + throw std::runtime_error("EVP_DigestUpdate failed"); + } +} + +std::string CDigest::FinalizeRaw() +{ + if (m_finalized) + { + throw std::logic_error("Digest can only be finalized once"); + } + + m_finalized = true; + + std::array digest; + std::size_t size = EVP_MD_size(m_md); + if (size > digest.size()) + { + throw std::runtime_error("Digest unexpectedly long"); + } + if (1 != EVP_DigestFinal_ex(m_context.get(), digest.data(), nullptr)) + { + throw std::runtime_error("EVP_DigestFinal_ex failed"); + } + return {reinterpret_cast (digest.data()), size}; +} + +std::string CDigest::Finalize() +{ + return StringUtils::ToHexadecimal(FinalizeRaw()); +} + +std::string CDigest::Calculate(Type type, std::string const& data) +{ + CDigest digest{type}; + digest.Update(data); + return digest.Finalize(); +} + +std::string CDigest::Calculate(Type type, void const* data, std::size_t size) +{ + CDigest digest{type}; + digest.Update(data, size); + return digest.Finalize(); +} + +} +} diff --git a/xbmc/utils/Digest.h b/xbmc/utils/Digest.h new file mode 100644 index 0000000..6452857 --- /dev/null +++ b/xbmc/utils/Digest.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "StringUtils.h" + +#include +#include +#include +#include + +#include + +namespace KODI +{ +namespace UTILITY +{ + +/** + * Utility class for calculating message digests/hashes, currently using OpenSSL + */ +class CDigest +{ +public: + enum class Type + { + MD5, + SHA1, + SHA256, + SHA512, + INVALID + }; + + /** + * Convert type enumeration value to lower-case string representation + */ + static std::string TypeToString(Type type); + /** + * Convert digest type string representation to enumeration value + */ + static Type TypeFromString(std::string const& type); + + /** + * Create a digest calculation object + */ + CDigest(Type type); + /** + * Update digest with data + * + * Cannot be called after \ref Finalize has been called + */ + void Update(std::string const& data); + /** + * Update digest with data + * + * Cannot be called after \ref Finalize has been called + */ + void Update(void const* data, std::size_t size); + /** + * Finalize and return the digest + * + * The digest object cannot be used any more after this function + * has been called. + * + * \return digest value as string in lower-case hexadecimal notation + */ + std::string Finalize(); + /** + * Finalize and return the digest + * + * The digest object cannot be used any more after this + * function has been called. + * + * \return digest value as binary std::string + */ + std::string FinalizeRaw(); + + /** + * Calculate message digest + */ + static std::string Calculate(Type type, std::string const& data); + /** + * Calculate message digest + */ + static std::string Calculate(Type type, void const* data, std::size_t size); + +private: + struct MdCtxDeleter + { + void operator()(EVP_MD_CTX* context); + }; + + bool m_finalized{false}; + std::unique_ptr m_context; + EVP_MD const* m_md; +}; + +struct TypedDigest +{ + CDigest::Type type{CDigest::Type::INVALID}; + std::string value; + + TypedDigest() = default; + + TypedDigest(CDigest::Type type, std::string const& value) + : type(type), value(value) + {} + + bool Empty() const + { + return (type == CDigest::Type::INVALID || value.empty()); + } +}; + +inline bool operator==(TypedDigest const& left, TypedDigest const& right) +{ + if (left.type != right.type) + { + throw std::logic_error("Cannot compare digests of different type"); + } + return StringUtils::EqualsNoCase(left.value, right.value); +} + +inline bool operator!=(TypedDigest const& left, TypedDigest const& right) +{ + return !(left == right); +} + +std::ostream& operator<<(std::ostream& os, TypedDigest const& digest); + +} +} diff --git a/xbmc/utils/DumbBufferObject.cpp b/xbmc/utils/DumbBufferObject.cpp new file mode 100644 index 0000000..84d28ea --- /dev/null +++ b/xbmc/utils/DumbBufferObject.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "DumbBufferObject.h" + +#include "ServiceBroker.h" +#include "utils/BufferObjectFactory.h" +#include "utils/log.h" +#include "windowing/gbm/WinSystemGbm.h" +#include "windowing/gbm/WinSystemGbmEGLContext.h" + +#include +#include + +using namespace KODI::WINDOWING::GBM; + +std::unique_ptr CDumbBufferObject::Create() +{ + return std::make_unique(); +} + +void CDumbBufferObject::Register() +{ + CBufferObjectFactory::RegisterBufferObject(CDumbBufferObject::Create); +} + +CDumbBufferObject::CDumbBufferObject() +{ + auto winSystem = static_cast(CServiceBroker::GetWinSystem()); + + m_device = winSystem->GetDrm()->GetFileDescriptor(); +} + +CDumbBufferObject::~CDumbBufferObject() +{ + ReleaseMemory(); + DestroyBufferObject(); +} + +bool CDumbBufferObject::CreateBufferObject(uint32_t format, uint32_t width, uint32_t height) +{ + if (m_fd >= 0) + return true; + + uint32_t bpp; + + switch (format) + { + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_RGB565: + bpp = 16; + break; + case DRM_FORMAT_ARGB8888: + bpp = 32; + break; + default: + throw std::runtime_error("CDumbBufferObject: pixel format not implemented"); + } + + struct drm_mode_create_dumb create_dumb = {.height = height, .width = width, .bpp = bpp}; + + int ret = drmIoctl(m_device, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb); + if (ret < 0) + { + CLog::Log(LOGERROR, "CDumbBufferObject::{} - ioctl DRM_IOCTL_MODE_CREATE_DUMB failed, errno={}", + __FUNCTION__, strerror(errno)); + return false; + } + + m_size = create_dumb.size; + m_stride = create_dumb.pitch; + + ret = drmPrimeHandleToFD(m_device, create_dumb.handle, 0, &m_fd); + if (ret < 0) + { + CLog::Log(LOGERROR, "CDumbBufferObject::{} - failed to get fd from prime handle, errno={}", + __FUNCTION__, strerror(errno)); + return false; + } + + return true; +} + +void CDumbBufferObject::DestroyBufferObject() +{ + if (m_fd < 0) + return; + + int ret = close(m_fd); + if (ret < 0) + CLog::Log(LOGERROR, "CDumbBufferObject::{} - close failed, errno={}", __FUNCTION__, + strerror(errno)); + + m_fd = -1; + m_stride = 0; + m_size = 0; +} + +uint8_t* CDumbBufferObject::GetMemory() +{ + if (m_fd < 0) + return nullptr; + + if (m_map) + { + CLog::Log(LOGDEBUG, "CDumbBufferObject::{} - already mapped fd={} map={}", __FUNCTION__, m_fd, + fmt::ptr(m_map)); + return m_map; + } + + uint32_t handle; + int ret = drmPrimeFDToHandle(m_device, m_fd, &handle); + if (ret < 0) + { + CLog::Log(LOGERROR, "CDumbBufferObject::{} - failed to get handle from prime fd, errno={}", + __FUNCTION__, strerror(errno)); + return nullptr; + } + + struct drm_mode_map_dumb map_dumb = {.handle = handle}; + + ret = drmIoctl(m_device, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb); + if (ret < 0) + { + CLog::Log(LOGERROR, "CDumbBufferObject::{} - ioctl DRM_IOCTL_MODE_MAP_DUMB failed, errno={}", + __FUNCTION__, strerror(errno)); + return nullptr; + } + + m_offset = map_dumb.offset; + + m_map = static_cast(mmap(nullptr, m_size, PROT_WRITE, MAP_SHARED, m_device, m_offset)); + if (m_map == MAP_FAILED) + { + CLog::Log(LOGERROR, "CDumbBufferObject::{} - mmap failed, errno={}", __FUNCTION__, + strerror(errno)); + return nullptr; + } + + return m_map; +} + +void CDumbBufferObject::ReleaseMemory() +{ + if (!m_map) + return; + + int ret = munmap(m_map, m_size); + if (ret < 0) + CLog::Log(LOGERROR, "CDumbBufferObject::{} - munmap failed, errno={}", __FUNCTION__, + strerror(errno)); + + m_map = nullptr; + m_offset = 0; +} diff --git a/xbmc/utils/DumbBufferObject.h b/xbmc/utils/DumbBufferObject.h new file mode 100644 index 0000000..2dec611 --- /dev/null +++ b/xbmc/utils/DumbBufferObject.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/BufferObject.h" + +#include +#include + +class CDumbBufferObject : public CBufferObject +{ +public: + CDumbBufferObject(); + virtual ~CDumbBufferObject() override; + + // Registration + static std::unique_ptr Create(); + static void Register(); + + // IBufferObject overrides via CBufferObject + bool CreateBufferObject(uint32_t format, uint32_t width, uint32_t height) override; + void DestroyBufferObject() override; + uint8_t* GetMemory() override; + void ReleaseMemory() override; + std::string GetName() const override { return "CDumbBufferObject"; } + +private: + int m_device{-1}; + uint64_t m_size{0}; + uint64_t m_offset{0}; + uint8_t* m_map{nullptr}; +}; diff --git a/xbmc/utils/EGLFence.cpp b/xbmc/utils/EGLFence.cpp new file mode 100644 index 0000000..369c40a --- /dev/null +++ b/xbmc/utils/EGLFence.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "EGLFence.h" + +#include "EGLUtils.h" +#include "utils/log.h" + +using namespace KODI::UTILS::EGL; + +CEGLFence::CEGLFence(EGLDisplay display) : + m_display(display) +{ + m_eglCreateSyncKHR = CEGLUtils::GetRequiredProcAddress("eglCreateSyncKHR"); + m_eglDestroySyncKHR = CEGLUtils::GetRequiredProcAddress("eglDestroySyncKHR"); + m_eglGetSyncAttribKHR = CEGLUtils::GetRequiredProcAddress("eglGetSyncAttribKHR"); +} + +void CEGLFence::CreateFence() +{ + m_fence = m_eglCreateSyncKHR(m_display, EGL_SYNC_FENCE_KHR, nullptr); + if (m_fence == EGL_NO_SYNC_KHR) + { + CEGLUtils::Log(LOGERROR, "failed to create egl sync fence"); + throw std::runtime_error("failed to create egl sync fence"); + } +} + +void CEGLFence::DestroyFence() +{ + if (m_fence == EGL_NO_SYNC_KHR) + { + return; + } + + if (m_eglDestroySyncKHR(m_display, m_fence) != EGL_TRUE) + { + CEGLUtils::Log(LOGERROR, "failed to destroy egl sync fence"); + } + + m_fence = EGL_NO_SYNC_KHR; +} + +bool CEGLFence::IsSignaled() +{ + // fence has been destroyed so return true immediately so buffer can be used + if (m_fence == EGL_NO_SYNC_KHR) + { + return true; + } + + EGLint status = EGL_UNSIGNALED_KHR; + if (m_eglGetSyncAttribKHR(m_display, m_fence, EGL_SYNC_STATUS_KHR, &status) != EGL_TRUE) + { + CEGLUtils::Log(LOGERROR, "failed to query egl sync fence"); + return false; + } + + if (status == EGL_SIGNALED_KHR) + { + return true; + } + + return false; +} diff --git a/xbmc/utils/EGLFence.h b/xbmc/utils/EGLFence.h new file mode 100644 index 0000000..1664772 --- /dev/null +++ b/xbmc/utils/EGLFence.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include + +namespace KODI +{ +namespace UTILS +{ +namespace EGL +{ + +class CEGLFence +{ +public: + explicit CEGLFence(EGLDisplay display); + CEGLFence(CEGLFence const& other) = delete; + CEGLFence& operator=(CEGLFence const& other) = delete; + + void CreateFence(); + void DestroyFence(); + bool IsSignaled(); + +private: + EGLDisplay m_display{nullptr}; + EGLSyncKHR m_fence{nullptr}; + + PFNEGLCREATESYNCKHRPROC m_eglCreateSyncKHR{nullptr}; + PFNEGLDESTROYSYNCKHRPROC m_eglDestroySyncKHR{nullptr}; + PFNEGLGETSYNCATTRIBKHRPROC m_eglGetSyncAttribKHR{nullptr}; +}; + +} +} +} diff --git a/xbmc/utils/EGLImage.cpp b/xbmc/utils/EGLImage.cpp new file mode 100644 index 0000000..633a44d --- /dev/null +++ b/xbmc/utils/EGLImage.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "EGLImage.h" + +#include "EGLUtils.h" +#include "log.h" + +#include + +namespace +{ + const EGLint eglDmabufPlaneFdAttr[CEGLImage::MAX_NUM_PLANES] = + { + EGL_DMA_BUF_PLANE0_FD_EXT, + EGL_DMA_BUF_PLANE1_FD_EXT, + EGL_DMA_BUF_PLANE2_FD_EXT, + }; + + const EGLint eglDmabufPlaneOffsetAttr[CEGLImage::MAX_NUM_PLANES] = + { + EGL_DMA_BUF_PLANE0_OFFSET_EXT, + EGL_DMA_BUF_PLANE1_OFFSET_EXT, + EGL_DMA_BUF_PLANE2_OFFSET_EXT, + }; + + const EGLint eglDmabufPlanePitchAttr[CEGLImage::MAX_NUM_PLANES] = + { + EGL_DMA_BUF_PLANE0_PITCH_EXT, + EGL_DMA_BUF_PLANE1_PITCH_EXT, + EGL_DMA_BUF_PLANE2_PITCH_EXT, + }; + +#if defined(EGL_EXT_image_dma_buf_import_modifiers) + const EGLint eglDmabufPlaneModifierLoAttr[CEGLImage::MAX_NUM_PLANES] = + { + EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, + EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, + EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, + }; + + const EGLint eglDmabufPlaneModifierHiAttr[CEGLImage::MAX_NUM_PLANES] = + { + EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, + EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT, + EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT, + }; +#endif + +#define X(VAL) std::make_pair(VAL, #VAL) +std::map eglAttributes = +{ + X(EGL_WIDTH), + X(EGL_HEIGHT), + + // please keep attributes in accordance to: + // https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import.txt + X(EGL_LINUX_DRM_FOURCC_EXT), + X(EGL_DMA_BUF_PLANE0_FD_EXT), + X(EGL_DMA_BUF_PLANE0_OFFSET_EXT), + X(EGL_DMA_BUF_PLANE0_PITCH_EXT), + X(EGL_DMA_BUF_PLANE1_FD_EXT), + X(EGL_DMA_BUF_PLANE1_OFFSET_EXT), + X(EGL_DMA_BUF_PLANE1_PITCH_EXT), + X(EGL_DMA_BUF_PLANE2_FD_EXT), + X(EGL_DMA_BUF_PLANE2_OFFSET_EXT), + X(EGL_DMA_BUF_PLANE2_PITCH_EXT), + X(EGL_YUV_COLOR_SPACE_HINT_EXT), + X(EGL_SAMPLE_RANGE_HINT_EXT), + X(EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT), + X(EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT), + X(EGL_ITU_REC601_EXT), + X(EGL_ITU_REC709_EXT), + X(EGL_ITU_REC2020_EXT), + X(EGL_YUV_FULL_RANGE_EXT), + X(EGL_YUV_NARROW_RANGE_EXT), + X(EGL_YUV_CHROMA_SITING_0_EXT), + X(EGL_YUV_CHROMA_SITING_0_5_EXT), + +#if defined(EGL_EXT_image_dma_buf_import_modifiers) + // please keep attributes in accordance to: + // https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import_modifiers.txt + X(EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT), + X(EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT), + X(EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT), + X(EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT), + X(EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT), + X(EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT), + X(EGL_DMA_BUF_PLANE3_FD_EXT), + X(EGL_DMA_BUF_PLANE3_OFFSET_EXT), + X(EGL_DMA_BUF_PLANE3_PITCH_EXT), + X(EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT), + X(EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT), +#endif +}; + +} // namespace + +CEGLImage::CEGLImage(EGLDisplay display) : + m_display(display) +{ + m_eglCreateImageKHR = CEGLUtils::GetRequiredProcAddress("eglCreateImageKHR"); + m_eglDestroyImageKHR = CEGLUtils::GetRequiredProcAddress("eglDestroyImageKHR"); + m_glEGLImageTargetTexture2DOES = CEGLUtils::GetRequiredProcAddress("glEGLImageTargetTexture2DOES"); +} + +bool CEGLImage::CreateImage(EglAttrs imageAttrs) +{ + CEGLAttributes<22> attribs; + attribs.Add({{EGL_WIDTH, imageAttrs.width}, + {EGL_HEIGHT, imageAttrs.height}, + {EGL_LINUX_DRM_FOURCC_EXT, static_cast(imageAttrs.format)}}); + + if (imageAttrs.colorSpace != 0 && imageAttrs.colorRange != 0) + { + attribs.Add({{EGL_YUV_COLOR_SPACE_HINT_EXT, imageAttrs.colorSpace}, + {EGL_SAMPLE_RANGE_HINT_EXT, imageAttrs.colorRange}, + {EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT, EGL_YUV_CHROMA_SITING_0_EXT}, + {EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT, EGL_YUV_CHROMA_SITING_0_EXT}}); + } + + for (int i = 0; i < MAX_NUM_PLANES; i++) + { + if (imageAttrs.planes[i].fd != 0) + { + attribs.Add({{eglDmabufPlaneFdAttr[i], imageAttrs.planes[i].fd}, + {eglDmabufPlaneOffsetAttr[i], imageAttrs.planes[i].offset}, + {eglDmabufPlanePitchAttr[i], imageAttrs.planes[i].pitch}}); + +#if defined(EGL_EXT_image_dma_buf_import_modifiers) + if (imageAttrs.planes[i].modifier != DRM_FORMAT_MOD_INVALID && imageAttrs.planes[i].modifier != DRM_FORMAT_MOD_LINEAR) + attribs.Add({{eglDmabufPlaneModifierLoAttr[i], static_cast(imageAttrs.planes[i].modifier & 0xFFFFFFFF)}, + {eglDmabufPlaneModifierHiAttr[i], static_cast(imageAttrs.planes[i].modifier >> 32)}}); +#endif + } + } + + m_image = m_eglCreateImageKHR(m_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, attribs.Get()); + + if(!m_image) + { + CLog::Log(LOGERROR, "CEGLImage::{} - failed to import buffer into EGL image: {}", __FUNCTION__, eglGetError()); + + const EGLint* attrs = attribs.Get(); + + std::string eglString; + + for (int i = 0; i < (attribs.Size()); i += 2) + { + std::string keyStr; + std::string valueStr; + + auto eglAttr = eglAttributes.find(attrs[i]); + if (eglAttr != eglAttributes.end()) + { + keyStr = eglAttr->second; + } + else + { + keyStr = std::to_string(attrs[i]); + } + + eglAttr = eglAttributes.find(attrs[i + 1]); + if (eglAttr != eglAttributes.end()) + { + valueStr = eglAttr->second; + } + else + { + valueStr = std::to_string(attrs[i + 1]); + } + + eglString.append(StringUtils::Format("%s: %s\n", keyStr, valueStr)); + } + + CLog::Log(LOGDEBUG, "CEGLImage::{} - attributes:\n{}", __FUNCTION__, eglString); + + return false; + } + + return true; +} + +void CEGLImage::UploadImage(GLenum textureTarget) +{ + m_glEGLImageTargetTexture2DOES(textureTarget, m_image); +} + +void CEGLImage::DestroyImage() +{ + m_eglDestroyImageKHR(m_display, m_image); +} diff --git a/xbmc/utils/EGLImage.h b/xbmc/utils/EGLImage.h new file mode 100644 index 0000000..d9a63e5 --- /dev/null +++ b/xbmc/utils/EGLImage.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +#include +#include +#include + +#include "system_gl.h" + +class CEGLImage +{ +public: + static const int MAX_NUM_PLANES{3}; + + struct EglPlane + { + int fd{0}; + int offset{0}; + int pitch{0}; + uint64_t modifier{DRM_FORMAT_MOD_INVALID}; + }; + + struct EglAttrs + { + int width{0}; + int height{0}; + uint32_t format{0}; + int colorSpace{0}; + int colorRange{0}; + std::array planes; + }; + + explicit CEGLImage(EGLDisplay display); + + CEGLImage(CEGLImage const& other) = delete; + CEGLImage& operator=(CEGLImage const& other) = delete; + + bool CreateImage(EglAttrs imageAttrs); + void UploadImage(GLenum textureTarget); + void DestroyImage(); + +private: + EGLDisplay m_display{nullptr}; + EGLImageKHR m_image{nullptr}; + + PFNEGLCREATEIMAGEKHRPROC m_eglCreateImageKHR{nullptr}; + PFNEGLDESTROYIMAGEKHRPROC m_eglDestroyImageKHR{nullptr}; + PFNGLEGLIMAGETARGETTEXTURE2DOESPROC m_glEGLImageTargetTexture2DOES{nullptr}; +}; diff --git a/xbmc/utils/EGLUtils.cpp b/xbmc/utils/EGLUtils.cpp new file mode 100644 index 0000000..01df4ba --- /dev/null +++ b/xbmc/utils/EGLUtils.cpp @@ -0,0 +1,615 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "EGLUtils.h" + +#include "ServiceBroker.h" +#include "StringUtils.h" +#include "guilib/IDirtyRegionSolver.h" +#include "log.h" +#include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" + +#include + +#include + +namespace +{ +//! @todo remove when Raspberry Pi updates their EGL headers +#ifndef EGL_NO_CONFIG_KHR +#define EGL_NO_CONFIG_KHR static_cast(0) +#endif +#ifndef EGL_CONTEXT_PRIORITY_LEVEL_IMG +#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100 +#endif +#ifndef EGL_CONTEXT_PRIORITY_HIGH_IMG +#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101 +#endif +#ifndef EGL_CONTEXT_PRIORITY_MEDIUM_IMG +#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102 +#endif + +#define X(VAL) std::make_pair(VAL, #VAL) +std::map eglAttributes = +{ + // please keep attributes in accordance to: + // https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglGetConfigAttrib.xhtml + X(EGL_ALPHA_SIZE), + X(EGL_ALPHA_MASK_SIZE), + X(EGL_BIND_TO_TEXTURE_RGB), + X(EGL_BIND_TO_TEXTURE_RGBA), + X(EGL_BLUE_SIZE), + X(EGL_BUFFER_SIZE), + X(EGL_COLOR_BUFFER_TYPE), + X(EGL_CONFIG_CAVEAT), + X(EGL_CONFIG_ID), + X(EGL_CONFORMANT), + X(EGL_DEPTH_SIZE), + X(EGL_GREEN_SIZE), + X(EGL_LEVEL), + X(EGL_LUMINANCE_SIZE), + X(EGL_MAX_PBUFFER_WIDTH), + X(EGL_MAX_PBUFFER_HEIGHT), + X(EGL_MAX_PBUFFER_PIXELS), + X(EGL_MAX_SWAP_INTERVAL), + X(EGL_MIN_SWAP_INTERVAL), + X(EGL_NATIVE_RENDERABLE), + X(EGL_NATIVE_VISUAL_ID), + X(EGL_NATIVE_VISUAL_TYPE), + X(EGL_RED_SIZE), + X(EGL_RENDERABLE_TYPE), + X(EGL_SAMPLE_BUFFERS), + X(EGL_SAMPLES), + X(EGL_STENCIL_SIZE), + X(EGL_SURFACE_TYPE), + X(EGL_TRANSPARENT_TYPE), + X(EGL_TRANSPARENT_RED_VALUE), + X(EGL_TRANSPARENT_GREEN_VALUE), + X(EGL_TRANSPARENT_BLUE_VALUE) +}; + +std::map eglErrors = +{ + // please keep errors in accordance to: + // https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglGetError.xhtml + X(EGL_SUCCESS), + X(EGL_NOT_INITIALIZED), + X(EGL_BAD_ACCESS), + X(EGL_BAD_ALLOC), + X(EGL_BAD_ATTRIBUTE), + X(EGL_BAD_CONFIG), + X(EGL_BAD_CONTEXT), + X(EGL_BAD_CURRENT_SURFACE), + X(EGL_BAD_DISPLAY), + X(EGL_BAD_MATCH), + X(EGL_BAD_NATIVE_PIXMAP), + X(EGL_BAD_NATIVE_WINDOW), + X(EGL_BAD_PARAMETER), + X(EGL_BAD_SURFACE), + X(EGL_CONTEXT_LOST), +}; + +std::map eglErrorType = +{ +//! @todo remove when Raspberry Pi updates their EGL headers +#if !defined(TARGET_RASPBERRY_PI) + X(EGL_DEBUG_MSG_CRITICAL_KHR), + X(EGL_DEBUG_MSG_ERROR_KHR), + X(EGL_DEBUG_MSG_WARN_KHR), + X(EGL_DEBUG_MSG_INFO_KHR), +#endif +}; +#undef X + +} // namespace + +//! @todo remove when Raspberry Pi updates their EGL headers +#if !defined(TARGET_RASPBERRY_PI) +void EglErrorCallback(EGLenum error, const char* command, EGLint messageType, EGLLabelKHR threadLabel, EGLLabelKHR objectLabel, const char* message) +{ + std::string errorStr; + std::string typeStr; + + auto eglError = eglErrors.find(error); + if (eglError != eglErrors.end()) + { + errorStr = eglError->second; + } + + auto eglType = eglErrorType.find(messageType); + if (eglType != eglErrorType.end()) + { + typeStr = eglType->second; + } + + CLog::Log(LOGDEBUG, "EGL Debugging:\nError: {}\nCommand: {}\nType: {}\nMessage: {}", errorStr, command, typeStr, message); +} +#endif + +std::set CEGLUtils::GetClientExtensions() +{ + const char* extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (!extensions) + { + return {}; + } + std::set result; + StringUtils::SplitTo(std::inserter(result, result.begin()), extensions, " "); + return result; +} + +std::set CEGLUtils::GetExtensions(EGLDisplay eglDisplay) +{ + const char* extensions = eglQueryString(eglDisplay, EGL_EXTENSIONS); + if (!extensions) + { + throw std::runtime_error("Could not query EGL for extensions"); + } + std::set result; + StringUtils::SplitTo(std::inserter(result, result.begin()), extensions, " "); + return result; +} + +bool CEGLUtils::HasExtension(EGLDisplay eglDisplay, const std::string& name) +{ + auto exts = GetExtensions(eglDisplay); + return (exts.find(name) != exts.end()); +} + +bool CEGLUtils::HasClientExtension(const std::string& name) +{ + auto exts = GetClientExtensions(); + return (exts.find(name) != exts.end()); +} + +void CEGLUtils::Log(int logLevel, const std::string& what) +{ + EGLenum error = eglGetError(); + std::string errorStr = StringUtils::Format("0x%04X", error); + + auto eglError = eglErrors.find(error); + if (eglError != eglErrors.end()) + { + errorStr = eglError->second; + } + + CLog::Log(logLevel, "{} ({})", what.c_str(), errorStr); +} + +CEGLContextUtils::CEGLContextUtils(EGLenum platform, std::string const& platformExtension) +: m_platform{platform} +{ +//! @todo remove when Raspberry Pi updates their EGL headers +#if !defined(TARGET_RASPBERRY_PI) + if (CEGLUtils::HasClientExtension("EGL_KHR_debug")) + { + auto eglDebugMessageControl = CEGLUtils::GetRequiredProcAddress("eglDebugMessageControlKHR"); + + EGLAttrib eglDebugAttribs[] = {EGL_DEBUG_MSG_CRITICAL_KHR, EGL_TRUE, + EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE, + EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE, + EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE, + EGL_NONE}; + + eglDebugMessageControl(EglErrorCallback, eglDebugAttribs); + } +#endif + + m_platformSupported = CEGLUtils::HasClientExtension("EGL_EXT_platform_base") && CEGLUtils::HasClientExtension(platformExtension); +} + +bool CEGLContextUtils::IsPlatformSupported() const +{ + return m_platformSupported; +} + +CEGLContextUtils::~CEGLContextUtils() +{ + Destroy(); +} + +bool CEGLContextUtils::CreateDisplay(EGLNativeDisplayType nativeDisplay) +{ + if (m_eglDisplay != EGL_NO_DISPLAY) + { + throw std::logic_error("Do not call CreateDisplay when display has already been created"); + } + + m_eglDisplay = eglGetDisplay(nativeDisplay); + if (m_eglDisplay == EGL_NO_DISPLAY) + { + CEGLUtils::Log(LOGERROR, "failed to get EGL display"); + return false; + } + + return true; +} + +bool CEGLContextUtils::CreatePlatformDisplay(void* nativeDisplay, EGLNativeDisplayType nativeDisplayLegacy) +{ + if (m_eglDisplay != EGL_NO_DISPLAY) + { + throw std::logic_error("Do not call CreateDisplay when display has already been created"); + } + +#if defined(EGL_EXT_platform_base) + if (IsPlatformSupported()) + { + // Theoretically it is possible to use eglGetDisplay() and eglCreateWindowSurface, + // but then the EGL library basically has to guess which platform we want + // if it supports multiple which is usually the case - + // it's better and safer to make it explicit + + auto getPlatformDisplayEXT = CEGLUtils::GetRequiredProcAddress("eglGetPlatformDisplayEXT"); + m_eglDisplay = getPlatformDisplayEXT(m_platform, nativeDisplay, nullptr); + + if (m_eglDisplay == EGL_NO_DISPLAY) + { + CEGLUtils::Log(LOGERROR, "failed to get platform display"); + return false; + } + } +#endif + + if (m_eglDisplay == EGL_NO_DISPLAY) + { + return CreateDisplay(nativeDisplayLegacy); + } + + return true; +} + +bool CEGLContextUtils::InitializeDisplay(EGLint renderingApi) +{ + if (!eglInitialize(m_eglDisplay, nullptr, nullptr)) + { + CEGLUtils::Log(LOGERROR, "failed to initialize EGL display"); + Destroy(); + return false; + } + + const char* value; + value = eglQueryString(m_eglDisplay, EGL_VERSION); + CLog::Log(LOGINFO, "EGL_VERSION = %s", value ? value : "NULL"); + + value = eglQueryString(m_eglDisplay, EGL_VENDOR); + CLog::Log(LOGINFO, "EGL_VENDOR = %s", value ? value : "NULL"); + + value = eglQueryString(m_eglDisplay, EGL_EXTENSIONS); + CLog::Log(LOGINFO, "EGL_EXTENSIONS = %s", value ? value : "NULL"); + + value = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + CLog::Log(LOGINFO, "EGL_CLIENT_EXTENSIONS = %s", value ? value : "NULL"); + + if (eglBindAPI(renderingApi) != EGL_TRUE) + { + CEGLUtils::Log(LOGERROR, "failed to bind EGL API"); + Destroy(); + return false; + } + + return true; +} + +bool CEGLContextUtils::ChooseConfig(EGLint renderableType, EGLint visualId, bool hdr) +{ + EGLint numMatched{0}; + + if (m_eglDisplay == EGL_NO_DISPLAY) + { + throw std::logic_error("Choosing an EGLConfig requires an EGL display"); + } + + EGLint surfaceType = EGL_WINDOW_BIT; + // for the non-trivial dirty region modes, we need the EGL buffer to be preserved across updates + int guiAlgorithmDirtyRegions = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_guiAlgorithmDirtyRegions; + if (guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_COST_REDUCTION || + guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_UNION) + surfaceType |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT; + + CEGLAttributesVec attribs; + attribs.Add({{EGL_RED_SIZE, 8}, + {EGL_GREEN_SIZE, 8}, + {EGL_BLUE_SIZE, 8}, + {EGL_ALPHA_SIZE, 2}, + {EGL_DEPTH_SIZE, 16}, + {EGL_STENCIL_SIZE, 0}, + {EGL_SAMPLE_BUFFERS, 0}, + {EGL_SAMPLES, 0}, + {EGL_SURFACE_TYPE, surfaceType}, + {EGL_RENDERABLE_TYPE, renderableType}}); + + EGLConfig* currentConfig(hdr ? &m_eglHDRConfig : &m_eglConfig); + + if (hdr) +#if EGL_EXT_pixel_format_float + attribs.Add({{EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT}}); +#else + return false; +#endif + + const char* errorMsg = nullptr; + + if (eglChooseConfig(m_eglDisplay, attribs.Get(), nullptr, 0, &numMatched) != EGL_TRUE) + errorMsg = "failed to query number of EGL configs"; + + std::vector eglConfigs(numMatched); + if (eglChooseConfig(m_eglDisplay, attribs.Get(), eglConfigs.data(), numMatched, &numMatched) != EGL_TRUE) + errorMsg = "failed to find EGL configs with appropriate attributes"; + + if (errorMsg) + { + if (!hdr) + { + CEGLUtils::Log(LOGERROR, errorMsg); + Destroy(); + } + else + CEGLUtils::Log(LOGINFO, errorMsg); + return false; + } + + EGLint id{0}; + for (const auto &eglConfig: eglConfigs) + { + *currentConfig = eglConfig; + + if (visualId == 0) + break; + + if (eglGetConfigAttrib(m_eglDisplay, *currentConfig, EGL_NATIVE_VISUAL_ID, &id) != EGL_TRUE) + CEGLUtils::Log(LOGERROR, "failed to query EGL attribute EGL_NATIVE_VISUAL_ID"); + + if (visualId == id) + break; + } + + if (visualId != 0 && visualId != id) + { + CLog::Log(LOGDEBUG, "failed to find EGL config with EGL_NATIVE_VISUAL_ID={}", visualId); + return false; + } + + CLog::Log(LOGDEBUG, "EGL %sConfig Attributes:", hdr ? "HDR " : ""); + + for (const auto &eglAttribute : eglAttributes) + { + EGLint value{0}; + if (eglGetConfigAttrib(m_eglDisplay, *currentConfig, eglAttribute.first, &value) != EGL_TRUE) + CEGLUtils::Log(LOGERROR, StringUtils::Format("failed to query EGL attribute %s", eglAttribute.second)); + + // we only need to print the hex value if it's an actual EGL define + CLog::Log(LOGDEBUG, " %s: %s", eglAttribute.second, (value >= 0x3000 && value <= 0x3200) ? StringUtils::Format("0x%04x", value) : StringUtils::Format("%d", value)); + } + + return true; +} + +EGLint CEGLContextUtils::GetConfigAttrib(EGLint attribute) const +{ + EGLint value{0}; + if (eglGetConfigAttrib(m_eglDisplay, m_eglConfig, attribute, &value) != EGL_TRUE) + CEGLUtils::Log(LOGERROR, "failed to query EGL attribute"); + return value; +} + +bool CEGLContextUtils::CreateContext(CEGLAttributesVec contextAttribs) +{ + if (m_eglContext != EGL_NO_CONTEXT) + { + throw std::logic_error("Do not call CreateContext when context has already been created"); + } + + EGLConfig eglConfig{m_eglConfig}; + + if (CEGLUtils::HasExtension(m_eglDisplay, "EGL_KHR_no_config_context")) + eglConfig = EGL_NO_CONFIG_KHR; + + if (CEGLUtils::HasExtension(m_eglDisplay, "EGL_IMG_context_priority")) + contextAttribs.Add({{EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG}}); + +//! @todo remove when Raspberry Pi updates their EGL headers +#if !defined(TARGET_RASPBERRY_PI) + if (CEGLUtils::HasExtension(m_eglDisplay, "EGL_KHR_create_context") && + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_openGlDebugging) + { + contextAttribs.Add({{EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR}}); + } +#endif + + m_eglContext = eglCreateContext(m_eglDisplay, eglConfig, + EGL_NO_CONTEXT, contextAttribs.Get()); + + if (CEGLUtils::HasExtension(m_eglDisplay, "EGL_IMG_context_priority")) + { + EGLint value{EGL_CONTEXT_PRIORITY_MEDIUM_IMG}; + + if (eglQueryContext(m_eglDisplay, m_eglContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &value) != EGL_TRUE) + CEGLUtils::Log(LOGERROR, "failed to query EGL context attribute EGL_CONTEXT_PRIORITY_LEVEL_IMG"); + + if (value != EGL_CONTEXT_PRIORITY_HIGH_IMG) + CLog::Log(LOGDEBUG, "Failed to obtain a high priority EGL context"); + } + + if (m_eglContext == EGL_NO_CONTEXT) + { + // This is expected to fail under some circumstances, so log as debug + CLog::Log(LOGDEBUG, "Failed to create EGL context (EGL error %d)", eglGetError()); + return false; + } + + return true; +} + +bool CEGLContextUtils::BindContext() +{ + if (m_eglDisplay == EGL_NO_DISPLAY || m_eglSurface == EGL_NO_SURFACE || m_eglContext == EGL_NO_CONTEXT) + { + throw std::logic_error("Activating an EGLContext requires display, surface, and context"); + } + + if (eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext) != EGL_TRUE) + { + CLog::Log(LOGERROR, "Failed to make context current %p %p %p", + m_eglDisplay, m_eglSurface, m_eglContext); + return false; + } + + return true; +} + +void CEGLContextUtils::SurfaceAttrib() +{ + if (m_eglDisplay == EGL_NO_DISPLAY || m_eglSurface == EGL_NO_SURFACE) + { + throw std::logic_error("Setting surface attributes requires a surface"); + } + + // for the non-trivial dirty region modes, we need the EGL buffer to be preserved across updates + int guiAlgorithmDirtyRegions = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_guiAlgorithmDirtyRegions; + if (guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_COST_REDUCTION || + guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_UNION) + { + if (eglSurfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED) != EGL_TRUE) + { + CEGLUtils::Log(LOGERROR, "failed to set EGL_BUFFER_PRESERVED swap behavior"); + } + } +} + +void CEGLContextUtils::SurfaceAttrib(EGLint attribute, EGLint value) +{ + if (eglSurfaceAttrib(m_eglDisplay, m_eglSurface, attribute, value) != EGL_TRUE) + { + CEGLUtils::Log(LOGERROR, "failed to set EGL_BUFFER_PRESERVED swap behavior"); + } +} + +bool CEGLContextUtils::CreateSurface(EGLNativeWindowType nativeWindow, EGLint HDRcolorSpace /* = EGL_NONE */) +{ + if (m_eglDisplay == EGL_NO_DISPLAY) + { + throw std::logic_error("Creating a surface requires a display"); + } + if (m_eglSurface != EGL_NO_SURFACE) + { + throw std::logic_error("Do not call CreateSurface when surface has already been created"); + } + + CEGLAttributesVec attribs; + EGLConfig config = m_eglConfig; + +#ifdef EGL_GL_COLORSPACE + if (HDRcolorSpace != EGL_NONE) + { + attribs.Add({{EGL_GL_COLORSPACE, HDRcolorSpace}}); + config = m_eglHDRConfig; + } +#endif + + m_eglSurface = eglCreateWindowSurface(m_eglDisplay, config, nativeWindow, attribs.Get()); + + if (m_eglSurface == EGL_NO_SURFACE) + { + CEGLUtils::Log(LOGERROR, "failed to create window surface"); + return false; + } + + SurfaceAttrib(); + + return true; +} + +bool CEGLContextUtils::CreatePlatformSurface(void* nativeWindow, EGLNativeWindowType nativeWindowLegacy) +{ + if (m_eglDisplay == EGL_NO_DISPLAY) + { + throw std::logic_error("Creating a surface requires a display"); + } + if (m_eglSurface != EGL_NO_SURFACE) + { + throw std::logic_error("Do not call CreateSurface when surface has already been created"); + } + +#if defined(EGL_EXT_platform_base) + if (IsPlatformSupported()) + { + auto createPlatformWindowSurfaceEXT = CEGLUtils::GetRequiredProcAddress("eglCreatePlatformWindowSurfaceEXT"); + m_eglSurface = createPlatformWindowSurfaceEXT(m_eglDisplay, m_eglConfig, nativeWindow, nullptr); + + if (m_eglSurface == EGL_NO_SURFACE) + { + CEGLUtils::Log(LOGERROR, "failed to create platform window surface"); + return false; + } + } +#endif + + if (m_eglSurface == EGL_NO_SURFACE) + { + return CreateSurface(nativeWindowLegacy); + } + + SurfaceAttrib(); + + return true; +} + +void CEGLContextUtils::Destroy() +{ + DestroyContext(); + DestroySurface(); + + if (m_eglDisplay != EGL_NO_DISPLAY) + { + eglTerminate(m_eglDisplay); + m_eglDisplay = EGL_NO_DISPLAY; + } +} + +void CEGLContextUtils::DestroyContext() +{ + if (m_eglContext != EGL_NO_CONTEXT) + { + eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(m_eglDisplay, m_eglContext); + m_eglContext = EGL_NO_CONTEXT; + } +} + +void CEGLContextUtils::DestroySurface() +{ + if (m_eglSurface != EGL_NO_SURFACE) + { + eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(m_eglDisplay, m_eglSurface); + m_eglSurface = EGL_NO_SURFACE; + } +} + + +bool CEGLContextUtils::SetVSync(bool enable) +{ + if (m_eglDisplay == EGL_NO_DISPLAY) + { + return false; + } + + return (eglSwapInterval(m_eglDisplay, enable) == EGL_TRUE); +} + +bool CEGLContextUtils::TrySwapBuffers() +{ + if (m_eglDisplay == EGL_NO_DISPLAY || m_eglSurface == EGL_NO_SURFACE) + { + return false; + } + + return (eglSwapBuffers(m_eglDisplay, m_eglSurface) == EGL_TRUE); +} diff --git a/xbmc/utils/EGLUtils.h b/xbmc/utils/EGLUtils.h new file mode 100644 index 0000000..ad3b04d --- /dev/null +++ b/xbmc/utils/EGLUtils.h @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +class CEGLUtils +{ +public: + static std::set GetClientExtensions(); + static std::set GetExtensions(EGLDisplay eglDisplay); + static bool HasExtension(EGLDisplay eglDisplay, std::string const & name); + static bool HasClientExtension(std::string const& name); + static void Log(int logLevel, std::string const& what); + template + static T GetRequiredProcAddress(const char * procname) + { + T p = reinterpret_cast(eglGetProcAddress(procname)); + if (!p) + { + throw std::runtime_error(std::string("Could not get EGL function \"") + procname + "\" - maybe a required extension is not supported?"); + } + return p; + } + +private: + CEGLUtils(); +}; + +/** + * Convenience wrapper for heap-allocated EGL attribute arrays + * + * The wrapper makes sure that the key/value pairs are always written in actual + * pairs and that the array is always terminated with EGL_NONE. + */ +class CEGLAttributesVec +{ +public: + struct EGLAttribute + { + EGLint key; + EGLint value; + }; + + /** + * Add multiple attributes + * + * The array is automatically terminated with EGL_NONE + */ + void Add(std::initializer_list const& attributes) + { + for (auto const& attribute : attributes) + { + m_attributes.insert(m_attributes.begin(), attribute.value); + m_attributes.insert(m_attributes.begin(), attribute.key); + } + } + + /** + * Add one attribute + * + * The array is automatically terminated with EGL_NONE + */ + void Add(EGLAttribute const& attribute) + { + Add({attribute}); + } + + EGLint const * Get() const + { + return m_attributes.data(); + } + +private: + std::vector m_attributes{EGL_NONE}; +}; + +/** + * Convenience wrapper for stack-allocated EGL attribute arrays + * + * The wrapper makes sure that the key/value pairs are always written in actual + * pairs, that the array is always terminated with EGL_NONE, and that the bounds + * of the array are not exceeded (checked on runtime). + * + * \tparam AttributeCount maximum number of attributes that can be added. + * Determines the size of the storage array. + */ +template +class CEGLAttributes +{ +public: + struct EGLAttribute + { + EGLint key; + EGLint value; + }; + + CEGLAttributes() + { + m_attributes[0] = EGL_NONE; + } + + /** + * Add multiple attributes + * + * The array is automatically terminated with EGL_NONE + * + * \throws std::out_of_range if more than AttributeCount attributes are added + * in total + */ + void Add(std::initializer_list const& attributes) + { + if (m_writePosition + attributes.size() * 2 + 1 > m_attributes.size()) + { + throw std::out_of_range("CEGLAttributes::Add"); + } + + for (auto const& attribute : attributes) + { + m_attributes[m_writePosition++] = attribute.key; + m_attributes[m_writePosition++] = attribute.value; + } + m_attributes[m_writePosition] = EGL_NONE; + } + + /** + * Add one attribute + * + * The array is automatically terminated with EGL_NONE + * + * \throws std::out_of_range if more than AttributeCount attributes are added + * in total + */ + void Add(EGLAttribute const& attribute) + { + Add({attribute}); + } + + EGLint const * Get() const + { + return m_attributes.data(); + } + + int Size() const + { + return m_writePosition; + } + +private: + std::array m_attributes; + int m_writePosition{}; +}; + +class CEGLContextUtils final +{ +public: + CEGLContextUtils() = default; + /** + * \param platform platform as constant from an extension building on EGL_EXT_platform_base + */ + CEGLContextUtils(EGLenum platform, std::string const& platformExtension); + ~CEGLContextUtils(); + + bool CreateDisplay(EGLNativeDisplayType nativeDisplay); + /** + * Create EGLDisplay with EGL_EXT_platform_base + * + * Falls back to \ref CreateDisplay (with nativeDisplayLegacy) on failure. + * The native displays to use with the platform-based and the legacy approach + * may be defined to have different types and/or semantics, so this function takes + * both as separate parameters. + * + * \param nativeDisplay native display to use with eglGetPlatformDisplayEXT + * \param nativeDisplayLegacy native display to use with eglGetDisplay + */ + bool CreatePlatformDisplay(void* nativeDisplay, EGLNativeDisplayType nativeDisplayLegacy); + + void SurfaceAttrib(EGLint attribute, EGLint value); + bool CreateSurface(EGLNativeWindowType nativeWindow, EGLint HDRcolorSpace = EGL_NONE); + bool CreatePlatformSurface(void* nativeWindow, EGLNativeWindowType nativeWindowLegacy); + bool InitializeDisplay(EGLint renderingApi); + bool ChooseConfig(EGLint renderableType, EGLint visualId = 0, bool hdr = false); + bool CreateContext(CEGLAttributesVec contextAttribs); + bool BindContext(); + void Destroy(); + void DestroySurface(); + void DestroyContext(); + bool SetVSync(bool enable); + bool TrySwapBuffers(); + bool IsPlatformSupported() const; + EGLint GetConfigAttrib(EGLint attribute) const; + + EGLDisplay GetEGLDisplay() const + { + return m_eglDisplay; + } + EGLSurface GetEGLSurface() const + { + return m_eglSurface; + } + EGLContext GetEGLContext() const + { + return m_eglContext; + } + EGLConfig GetEGLConfig() const + { + return m_eglConfig; + } + +private: + void SurfaceAttrib(); + + EGLenum m_platform{EGL_NONE}; + bool m_platformSupported{false}; + + EGLDisplay m_eglDisplay{EGL_NO_DISPLAY}; + EGLSurface m_eglSurface{EGL_NO_SURFACE}; + EGLContext m_eglContext{EGL_NO_CONTEXT}; + EGLConfig m_eglConfig{}, m_eglHDRConfig{}; +}; diff --git a/xbmc/utils/EmbeddedArt.cpp b/xbmc/utils/EmbeddedArt.cpp new file mode 100644 index 0000000..3af2259 --- /dev/null +++ b/xbmc/utils/EmbeddedArt.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "EmbeddedArt.h" + +#include "Archive.h" + +EmbeddedArtInfo::EmbeddedArtInfo(size_t size, + const std::string &mime, const std::string& type) +{ + Set(size, mime, type); +} + +void EmbeddedArtInfo::Set(size_t size, const std::string &mime, const std::string& type) +{ + m_size = size; + m_mime = mime; + m_type = type; +} + +void EmbeddedArtInfo::Clear() +{ + m_mime.clear(); + m_size = 0; +} + +bool EmbeddedArtInfo::Empty() const +{ + return m_size == 0; +} + +bool EmbeddedArtInfo::Matches(const EmbeddedArtInfo &right) const +{ + return (m_size == right.m_size && + m_mime == right.m_mime && + m_type == right.m_type); +} + +void EmbeddedArtInfo::Archive(CArchive &ar) +{ + if (ar.IsStoring()) + { + ar << m_size; + ar << m_mime; + ar << m_type; + } + else + { + ar >> m_size; + ar >> m_mime; + ar >> m_type; + } +} + +EmbeddedArt::EmbeddedArt(const uint8_t *data, size_t size, + const std::string &mime, const std::string& type) +{ + Set(data, size, mime, type); +} + +void EmbeddedArt::Set(const uint8_t *data, size_t size, + const std::string &mime, const std::string& type) +{ + EmbeddedArtInfo::Set(size, mime, type); + m_data.resize(size); + m_data.assign(data, data+size); +} diff --git a/xbmc/utils/EmbeddedArt.h b/xbmc/utils/EmbeddedArt.h new file mode 100644 index 0000000..b752bac --- /dev/null +++ b/xbmc/utils/EmbeddedArt.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "IArchivable.h" + +#include +#include +#include + +class EmbeddedArtInfo : public IArchivable +{ +public: + EmbeddedArtInfo() = default; + EmbeddedArtInfo(size_t size, const std::string &mime, const std::string& type = ""); + virtual ~EmbeddedArtInfo() = default; + + // implementation of IArchivable + void Archive(CArchive& ar) override; + + void Set(size_t size, const std::string &mime, const std::string& type = ""); + void Clear(); + bool Empty() const; + bool Matches(const EmbeddedArtInfo &right) const; + void SetType(const std::string& type) { m_type = type; } + + size_t m_size = 0; + std::string m_mime; + std::string m_type; +}; + +class EmbeddedArt : public EmbeddedArtInfo +{ +public: + EmbeddedArt() = default; + EmbeddedArt(const uint8_t *data, size_t size, + const std::string &mime, const std::string& type = ""); + + void Set(const uint8_t *data, size_t size, + const std::string &mime, const std::string& type = ""); + + std::vector m_data; +}; diff --git a/xbmc/utils/EndianSwap.cpp b/xbmc/utils/EndianSwap.cpp new file mode 100644 index 0000000..3f645d9 --- /dev/null +++ b/xbmc/utils/EndianSwap.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "EndianSwap.h" + +/* based on libavformat/spdif.c */ +void Endian_Swap16_buf(uint16_t *dst, uint16_t *src, int w) +{ + int i; + + for (i = 0; i + 8 <= w; i += 8) { + dst[i + 0] = Endian_Swap16(src[i + 0]); + dst[i + 1] = Endian_Swap16(src[i + 1]); + dst[i + 2] = Endian_Swap16(src[i + 2]); + dst[i + 3] = Endian_Swap16(src[i + 3]); + dst[i + 4] = Endian_Swap16(src[i + 4]); + dst[i + 5] = Endian_Swap16(src[i + 5]); + dst[i + 6] = Endian_Swap16(src[i + 6]); + dst[i + 7] = Endian_Swap16(src[i + 7]); + } + + for (; i < w; i++) + dst[i + 0] = Endian_Swap16(src[i + 0]); +} + diff --git a/xbmc/utils/EndianSwap.h b/xbmc/utils/EndianSwap.h new file mode 100644 index 0000000..0b02689 --- /dev/null +++ b/xbmc/utils/EndianSwap.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + + /* Endian_SwapXX functions taken from SDL (SDL_endian.h) */ + +#ifdef TARGET_POSIX +#include +#elif TARGET_WINDOWS +#define __inline__ __inline +#include +#endif + + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__)) +static __inline__ uint16_t Endian_Swap16(uint16_t x) +{ + uint16_t result; + + __asm__("rlwimi %0,%2,8,16,23" : "=&r" (result) : "0" (x >> 8), "r" (x)); + return result; +} + +static __inline__ uint32_t Endian_Swap32(uint32_t x) +{ + uint32_t result; + + __asm__("rlwimi %0,%2,24,16,23" : "=&r" (result) : "0" (x>>24), "r" (x)); + __asm__("rlwimi %0,%2,8,8,15" : "=&r" (result) : "0" (result), "r" (x)); + __asm__("rlwimi %0,%2,24,0,7" : "=&r" (result) : "0" (result), "r" (x)); + return result; +} +#else +static __inline__ uint16_t Endian_Swap16(uint16_t x) { + return((x<<8)|(x>>8)); +} + +static __inline__ uint32_t Endian_Swap32(uint32_t x) { + return((x<<24)|((x<<8)&0x00FF0000)|((x>>8)&0x0000FF00)|(x>>24)); +} +#endif + +static __inline__ uint64_t Endian_Swap64(uint64_t x) { + uint32_t hi, lo; + + /* Separate into high and low 32-bit values and swap them */ + lo = (uint32_t)(x&0xFFFFFFFF); + x >>= 32; + hi = (uint32_t)(x&0xFFFFFFFF); + x = Endian_Swap32(lo); + x <<= 32; + x |= Endian_Swap32(hi); + return(x); + +} + +void Endian_Swap16_buf(uint16_t *dst, uint16_t *src, int w); + +#ifndef WORDS_BIGENDIAN +#define Endian_SwapLE16(X) (X) +#define Endian_SwapLE32(X) (X) +#define Endian_SwapLE64(X) (X) +#define Endian_SwapBE16(X) Endian_Swap16(X) +#define Endian_SwapBE32(X) Endian_Swap32(X) +#define Endian_SwapBE64(X) Endian_Swap64(X) +#else +#define Endian_SwapLE16(X) Endian_Swap16(X) +#define Endian_SwapLE32(X) Endian_Swap32(X) +#define Endian_SwapLE64(X) Endian_Swap64(X) +#define Endian_SwapBE16(X) (X) +#define Endian_SwapBE32(X) (X) +#define Endian_SwapBE64(X) (X) +#endif + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif + diff --git a/xbmc/utils/EventStream.h b/xbmc/utils/EventStream.h new file mode 100644 index 0000000..42a17df --- /dev/null +++ b/xbmc/utils/EventStream.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "EventStreamDetail.h" +#include "JobManager.h" +#include "threads/CriticalSection.h" +#include "threads/SingleLock.h" + +#include +#include +#include + + +template +class CEventStream +{ +public: + + template + void Subscribe(A* owner, void (A::*fn)(const Event&)) + { + auto subscription = std::make_shared>(owner, fn); + CSingleLock lock(m_criticalSection); + m_subscriptions.emplace_back(std::move(subscription)); + } + + template + void Unsubscribe(A* obj) + { + std::vector>> toCancel; + { + CSingleLock lock(m_criticalSection); + auto it = m_subscriptions.begin(); + while (it != m_subscriptions.end()) + { + if ((*it)->IsOwnedBy(obj)) + { + toCancel.push_back(*it); + it = m_subscriptions.erase(it); + } + else + { + ++it; + } + } + } + for (auto& subscription : toCancel) + subscription->Cancel(); + } + +protected: + std::vector>> m_subscriptions; + CCriticalSection m_criticalSection; +}; + + +template +class CEventSource : public CEventStream +{ +public: + explicit CEventSource() : m_queue(false, 1, CJob::PRIORITY_HIGH) {}; + + template + void Publish(A event) + { + CSingleLock lock(this->m_criticalSection); + auto& subscriptions = this->m_subscriptions; + auto task = [subscriptions, event](){ + for (auto& s: subscriptions) + s->HandleEvent(event); + }; + lock.Leave(); + m_queue.Submit(std::move(task)); + } + +private: + CJobQueue m_queue; +}; + +template +class CBlockingEventSource : public CEventStream +{ +public: + template + void HandleEvent(A event) + { + CSingleLock lock(this->m_criticalSection); + for (const auto& subscription : this->m_subscriptions) + { + subscription->HandleEvent(event); + } + } +}; diff --git a/xbmc/utils/EventStreamDetail.h b/xbmc/utils/EventStreamDetail.h new file mode 100644 index 0000000..c8eec67 --- /dev/null +++ b/xbmc/utils/EventStreamDetail.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "threads/CriticalSection.h" +#include "threads/SingleLock.h" + +namespace detail +{ + +template +class ISubscription +{ +public: + virtual void HandleEvent(const Event& event) = 0; + virtual void Cancel() = 0; + virtual bool IsOwnedBy(void* obj) = 0; + virtual ~ISubscription() = default; +}; + +template +class CSubscription : public ISubscription +{ +public: + typedef void (Owner::*Fn)(const Event&); + CSubscription(Owner* owner, Fn fn); + void HandleEvent(const Event& event) override; + void Cancel() override; + bool IsOwnedBy(void *obj) override; + +private: + Owner* m_owner; + Fn m_eventHandler; + CCriticalSection m_criticalSection; +}; + +template +CSubscription::CSubscription(Owner* owner, Fn fn) + : m_owner(owner), m_eventHandler(fn) +{} + +template +bool CSubscription::IsOwnedBy(void* obj) +{ + CSingleLock lock(m_criticalSection); + return obj != nullptr && obj == m_owner; +} + +template +void CSubscription::Cancel() +{ + CSingleLock lock(m_criticalSection); + m_owner = nullptr; +} + +template +void CSubscription::HandleEvent(const Event& event) +{ + CSingleLock lock(m_criticalSection); + if (m_owner) + (m_owner->*m_eventHandler)(event); +} +} diff --git a/xbmc/utils/Fanart.cpp b/xbmc/utils/Fanart.cpp new file mode 100644 index 0000000..fbc3774 --- /dev/null +++ b/xbmc/utils/Fanart.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Fanart.h" + +#include "StringUtils.h" +#include "URIUtils.h" +#include "utils/XBMCTinyXML.h" +#include "utils/XMLUtils.h" + +#include +#include + +const unsigned int CFanart::max_fanart_colors=3; + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// CFanart Functions +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +CFanart::CFanart() = default; + +void CFanart::Pack() +{ + // Take our data and pack it into the m_xml string + m_xml.clear(); + TiXmlElement fanart("fanart"); + for (std::vector::const_iterator it = m_fanart.begin(); it != m_fanart.end(); ++it) + { + TiXmlElement thumb("thumb"); + thumb.SetAttribute("colors", it->strColors.c_str()); + thumb.SetAttribute("preview", it->strPreview.c_str()); + TiXmlText text(it->strImage); + thumb.InsertEndChild(text); + fanart.InsertEndChild(thumb); + } + m_xml << fanart; +} + +void CFanart::AddFanart(const std::string& image, const std::string& preview, const std::string& colors) +{ + SFanartData info; + info.strPreview = preview; + info.strImage = image; + ParseColors(colors, info.strColors); + m_fanart.push_back(std::move(info)); +} + +void CFanart::Clear() +{ + m_fanart.clear(); + m_xml.clear(); +} + +bool CFanart::Unpack() +{ + CXBMCTinyXML doc; + doc.Parse(m_xml); + + m_fanart.clear(); + + TiXmlElement *fanart = doc.FirstChildElement("fanart"); + while (fanart) + { + std::string url = XMLUtils::GetAttribute(fanart, "url"); + TiXmlElement *fanartThumb = fanart->FirstChildElement("thumb"); + while (fanartThumb) + { + if (!fanartThumb->NoChildren()) + { + SFanartData data; + if (url.empty()) + { + data.strImage = fanartThumb->FirstChild()->ValueStr(); + data.strPreview = XMLUtils::GetAttribute(fanartThumb, "preview"); + } + else + { + data.strImage = URIUtils::AddFileToFolder(url, fanartThumb->FirstChild()->ValueStr()); + if (fanartThumb->Attribute("preview")) + data.strPreview = URIUtils::AddFileToFolder(url, fanartThumb->Attribute("preview")); + } + ParseColors(XMLUtils::GetAttribute(fanartThumb, "colors"), data.strColors); + m_fanart.push_back(data); + } + fanartThumb = fanartThumb->NextSiblingElement("thumb"); + } + fanart = fanart->NextSiblingElement("fanart"); + } + return true; +} + +std::string CFanart::GetImageURL(unsigned int index) const +{ + if (index >= m_fanart.size()) + return ""; + + return m_fanart[index].strImage; +} + +std::string CFanart::GetPreviewURL(unsigned int index) const +{ + if (index >= m_fanart.size()) + return ""; + + return m_fanart[index].strPreview.empty() ? m_fanart[index].strImage : m_fanart[index].strPreview; +} + +const std::string CFanart::GetColor(unsigned int index) const +{ + if (index >= max_fanart_colors || m_fanart.empty() || + m_fanart[0].strColors.size() < index*9+8) + return "FFFFFFFF"; + + // format is AARRGGBB,AARRGGBB etc. + return m_fanart[0].strColors.substr(index*9, 8); +} + +bool CFanart::SetPrimaryFanart(unsigned int index) +{ + if (index >= m_fanart.size()) + return false; + + std::iter_swap(m_fanart.begin()+index, m_fanart.begin()); + + // repack our data + Pack(); + + return true; +} + +unsigned int CFanart::GetNumFanarts() const +{ + return m_fanart.size(); +} + +bool CFanart::ParseColors(const std::string &colorsIn, std::string &colorsOut) +{ + // Formats: + // 0: XBMC ARGB Hexadecimal string comma separated "FFFFFFFF,DDDDDDDD,AAAAAAAA" + // 1: The TVDB RGB Int Triplets, pipe separate with leading/trailing pipes "|68,69,59|69,70,58|78,78,68|" + + // Essentially we read the colors in using the proper format, and store them in our own fixed temporary format (3 DWORDS), and then + // write them back in in the specified format. + + if (colorsIn.empty()) + return false; + + // check for the TVDB RGB triplets "|68,69,59|69,70,58|78,78,68|" + if (colorsIn[0] == '|') + { // need conversion + colorsOut.clear(); + std::vector strColors = StringUtils::Split(colorsIn, "|"); + for (int i = 0; i < std::min((int)strColors.size()-1, (int)max_fanart_colors); i++) + { // split up each color + std::vector strTriplets = StringUtils::Split(strColors[i+1], ","); + if (strTriplets.size() == 3) + { // convert + if (colorsOut.size()) + colorsOut += ","; + colorsOut += StringUtils::Format("FF%2lx%2lx%2lx", atol(strTriplets[0].c_str()), atol(strTriplets[1].c_str()), atol(strTriplets[2].c_str())); + } + } + } + else + { // assume is our format + colorsOut = colorsIn; + } + return true; +} diff --git a/xbmc/utils/Fanart.h b/xbmc/utils/Fanart.h new file mode 100644 index 0000000..c47d2df --- /dev/null +++ b/xbmc/utils/Fanart.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +// Fanart.h +////////////////////////////////////////////////////////////////////// + +#include +#include + +/// +/// /brief CFanart is the core of fanart support and contains all fanart data for a specific show +/// +/// CFanart stores all data related to all available fanarts for a given TV show and provides +/// functions required to manipulate and access that data. +/// In order to provide an interface between the fanart data and the XBMC database, all data +/// is stored internally it its own form, as well as packed into an XML formatted string +/// stored in the member variable m_xml. +/// Information on multiple fanarts for a given show is stored, but XBMC only cares about the +/// very first fanart stored. These interfaces provide a means to access the data in that first +/// fanart record, as well as to set which fanart is the first record. Externally, all XBMC needs +/// to care about is getting and setting that first record. Everything else is maintained internally +/// by CFanart. This point is key to using the interface properly. +class CFanart +{ +public: + /// + /// Standard constructor doesn't need to do anything + CFanart(); + /// + /// Takes the internal fanart data and packs it into an XML formatted string in m_xml + /// \sa m_xml + void Pack(); + /// + /// Takes the XML formatted string m_xml and unpacks the fanart data contained into the internal data + /// \return A boolean indicating success or failure + /// \sa m_xml + bool Unpack(); + /// + /// Retrieves the fanart full res image URL + /// \param index - index of image to retrieve (defaults to 0) + /// \return A string containing the full URL to the full resolution fanart image + std::string GetImageURL(unsigned int index = 0) const; + /// + /// Retrieves the fanart preview image URL, or full res image URL if that doesn't exist + /// \param index - index of image to retrieve (defaults to 0) + /// \return A string containing the full URL to the full resolution fanart image + std::string GetPreviewURL(unsigned int index = 0) const; + /// + /// Used to return a specified fanart theme color value + /// \param index: 0 based index of the color to retrieve. A fanart theme contains 3 colors, indices 0-2, arranged from darkest to lightest. + const std::string GetColor(unsigned int index) const; + /// + /// Sets a particular fanart to be the "primary" fanart, or in other words, sets which fanart is actually used by XBMC + /// + /// This is the one of the only instances in the public interface where there is any hint that more than one fanart exists, but its by necessity. + /// \param index: 0 based index of which fanart to set as the primary fanart + /// \return A boolean value indicating success or failure. This should only return false if the specified index is not a valid fanart + bool SetPrimaryFanart(unsigned int index); + /// + /// Returns how many fanarts are stored + /// \return An integer indicating how many fanarts are stored in the class. Fanart indices are 0 to (GetNumFanarts() - 1) + unsigned int GetNumFanarts() const; + /// Adds an image to internal fanart data + void AddFanart(const std::string& image, const std::string& preview, const std::string& colors); + /// Clear all internal fanart data + void Clear(); + /// + /// m_xml contains an XML formatted string which is all fanart packed into one string. + /// + /// This string is the "interface" as it were to the XBMC database, and MUST be kept in sync with the rest of the class. Therefore + /// anytime this string is changed, the change should be followed up by a call to CFanart::UnPack(). This XML formatted string is + /// also the interface used to pass the fanart data from the scraper to CFanart. + std::string m_xml; +private: + static const unsigned int max_fanart_colors; + /// + /// Parse various color formats as returned by the sites scraped into a format we recognize + /// + /// Supported Formats: + /// + /// * The TVDB RGB Int Triplets, pipe separate with leading/trailing pipes "|68,69,59|69,70,58|78,78,68|" + /// * XBMC ARGB Hexadecimal string comma separated "FFFFFFFF,DDDDDDDD,AAAAAAAA" + /// + /// \param colorsIn: string containing colors in some format to be converted + /// \param colorsOut: XBMC ARGB Hexadecimal string comma separated "FFFFFFFF,DDDDDDDD,AAAAAAAA" + /// \return boolean indicating success or failure. + static bool ParseColors(const std::string&colorsIn, std::string&colorsOut); + + struct SFanartData + { + std::string strImage; + std::string strColors; + std::string strPreview; + }; + + /// + /// std::vector that stores all our fanart data + std::vector m_fanart; +}; + diff --git a/xbmc/utils/FileExtensionProvider.cpp b/xbmc/utils/FileExtensionProvider.cpp new file mode 100644 index 0000000..001629e --- /dev/null +++ b/xbmc/utils/FileExtensionProvider.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "FileExtensionProvider.h" + +#include "ServiceBroker.h" +#include "addons/AddonManager.h" +#include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" + +#include +#include + +using namespace ADDON; + +const std::vector ADDON_TYPES = { + ADDON_VFS, + ADDON_IMAGEDECODER, + ADDON_AUDIODECODER +}; + +CFileExtensionProvider::CFileExtensionProvider(ADDON::CAddonMgr& addonManager) + : m_advancedSettings(CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()), + m_addonManager(addonManager) +{ + SetAddonExtensions(); + + m_addonManager.Events().Subscribe(this, &CFileExtensionProvider::OnAddonEvent); +} + +CFileExtensionProvider::~CFileExtensionProvider() +{ + m_addonManager.Events().Unsubscribe(this); + + m_advancedSettings.reset(); + m_addonExtensions.clear(); +} + +std::string CFileExtensionProvider::GetDiscStubExtensions() const +{ + return m_advancedSettings->m_discStubExtensions; +} + +std::string CFileExtensionProvider::GetMusicExtensions() const +{ + std::string extensions(m_advancedSettings->m_musicExtensions); + extensions += '|' + GetAddonExtensions(ADDON_VFS); + extensions += '|' + GetAddonExtensions(ADDON_AUDIODECODER); + + return extensions; +} + +std::string CFileExtensionProvider::GetPictureExtensions() const +{ + std::string extensions(m_advancedSettings->m_pictureExtensions); + extensions += '|' + GetAddonExtensions(ADDON_VFS); + extensions += '|' + GetAddonExtensions(ADDON_IMAGEDECODER); + + return extensions; +} + +std::string CFileExtensionProvider::GetSubtitleExtensions() const +{ + std::string extensions(m_advancedSettings->m_subtitlesExtensions); + extensions += '|' + GetAddonExtensions(ADDON_VFS); + + return extensions; +} + +std::string CFileExtensionProvider::GetVideoExtensions() const +{ + std::string extensions(m_advancedSettings->m_videoExtensions); + if (!extensions.empty()) + extensions += '|'; + extensions += GetAddonExtensions(ADDON_VFS); + + return extensions; +} + +std::string CFileExtensionProvider::GetFileFolderExtensions() const +{ + std::string extensions(GetAddonFileFolderExtensions(ADDON_VFS)); + if (!extensions.empty()) + extensions += '|'; + extensions += GetAddonFileFolderExtensions(ADDON_AUDIODECODER); + + return extensions; +} + +std::string CFileExtensionProvider::GetAddonExtensions(const TYPE &type) const +{ + auto it = m_addonExtensions.find(type); + if (it != m_addonExtensions.end()) + return it->second; + + return ""; +} + +std::string CFileExtensionProvider::GetAddonFileFolderExtensions(const TYPE &type) const +{ + auto it = m_addonExtensions.find(type); + if (it != m_addonExtensions.end()) + return it->second; + + return ""; +} + +void CFileExtensionProvider::SetAddonExtensions() +{ + for (auto const type : ADDON_TYPES) + { + SetAddonExtensions(type); + } +} + +void CFileExtensionProvider::SetAddonExtensions(const TYPE& type) +{ + std::vector extensions; + std::vector fileFolderExtensions; + std::vector addonInfos; + m_addonManager.GetAddonInfos(addonInfos, true, type); + for (const auto& addonInfo : addonInfos) + { + std::string info = ADDON_VFS == type ? "@extensions" : "@extension"; + std::string ext = addonInfo->Type(type)->GetValue(info).asString(); + if (!ext.empty()) + { + extensions.push_back(ext); + if (type == ADDON_VFS || type == ADDON_AUDIODECODER) + { + std::string info2 = ADDON_VFS == type ? "@filedirectories" : "@tracks"; + if (addonInfo->Type(type)->GetValue(info2).asBoolean()) + fileFolderExtensions.push_back(ext); + } + if (type == ADDON_VFS) + { + if (addonInfo->Type(type)->GetValue("@encodedhostname").asBoolean()) + { + std::string prot = addonInfo->Type(type)->GetValue("@protocols").asString(); + auto prots = StringUtils::Split(prot, "|"); + for (const std::string& it : prots) + m_encoded.push_back(it); + } + } + } + } + + m_addonExtensions.insert(make_pair(type, StringUtils::Join(extensions, "|"))); + if (!fileFolderExtensions.empty()) + m_addonFileFolderExtensions.insert(make_pair(type, StringUtils::Join(fileFolderExtensions, "|"))); +} + +void CFileExtensionProvider::OnAddonEvent(const AddonEvent& event) +{ + if (typeid(event) == typeid(AddonEvents::Enabled) || + typeid(event) == typeid(AddonEvents::Disabled) || + typeid(event) == typeid(AddonEvents::ReInstalled)) + { + for (auto &type : ADDON_TYPES) + { + if (m_addonManager.HasType(event.id, type)) + { + SetAddonExtensions(type); + break; + } + } + } + else if (typeid(event) == typeid(AddonEvents::UnInstalled)) + { + SetAddonExtensions(); + } +} + +bool CFileExtensionProvider::EncodedHostName(const std::string& protocol) const +{ + return std::find(m_encoded.begin(),m_encoded.end(),protocol) != m_encoded.end(); +} diff --git a/xbmc/utils/FileExtensionProvider.h b/xbmc/utils/FileExtensionProvider.h new file mode 100644 index 0000000..fce384a --- /dev/null +++ b/xbmc/utils/FileExtensionProvider.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "addons/AddonEvents.h" +#include "addons/addoninfo/AddonInfo.h" +#include "settings/AdvancedSettings.h" + +namespace ADDON +{ + class CAddonMgr; +} + +class CFileExtensionProvider +{ +public: + CFileExtensionProvider(ADDON::CAddonMgr& addonManager); + ~CFileExtensionProvider(); + + /*! + * @brief Returns a list of picture extensions + */ + std::string GetPictureExtensions() const; + + /*! + * @brief Returns a list of music extensions + */ + std::string GetMusicExtensions() const; + + /*! + * @brief Returns a list of video extensions + */ + std::string GetVideoExtensions() const; + + /*! + * @brief Returns a list of subtitle extensions + */ + std::string GetSubtitleExtensions() const; + + /*! + * @brief Returns a list of disc stub extensions + */ + std::string GetDiscStubExtensions() const; + + /*! + * @brief Returns a file folder extensions + */ + std::string GetFileFolderExtensions() const; + + /*! + * @brief Returns whether a url protocol from add-ons use encoded hostnames + */ + bool EncodedHostName(const std::string& protocol) const; + +private: + std::string GetAddonExtensions(const ADDON::TYPE &type) const; + std::string GetAddonFileFolderExtensions(const ADDON::TYPE &type) const; + void SetAddonExtensions(); + void SetAddonExtensions(const ADDON::TYPE &type); + + void OnAddonEvent(const ADDON::AddonEvent& event); + + // Construction properties + std::shared_ptr m_advancedSettings; + ADDON::CAddonMgr &m_addonManager; + + // File extension properties + std::map m_addonExtensions; + std::map m_addonFileFolderExtensions; + + // Protocols from add-ons with encoded host names + std::vector m_encoded; +}; diff --git a/xbmc/utils/FileOperationJob.cpp b/xbmc/utils/FileOperationJob.cpp new file mode 100644 index 0000000..67a5536 --- /dev/null +++ b/xbmc/utils/FileOperationJob.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "FileOperationJob.h" + +#include "ServiceBroker.h" +#include "URL.h" +#include "Util.h" +#include "dialogs/GUIDialogExtendedProgressBar.h" +#include "filesystem/Directory.h" +#include "filesystem/File.h" +#include "filesystem/FileDirectoryFactory.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/LocalizeStrings.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "utils/log.h" + +using namespace XFILE; + +CFileOperationJob::CFileOperationJob() + : m_items(), + m_strDestFile(), + m_avgSpeed(), + m_currentOperation(), + m_currentFile() +{ } + +CFileOperationJob::CFileOperationJob(FileAction action, CFileItemList & items, + const std::string& strDestFile, + bool displayProgress /* = false */, + int heading /* = 0 */, int line /* = 0 */) + : m_action(action), + m_items(), + m_strDestFile(strDestFile), + m_avgSpeed(), + m_currentOperation(), + m_currentFile(), + m_displayProgress(displayProgress), + m_heading(heading), + m_line(line) +{ + SetFileOperation(action, items, strDestFile); +} + +void CFileOperationJob::SetFileOperation(FileAction action, CFileItemList &items, const std::string &strDestFile) +{ + m_action = action; + m_strDestFile = strDestFile; + + m_items.Clear(); + for (int i = 0; i < items.Size(); i++) + m_items.Add(CFileItemPtr(new CFileItem(*items[i]))); +} + +bool CFileOperationJob::DoWork() +{ + FileOperationList ops; + double totalTime = 0.0; + + if (m_displayProgress && GetProgressDialog() == NULL) + { + CGUIDialogExtendedProgressBar* dialog = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow(WINDOW_DIALOG_EXT_PROGRESS); + SetProgressBar(dialog->GetHandle(GetActionString(m_action))); + } + + bool success = DoProcess(m_action, m_items, m_strDestFile, ops, totalTime); + + unsigned int size = ops.size(); + + double opWeight = 100.0 / totalTime; + double current = 0.0; + + for (unsigned int i = 0; i < size && success; i++) + success &= ops[i].ExecuteOperation(this, current, opWeight); + + MarkFinished(); + + return success; +} + +bool CFileOperationJob::DoProcessFile(FileAction action, const std::string& strFileA, const std::string& strFileB, FileOperationList &fileOperations, double &totalTime) +{ + int64_t time = 1; + + if (action == ActionCopy || action == ActionReplace || (action == ActionMove && !CanBeRenamed(strFileA, strFileB))) + { + struct __stat64 data; + if (CFile::Stat(strFileA, &data) == 0) + time += data.st_size; + } + + fileOperations.push_back(CFileOperation(action, strFileA, strFileB, time)); + + totalTime += time; + + return true; +} + +bool CFileOperationJob::DoProcessFolder(FileAction action, const std::string& strPath, const std::string& strDestFile, FileOperationList &fileOperations, double &totalTime) +{ + // check whether this folder is a filedirectory - if so, we don't process it's contents + CFileItem item(strPath, false); + IFileDirectory *file = CFileDirectoryFactory::Create(item.GetURL(), &item); + if (file) + { + delete file; + return true; + } + + CFileItemList items; + CDirectory::GetDirectory(strPath, items, "", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_GET_HIDDEN); + for (int i = 0; i < items.Size(); i++) + { + CFileItemPtr pItem = items[i]; + pItem->Select(true); + } + + if (!DoProcess(action, items, strDestFile, fileOperations, totalTime)) + { + CLog::Log(LOGERROR,"FileManager: error while processing folder: %s", strPath.c_str()); + return false; + } + + if (action == ActionMove) + { + fileOperations.push_back(CFileOperation(ActionDeleteFolder, strPath, "", 1)); + totalTime += 1.0; + } + + return true; +} + +bool CFileOperationJob::DoProcess(FileAction action, CFileItemList & items, const std::string& strDestFile, FileOperationList &fileOperations, double &totalTime) +{ + for (int iItem = 0; iItem < items.Size(); ++iItem) + { + CFileItemPtr pItem = items[iItem]; + if (pItem->IsSelected()) + { + std::string strNoSlash = pItem->GetPath(); + URIUtils::RemoveSlashAtEnd(strNoSlash); + std::string strFileName = URIUtils::GetFileName(strNoSlash); + + // special case for upnp + if (URIUtils::IsUPnP(items.GetPath()) || URIUtils::IsUPnP(pItem->GetPath())) + { + // get filename from label instead of path + strFileName = pItem->GetLabel(); + + if (!pItem->m_bIsFolder && !URIUtils::HasExtension(strFileName)) + { + // FIXME: for now we only work well if the url has the extension + // we should map the content type to the extension otherwise + strFileName += URIUtils::GetExtension(pItem->GetPath()); + } + + strFileName = CUtil::MakeLegalFileName(strFileName); + } + + std::string strnewDestFile; + if (!strDestFile.empty()) // only do this if we have a destination + strnewDestFile = URIUtils::ChangeBasePath(pItem->GetPath(), strFileName, strDestFile); // Convert (URL) encoding + slashes (if source / target differ) + + if (pItem->m_bIsFolder) + { + // in ActionReplace mode all subdirectories will be removed by the below + // DoProcessFolder(ActionDelete) call as well, so ActionCopy is enough when + // processing those + FileAction subdirAction = (action == ActionReplace) ? ActionCopy : action; + // create folder on dest. drive + if (action != ActionDelete && action != ActionDeleteFolder) + DoProcessFile(ActionCreateFolder, strnewDestFile, "", fileOperations, totalTime); + + if (action == ActionReplace && CDirectory::Exists(strnewDestFile)) + DoProcessFolder(ActionDelete, strnewDestFile, "", fileOperations, totalTime); + + if (!DoProcessFolder(subdirAction, pItem->GetPath(), strnewDestFile, fileOperations, totalTime)) + return false; + + if (action == ActionDelete || action == ActionDeleteFolder) + DoProcessFile(ActionDeleteFolder, pItem->GetPath(), "", fileOperations, totalTime); + } + else + DoProcessFile(action, pItem->GetPath(), strnewDestFile, fileOperations, totalTime); + } + } + + return true; +} + +CFileOperationJob::CFileOperation::CFileOperation(FileAction action, const std::string &strFileA, const std::string &strFileB, int64_t time) + : m_action(action), + m_strFileA(strFileA), + m_strFileB(strFileB), + m_time(time) +{ } + +struct DataHolder +{ + CFileOperationJob *base; + double current; + double opWeight; +}; + +std::string CFileOperationJob::GetActionString(FileAction action) +{ + std::string result; + switch (action) + { + case ActionCopy: + case ActionReplace: + result = g_localizeStrings.Get(115); + break; + + case ActionMove: + result = g_localizeStrings.Get(116); + break; + + case ActionDelete: + case ActionDeleteFolder: + result = g_localizeStrings.Get(117); + break; + + case ActionCreateFolder: + result = g_localizeStrings.Get(119); + break; + + default: + break; + } + + return result; +} + +bool CFileOperationJob::CFileOperation::ExecuteOperation(CFileOperationJob *base, double ¤t, double opWeight) +{ + bool bResult = true; + + base->m_currentFile = CURL(m_strFileA).GetFileNameWithoutPath(); + base->m_currentOperation = GetActionString(m_action); + + if (base->ShouldCancel((unsigned int)current, 100)) + return false; + + base->SetText(base->GetCurrentFile()); + + DataHolder data = {base, current, opWeight}; + + switch (m_action) + { + case ActionCopy: + case ActionReplace: + bResult = CFile::Copy(m_strFileA, m_strFileB, this, &data); + break; + + case ActionMove: + if (CanBeRenamed(m_strFileA, m_strFileB)) + bResult = CFile::Rename(m_strFileA, m_strFileB); + else if (CFile::Copy(m_strFileA, m_strFileB, this, &data)) + bResult = CFile::Delete(m_strFileA); + else + bResult = false; + break; + + case ActionDelete: + bResult = CFile::Delete(m_strFileA); + break; + + case ActionDeleteFolder: + bResult = CDirectory::Remove(m_strFileA); + break; + + case ActionCreateFolder: + bResult = CDirectory::Create(m_strFileA); + break; + + default: + CLog::Log(LOGERROR, "FileManager: unknown operation"); + bResult = false; + break; + } + + current += (double)m_time * opWeight; + + return bResult; +} + +inline bool CFileOperationJob::CanBeRenamed(const std::string &strFileA, const std::string &strFileB) +{ +#ifndef TARGET_POSIX + if (strFileA[1] == ':' && strFileA[0] == strFileB[0]) + return true; +#else + if (URIUtils::IsHD(strFileA) && URIUtils::IsHD(strFileB)) + return true; + else if (URIUtils::IsSmb(strFileA) && URIUtils::IsSmb(strFileB)) { + CURL smbFileA(strFileA), smbFileB(strFileB); + return smbFileA.GetHostName() == smbFileB.GetHostName() && + smbFileA.GetShareName() == smbFileB.GetShareName(); + } +#endif + return false; +} + +bool CFileOperationJob::CFileOperation::OnFileCallback(void* pContext, int ipercent, float avgSpeed) +{ + DataHolder *data = static_cast(pContext); + double current = data->current + ((double)ipercent * data->opWeight * (double)m_time)/ 100.0; + + if (avgSpeed > 1000000.0f) + data->base->m_avgSpeed = StringUtils::Format("%.1f MB/s", avgSpeed / 1000000.0f); + else + data->base->m_avgSpeed = StringUtils::Format("%.1f KB/s", avgSpeed / 1000.0f); + + std::string line; + line = StringUtils::Format("%s (%s)", + data->base->GetCurrentFile().c_str(), + data->base->GetAverageSpeed().c_str()); + data->base->SetText(line); + return !data->base->ShouldCancel((unsigned)current, 100); +} + +bool CFileOperationJob::operator==(const CJob* job) const +{ + if (strcmp(job->GetType(), GetType()) != 0) + return false; + + const CFileOperationJob* rjob = dynamic_cast(job); + if (rjob == NULL) + return false; + + if (GetAction() != rjob->GetAction() || + m_strDestFile != rjob->m_strDestFile || + m_items.Size() != rjob->m_items.Size()) + return false; + + for (int i = 0; i < m_items.Size(); i++) + { + if (m_items[i]->GetPath() != rjob->m_items[i]->GetPath() || + m_items[i]->IsSelected() != rjob->m_items[i]->IsSelected()) + return false; + } + + return true; +} diff --git a/xbmc/utils/FileOperationJob.h b/xbmc/utils/FileOperationJob.h new file mode 100644 index 0000000..de1264e --- /dev/null +++ b/xbmc/utils/FileOperationJob.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "FileItem.h" +#include "filesystem/File.h" +#include "utils/ProgressJob.h" + +#include +#include + +class CFileOperationJob : public CProgressJob +{ +public: + enum FileAction + { + ActionCopy = 1, + ActionMove, + ActionDelete, + ActionReplace, ///< Copy, emptying any existing destination directories first + ActionCreateFolder, + ActionDeleteFolder, + }; + + CFileOperationJob(); + CFileOperationJob(FileAction action, CFileItemList & items, + const std::string& strDestFile, + bool displayProgress = false, + int errorHeading = 0, int errorLine = 0); + + static std::string GetActionString(FileAction action); + + // implementations of CJob + bool DoWork() override; + const char* GetType() const override { return m_displayProgress ? "filemanager" : ""; } + bool operator==(const CJob *job) const override; + + void SetFileOperation(FileAction action, CFileItemList &items, const std::string &strDestFile); + + const std::string &GetAverageSpeed() const { return m_avgSpeed; } + const std::string &GetCurrentOperation() const { return m_currentOperation; } + const std::string &GetCurrentFile() const { return m_currentFile; } + const CFileItemList &GetItems() const { return m_items; } + FileAction GetAction() const { return m_action; } + int GetHeading() const { return m_heading; } + int GetLine() const { return m_line; } + +private: + class CFileOperation : public XFILE::IFileCallback + { + public: + CFileOperation(FileAction action, const std::string &strFileA, const std::string &strFileB, int64_t time); + + bool OnFileCallback(void* pContext, int ipercent, float avgSpeed) override; + + bool ExecuteOperation(CFileOperationJob *base, double ¤t, double opWeight); + + private: + FileAction m_action; + std::string m_strFileA, m_strFileB; + int64_t m_time; + }; + friend class CFileOperation; + + typedef std::vector FileOperationList; + bool DoProcess(FileAction action, CFileItemList & items, const std::string& strDestFile, FileOperationList &fileOperations, double &totalTime); + bool DoProcessFolder(FileAction action, const std::string& strPath, const std::string& strDestFile, FileOperationList &fileOperations, double &totalTime); + bool DoProcessFile(FileAction action, const std::string& strFileA, const std::string& strFileB, FileOperationList &fileOperations, double &totalTime); + + static inline bool CanBeRenamed(const std::string &strFileA, const std::string &strFileB); + + FileAction m_action = ActionCopy; + CFileItemList m_items; + std::string m_strDestFile; + std::string m_avgSpeed, m_currentOperation, m_currentFile; + bool m_displayProgress = false; + int m_heading = 0; + int m_line = 0; +}; diff --git a/xbmc/utils/FileUtils.cpp b/xbmc/utils/FileUtils.cpp new file mode 100644 index 0000000..e51f3d6 --- /dev/null +++ b/xbmc/utils/FileUtils.cpp @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2010-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "FileUtils.h" +#include "ServiceBroker.h" +#include "guilib/GUIKeyboardFactory.h" +#include "utils/log.h" +#include "guilib/LocalizeStrings.h" +#include "JobManager.h" +#include "FileOperationJob.h" +#include "URIUtils.h" +#include "filesystem/MultiPathDirectory.h" +#include "filesystem/SpecialProtocol.h" +#include "filesystem/StackDirectory.h" +#include "settings/MediaSourceSettings.h" +#include "Util.h" +#include "StringUtils.h" +#include "URL.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "storage/MediaManager.h" +#include "utils/Variant.h" + +#if defined(TARGET_WINDOWS) +#include "platform/win32/WIN32Util.h" +#include "utils/CharsetConverter.h" +#endif + +#include + +using namespace XFILE; + +bool CFileUtils::DeleteItem(const std::string &strPath) +{ + CFileItemPtr item(new CFileItem(strPath)); + item->SetPath(strPath); + item->m_bIsFolder = URIUtils::HasSlashAtEnd(strPath); + item->Select(true); + return DeleteItem(item); +} + +bool CFileUtils::DeleteItem(const CFileItemPtr &item) +{ + if (!item || item->IsParentFolder()) + return false; + + // Create a temporary item list containing the file/folder for deletion + CFileItemPtr pItemTemp(new CFileItem(*item)); + pItemTemp->Select(true); + CFileItemList items; + items.Add(pItemTemp); + + // grab the real filemanager window, set up the progress bar, + // and process the delete action + CFileOperationJob op(CFileOperationJob::ActionDelete, items, ""); + + return op.DoWork(); +} + +bool CFileUtils::RenameFile(const std::string &strFile) +{ + std::string strFileAndPath(strFile); + URIUtils::RemoveSlashAtEnd(strFileAndPath); + std::string strFileName = URIUtils::GetFileName(strFileAndPath); + std::string strPath = URIUtils::GetDirectory(strFileAndPath); + if (CGUIKeyboardFactory::ShowAndGetInput(strFileName, CVariant{g_localizeStrings.Get(16013)}, false)) + { + strPath = URIUtils::AddFileToFolder(strPath, strFileName); + CLog::Log(LOGINFO, "FileUtils: rename %s->%s", strFileAndPath.c_str(), strPath.c_str()); + if (URIUtils::IsMultiPath(strFileAndPath)) + { // special case for multipath renames - rename all the paths. + std::vector paths; + CMultiPathDirectory::GetPaths(strFileAndPath, paths); + bool success = false; + for (unsigned int i = 0; i < paths.size(); ++i) + { + std::string filePath(paths[i]); + URIUtils::RemoveSlashAtEnd(filePath); + filePath = URIUtils::GetDirectory(filePath); + filePath = URIUtils::AddFileToFolder(filePath, strFileName); + if (CFile::Rename(paths[i], filePath)) + success = true; + } + return success; + } + return CFile::Rename(strFileAndPath, strPath); + } + return false; +} + +bool CFileUtils::RemoteAccessAllowed(const std::string &strPath) +{ + std::string SourceNames[] = { "programs", "files", "video", "music", "pictures" }; + + std::string realPath = URIUtils::GetRealPath(strPath); + // for rar:// and zip:// paths we need to extract the path to the archive + // instead of using the VFS path + while (URIUtils::IsInArchive(realPath)) + realPath = CURL(realPath).GetHostName(); + + if (StringUtils::StartsWithNoCase(realPath, "virtualpath://upnproot/")) + return true; + else if (StringUtils::StartsWithNoCase(realPath, "musicdb://")) + return true; + else if (StringUtils::StartsWithNoCase(realPath, "videodb://")) + return true; + else if (StringUtils::StartsWithNoCase(realPath, "library://video")) + return true; + else if (StringUtils::StartsWithNoCase(realPath, "library://music")) + return true; + else if (StringUtils::StartsWithNoCase(realPath, "sources://video")) + return true; + else if (StringUtils::StartsWithNoCase(realPath, "special://musicplaylists")) + return true; + else if (StringUtils::StartsWithNoCase(realPath, "special://profile/playlists")) + return true; + else if (StringUtils::StartsWithNoCase(realPath, "special://videoplaylists")) + return true; + else if (StringUtils::StartsWithNoCase(realPath, "special://skin")) + return true; + else if (StringUtils::StartsWithNoCase(realPath, "special://profile/addon_data")) + return true; + else if (StringUtils::StartsWithNoCase(realPath, "addons://sources")) + return true; + else if (StringUtils::StartsWithNoCase(realPath, "upnp://")) + return true; + else if (StringUtils::StartsWithNoCase(realPath, "plugin://")) + return true; + else + { + std::string strPlaylistsPath = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_SYSTEM_PLAYLISTSPATH); + URIUtils::RemoveSlashAtEnd(strPlaylistsPath); + if (StringUtils::StartsWithNoCase(realPath, strPlaylistsPath)) + return true; + } + bool isSource; + // Check manually added sources (held in sources.xml) + for (const std::string& sourceName : SourceNames) + { + VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources(sourceName); + int sourceIndex = CUtil::GetMatchingSource(realPath, *sources, isSource); + if (sourceIndex >= 0 && sourceIndex < static_cast(sources->size()) && + sources->at(sourceIndex).m_iHasLock != LOCK_STATE_LOCKED && + sources->at(sourceIndex).m_allowSharing) + return true; + } + // Check auto-mounted sources + VECSOURCES sources; + CServiceBroker::GetMediaManager().GetRemovableDrives( + sources); // Sources returned allways have m_allowsharing = true + //! @todo Make sharing of auto-mounted sources user configurable + int sourceIndex = CUtil::GetMatchingSource(realPath, sources, isSource); + if (sourceIndex >= 0 && sourceIndex < static_cast(sources.size()) && + sources.at(sourceIndex).m_iHasLock != LOCK_STATE_LOCKED && + sources.at(sourceIndex).m_allowSharing) + return true; + + return false; +} + +CDateTime CFileUtils::GetModificationDate(const std::string& strFileNameAndPath, + const bool& bUseLatestDate) +{ + if (bUseLatestDate) + return GetModificationDate(1, strFileNameAndPath); + else + return GetModificationDate(0, strFileNameAndPath); +} + +CDateTime CFileUtils::GetModificationDate(const int& code, const std::string& strFileNameAndPath) +{ + CDateTime dateAdded; + if (strFileNameAndPath.empty()) + { + CLog::Log(LOGDEBUG, "%s empty strFileNameAndPath variable", __FUNCTION__); + return dateAdded; + } + + try + { + std::string file = strFileNameAndPath; + if (URIUtils::IsStack(strFileNameAndPath)) + file = CStackDirectory::GetFirstStackedFile(strFileNameAndPath); + + if (URIUtils::IsInArchive(file)) + file = CURL(file).GetHostName(); + + // Try to get ctime (creation on Windows, metadata change on Linux) and mtime (modification) + struct __stat64 buffer; + if (CFile::Stat(file, &buffer) == 0 && (buffer.st_mtime != 0 || buffer.st_ctime != 0)) + { + time_t now = time(NULL); + time_t addedTime; + // Prefer the modification time if it's valid, fallback to ctime + if (code == 0) + { + if (buffer.st_mtime != 0 && static_cast(buffer.st_mtime) <= now) + addedTime = static_cast(buffer.st_mtime); + else + addedTime = static_cast(buffer.st_ctime); + } + // Use the later of the ctime and mtime + else if (code == 1) + { + addedTime = + std::max(static_cast(buffer.st_ctime), static_cast(buffer.st_mtime)); + // if the newer of the two dates is in the future, we try it with the older one + if (addedTime > now) + addedTime = + std::min(static_cast(buffer.st_ctime), static_cast(buffer.st_mtime)); + } + // Perfer the earliest of ctime and mtime, fallback to other + else + { + addedTime = + std::min(static_cast(buffer.st_ctime), static_cast(buffer.st_mtime)); + // if the older of the two dates is invalid, we try it with the newer one + if (addedTime == 0) + addedTime = + std::max(static_cast(buffer.st_ctime), static_cast(buffer.st_mtime)); + } + + + // make sure the datetime does is not in the future + if (addedTime <= now) + { + struct tm* time; +#ifdef HAVE_LOCALTIME_R + struct tm result = {}; + time = localtime_r(&addedTime, &result); +#else + time = localtime(&addedTime); +#endif + if (time) + dateAdded = *time; + } + } + } + catch (...) + { + CLog::Log(LOGERROR, "%s unable to extract modification date for file (%s)", __FUNCTION__, + strFileNameAndPath.c_str()); + } + return dateAdded; +} + +bool CFileUtils::CheckFileAccessAllowed(const std::string &filePath) +{ + // DENY access to paths matching + const std::vector blacklist = { + "passwords.xml", + "sources.xml", + "guisettings.xml", + "advancedsettings.xml", + "server.key", + "/.ssh/", + }; + // ALLOW kodi paths + const std::vector whitelist = { + CSpecialProtocol::TranslatePath("special://home"), + CSpecialProtocol::TranslatePath("special://xbmc"), + CSpecialProtocol::TranslatePath("special://musicartistsinfo") + }; + + // image urls come in the form of image://... sometimes with a / appended at the end + // and can be embedded in a music or video file image://music@... + // strip this off to get the real file path + bool isImage = false; + std::string decodePath = CURL::Decode(filePath); + size_t pos = decodePath.find("image://"); + if (pos != std::string::npos) + { + isImage = true; + decodePath.erase(pos, 8); + URIUtils::RemoveSlashAtEnd(decodePath); + if (StringUtils::StartsWith(decodePath, "music@") || StringUtils::StartsWith(decodePath, "video@")) + decodePath.erase(pos, 6); + } + + // check blacklist + for (const auto &b : blacklist) + { + if (decodePath.find(b) != std::string::npos) + { + CLog::Log(LOGERROR,"%s denied access to %s", __FUNCTION__, decodePath.c_str()); + return false; + } + } + +#if defined(TARGET_POSIX) + std::string whiteEntry; + char *fullpath = realpath(decodePath.c_str(), nullptr); + + // if this is a locally existing file, check access permissions + if (fullpath) + { + const std::string realPath = fullpath; + free(fullpath); + + // check whitelist + for (const auto &w : whitelist) + { + char *realtemp = realpath(w.c_str(), nullptr); + if (realtemp) + { + whiteEntry = realtemp; + free(realtemp); + } + if (StringUtils::StartsWith(realPath, whiteEntry)) + return true; + } + // check sources with realPath + return CFileUtils::RemoteAccessAllowed(realPath); + } +#elif defined(TARGET_WINDOWS) + CURL url(decodePath); + if (url.GetProtocol().empty()) + { + std::wstring decodePathW; + g_charsetConverter.utf8ToW(decodePath, decodePathW, false); + CWIN32Util::AddExtraLongPathPrefix(decodePathW); + DWORD bufSize = GetFullPathNameW(decodePathW.c_str(), 0, nullptr, nullptr); + if (bufSize > 0) + { + std::wstring fullpathW; + fullpathW.resize(bufSize); + if (GetFullPathNameW(decodePathW.c_str(), bufSize, const_cast(fullpathW.c_str()), nullptr) <= bufSize - 1) + { + CWIN32Util::RemoveExtraLongPathPrefix(fullpathW); + std::string fullpath; + g_charsetConverter.wToUTF8(fullpathW, fullpath, false); + for (const std::string& whiteEntry : whitelist) + { + if (StringUtils::StartsWith(fullpath, whiteEntry)) + return true; + } + return CFileUtils::RemoteAccessAllowed(fullpath); + } + } + } +#endif + // if it isn't a local file, it must be a vfs entry + if (! isImage) + return CFileUtils::RemoteAccessAllowed(decodePath); + return true; +} diff --git a/xbmc/utils/FileUtils.h b/xbmc/utils/FileUtils.h new file mode 100644 index 0000000..afd1552 --- /dev/null +++ b/xbmc/utils/FileUtils.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "FileItem.h" + +#include + +class CFileUtils +{ +public: + static bool CheckFileAccessAllowed(const std::string &filePath); + static bool DeleteItem(const CFileItemPtr &item); + static bool DeleteItem(const std::string &strPath); + static bool RenameFile(const std::string &strFile); + static bool RemoteAccessAllowed(const std::string &strPath); + static unsigned int LoadFile(const std::string &filename, void* &outputBuffer); + /*! \brief Get the modified date of a file if its invalid it returns the creation date - this behavior changes when you set bUseLatestDate + \param strFileNameAndPath path to the file + \param bUseLatestDate use the newer datetime of the files mtime and ctime + \return Returns the file date, can return a invalid date if problems occur + */ + static CDateTime GetModificationDate(const std::string& strFileNameAndPath, const bool& bUseLatestDate); + static CDateTime GetModificationDate(const int& code, const std::string& strFileNameAndPath); +}; diff --git a/xbmc/utils/GBMBufferObject.cpp b/xbmc/utils/GBMBufferObject.cpp new file mode 100644 index 0000000..88b7575 --- /dev/null +++ b/xbmc/utils/GBMBufferObject.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "GBMBufferObject.h" + +#include "BufferObjectFactory.h" +#include "ServiceBroker.h" +#include "windowing/gbm/WinSystemGbmEGLContext.h" + +#include + +using namespace KODI::WINDOWING::GBM; + +std::unique_ptr CGBMBufferObject::Create() +{ + return std::make_unique(); +} + +void CGBMBufferObject::Register() +{ + CBufferObjectFactory::RegisterBufferObject(CGBMBufferObject::Create); +} + +CGBMBufferObject::CGBMBufferObject() +{ + m_device = static_cast(CServiceBroker::GetWinSystem())->GetGBMDevice(); +} + +CGBMBufferObject::~CGBMBufferObject() +{ + ReleaseMemory(); + DestroyBufferObject(); +} + +bool CGBMBufferObject::CreateBufferObject(uint32_t format, uint32_t width, uint32_t height) +{ + if (m_fd >= 0) + return true; + + m_width = width; + m_height = height; + + m_bo = gbm_bo_create(m_device, m_width, m_height, format, GBM_BO_USE_LINEAR); + + if (!m_bo) + return false; + + m_fd = gbm_bo_get_fd(m_bo); + + return true; +} + +void CGBMBufferObject::DestroyBufferObject() +{ + close(m_fd); + + if (m_bo) + gbm_bo_destroy(m_bo); + + m_bo = nullptr; + m_fd = -1; +} + +uint8_t* CGBMBufferObject::GetMemory() +{ + if (m_bo) + { + m_map = static_cast(gbm_bo_map(m_bo, 0, 0, m_width, m_height, GBM_BO_TRANSFER_WRITE, &m_stride, &m_map_data)); + if (m_map) + return m_map; + } + + return nullptr; +} + +void CGBMBufferObject::ReleaseMemory() +{ + if (m_bo && m_map) + { + gbm_bo_unmap(m_bo, m_map_data); + m_map_data = nullptr; + m_map = nullptr; + } +} + +uint64_t CGBMBufferObject::GetModifier() +{ +#if defined(HAS_GBM_MODIFIERS) + return gbm_bo_get_modifier(m_bo); +#else + return 0; +#endif +} diff --git a/xbmc/utils/GBMBufferObject.h b/xbmc/utils/GBMBufferObject.h new file mode 100644 index 0000000..ae8de58 --- /dev/null +++ b/xbmc/utils/GBMBufferObject.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/BufferObject.h" + +#include +#include + +struct gbm_bo; +struct gbm_device; + +class CGBMBufferObject : public CBufferObject +{ +public: + CGBMBufferObject(); + ~CGBMBufferObject() override; + + // Registration + static std::unique_ptr Create(); + static void Register(); + + // IBufferObject overrides via CBufferObject + bool CreateBufferObject(uint32_t format, uint32_t width, uint32_t height) override; + void DestroyBufferObject() override; + uint8_t* GetMemory() override; + void ReleaseMemory() override; + std::string GetName() const override { return "CGBMBufferObject"; } + + // CBufferObject overrides + uint64_t GetModifier() override; + +private: + gbm_device* m_device{nullptr}; + gbm_bo* m_bo{nullptr}; + + uint32_t m_width{0}; + uint32_t m_height{0}; + + uint8_t* m_map{nullptr}; + void* m_map_data{nullptr}; +}; diff --git a/xbmc/utils/GLUtils.cpp b/xbmc/utils/GLUtils.cpp new file mode 100644 index 0000000..be94eb5 --- /dev/null +++ b/xbmc/utils/GLUtils.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "GLUtils.h" + +#include "ServiceBroker.h" +#include "log.h" +#include "rendering/MatrixGL.h" +#include "rendering/RenderSystem.h" +#include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" +#include "utils/StringUtils.h" + +#include +#include + +namespace +{ + +#define X(VAL) std::make_pair(VAL, #VAL) +std::map glErrors = +{ + // please keep attributes in accordance to: + // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetError.xhtml + X(GL_NO_ERROR), + X(GL_INVALID_ENUM), + X(GL_INVALID_VALUE), + X(GL_INVALID_OPERATION), + X(GL_INVALID_FRAMEBUFFER_OPERATION), + X(GL_OUT_OF_MEMORY), +#if defined(HAS_GL) + X(GL_STACK_UNDERFLOW), + X(GL_STACK_OVERFLOW), +#endif +}; + +std::map glErrorSource = +{ +//! @todo remove TARGET_RASPBERRY_PI when Raspberry Pi updates their GL headers +#if defined(HAS_GLES) && defined(TARGET_LINUX) && !defined(TARGET_RASPBERRY_PI) + X(GL_DEBUG_SOURCE_API_KHR), + X(GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR), + X(GL_DEBUG_SOURCE_SHADER_COMPILER_KHR), + X(GL_DEBUG_SOURCE_THIRD_PARTY_KHR), + X(GL_DEBUG_SOURCE_APPLICATION_KHR), + X(GL_DEBUG_SOURCE_OTHER_KHR), +#endif +}; + +std::map glErrorType = +{ +//! @todo remove TARGET_RASPBERRY_PI when Raspberry Pi updates their GL headers +#if defined(HAS_GLES) && defined(TARGET_LINUX) && !defined(TARGET_RASPBERRY_PI) + X(GL_DEBUG_TYPE_ERROR_KHR), + X(GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR), + X(GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR), + X(GL_DEBUG_TYPE_PORTABILITY_KHR), + X(GL_DEBUG_TYPE_PERFORMANCE_KHR), + X(GL_DEBUG_TYPE_OTHER_KHR), + X(GL_DEBUG_TYPE_MARKER_KHR), +#endif +}; + +std::map glErrorSeverity = +{ +//! @todo remove TARGET_RASPBERRY_PI when Raspberry Pi updates their GL headers +#if defined(HAS_GLES) && defined(TARGET_LINUX) && !defined(TARGET_RASPBERRY_PI) + X(GL_DEBUG_SEVERITY_HIGH_KHR), + X(GL_DEBUG_SEVERITY_MEDIUM_KHR), + X(GL_DEBUG_SEVERITY_LOW_KHR), + X(GL_DEBUG_SEVERITY_NOTIFICATION_KHR), +#endif +}; +#undef X + +} // namespace + +void KODI::UTILS::GL::GlErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) +{ + std::string sourceStr; + std::string typeStr; + std::string severityStr; + + auto glSource = glErrorSource.find(source); + if (glSource != glErrorSource.end()) + { + sourceStr = glSource->second; + } + + auto glType = glErrorType.find(type); + if (glType != glErrorType.end()) + { + typeStr = glType->second; + } + + auto glSeverity = glErrorSeverity.find(severity); + if (glSeverity != glErrorSeverity.end()) + { + severityStr = glSeverity->second; + } + + CLog::Log(LOGDEBUG, "OpenGL(ES) Debugging:\nSource: {}\nType: {}\nSeverity: {}\nID: {}\nMessage: {}", sourceStr, typeStr, severityStr, id, message); +} + +static void PrintMatrix(const GLfloat* matrix, std::string matrixName) +{ + CLog::Log(LOGDEBUG, "{}:\n{:> 10.3f} {:> 10.3f} {:> 10.3f} {:> 10.3f}\n{:> 10.3f} {:> 10.3f} {:> 10.3f} {:> 10.3f}\n{:> 10.3f} {:> 10.3f} {:> 10.3f} {:> 10.3f}\n{:> 10.3f} {:> 10.3f} {:> 10.3f} {:> 10.3f}", + matrixName, + matrix[0], matrix[1], matrix[2], matrix[3], + matrix[4], matrix[5], matrix[6], matrix[7], + matrix[8], matrix[9], matrix[10], matrix[11], + matrix[12], matrix[13], matrix[14], matrix[15]); +} + +void _VerifyGLState(const char* szfile, const char* szfunction, int lineno) +{ + GLenum err = glGetError(); + if (err == GL_NO_ERROR) + { + return; + } + + auto error = glErrors.find(err); + if (error != glErrors.end()) + { + CLog::Log(LOGERROR, "GL(ES) ERROR: {}", error->second); + } + + if (szfile && szfunction) + { + CLog::Log(LOGERROR, "In file: {} function: {} line: {}", szfile, szfunction, lineno); + } + + GLboolean scissors; + glGetBooleanv(GL_SCISSOR_TEST, &scissors); + CLog::Log(LOGDEBUG, "Scissor test enabled: {}", scissors == GL_TRUE ? "True" : "False"); + + GLfloat matrix[16]; + glGetFloatv(GL_SCISSOR_BOX, matrix); + CLog::Log(LOGDEBUG, "Scissor box: {}, {}, {}, {}", matrix[0], matrix[1], matrix[2], matrix[3]); + + glGetFloatv(GL_VIEWPORT, matrix); + CLog::Log(LOGDEBUG, "Viewport: {}, {}, {}, {}", matrix[0], matrix[1], matrix[2], matrix[3]); + + PrintMatrix(glMatrixProject.Get(), "Projection Matrix"); + PrintMatrix(glMatrixModview.Get(), "Modelview Matrix"); +} + +void LogGraphicsInfo() +{ +#if defined(HAS_GL) || defined(HAS_GLES) + const GLubyte *s; + + s = glGetString(GL_VENDOR); + if (s) + CLog::Log(LOGINFO, "GL_VENDOR = %s", s); + else + CLog::Log(LOGINFO, "GL_VENDOR = NULL"); + + s = glGetString(GL_RENDERER); + if (s) + CLog::Log(LOGINFO, "GL_RENDERER = %s", s); + else + CLog::Log(LOGINFO, "GL_RENDERER = NULL"); + + s = glGetString(GL_VERSION); + if (s) + CLog::Log(LOGINFO, "GL_VERSION = %s", s); + else + CLog::Log(LOGINFO, "GL_VERSION = NULL"); + + s = glGetString(GL_SHADING_LANGUAGE_VERSION); + if (s) + CLog::Log(LOGINFO, "GL_SHADING_LANGUAGE_VERSION = %s", s); + else + CLog::Log(LOGINFO, "GL_SHADING_LANGUAGE_VERSION = NULL"); + + //GL_NVX_gpu_memory_info extension +#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047 +#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048 +#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049 +#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A +#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B + + if (CServiceBroker::GetRenderSystem()->IsExtSupported("GL_NVX_gpu_memory_info")) + { + GLint mem = 0; + + glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &mem); + CLog::Log(LOGINFO, "GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX = %i", mem); + + //this seems to be the amount of ram on the videocard + glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &mem); + CLog::Log(LOGINFO, "GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX = %i", mem); + } + + std::string extensions; +#if defined(HAS_GL) + unsigned int renderVersionMajor, renderVersionMinor; + CServiceBroker::GetRenderSystem()->GetRenderVersion(renderVersionMajor, renderVersionMinor); + if (renderVersionMajor > 3 || + (renderVersionMajor == 3 && renderVersionMinor >= 2)) + { + GLint n; + glGetIntegerv(GL_NUM_EXTENSIONS, &n); + if (n > 0) + { + GLint i; + for (i = 0; i < n; i++) + { + extensions += (const char*)glGetStringi(GL_EXTENSIONS, i); + extensions += " "; + } + } + } + else +#endif + { + extensions += (const char*) glGetString(GL_EXTENSIONS); + } + + if (!extensions.empty()) + CLog::Log(LOGINFO, "GL_EXTENSIONS = %s", extensions.c_str()); + else + CLog::Log(LOGINFO, "GL_EXTENSIONS = NULL"); + + +#else /* !HAS_GL */ + CLog::Log(LOGINFO, "Please define LogGraphicsInfo for your chosen graphics library"); +#endif /* !HAS_GL */ +} + +int glFormatElementByteCount(GLenum format) +{ + switch (format) + { +#ifdef HAS_GL + case GL_BGRA: + return 4; + case GL_RED: + return 1; + case GL_GREEN: + return 1; + case GL_RG: + return 2; + case GL_BGR: + return 3; +#endif + case GL_RGBA: + return 4; + case GL_RGB: + return 3; + case GL_LUMINANCE_ALPHA: + return 2; + case GL_LUMINANCE: + case GL_ALPHA: + return 1; + default: + CLog::Log(LOGERROR, "glFormatElementByteCount - Unknown format %u", format); + return 1; + } +} diff --git a/xbmc/utils/GLUtils.h b/xbmc/utils/GLUtils.h new file mode 100644 index 0000000..2dea067 --- /dev/null +++ b/xbmc/utils/GLUtils.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +// GL Error checking macro +// this function is useful for tracking down GL errors, which otherwise +// just result in undefined behavior and can be difficult to track down. +// +// Just call it 'VerifyGLState()' after a sequence of GL calls +// +// if GL_DEBUGGING and HAS_GL are defined, the function checks +// for GL errors and prints the current state of the various matrices; +// if not it's just an empty inline stub, and thus won't affect performance +// and will be optimized out. + +#include "system_gl.h" + +namespace KODI +{ +namespace UTILS +{ +namespace GL +{ + +void GlErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam); + +} +} +} + +void _VerifyGLState(const char* szfile, const char* szfunction, int lineno); +#if defined(GL_DEBUGGING) && (defined(HAS_GL) || defined(HAS_GLES)) +#define VerifyGLState() _VerifyGLState(__FILE__, __FUNCTION__, __LINE__) +#else +#define VerifyGLState() +#endif + +void LogGraphicsInfo(); + +int glFormatElementByteCount(GLenum format); diff --git a/xbmc/utils/Geometry.h b/xbmc/utils/Geometry.h new file mode 100644 index 0000000..878905b --- /dev/null +++ b/xbmc/utils/Geometry.h @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifdef __GNUC__ +// under gcc, inline will only take place if optimizations are applied (-O). this will force inline even with optimizations. +#define XBMC_FORCE_INLINE __attribute__((always_inline)) +#else +#define XBMC_FORCE_INLINE +#endif + +#include +#include +#include + +template class CPointGen +{ +public: + typedef CPointGen this_type; + + CPointGen() noexcept = default; + + constexpr CPointGen(T a, T b) + : x{a}, y{b} + {} + + template explicit constexpr CPointGen(const CPointGen& rhs) + : x{static_cast (rhs.x)}, y{static_cast (rhs.y)} + {} + + constexpr this_type operator+(const this_type &point) const + { + return {x + point.x, y + point.y}; + }; + + this_type& operator+=(const this_type &point) + { + x += point.x; + y += point.y; + return *this; + }; + + constexpr this_type operator-(const this_type &point) const + { + return {x - point.x, y - point.y}; + }; + + this_type& operator-=(const this_type &point) + { + x -= point.x; + y -= point.y; + return *this; + }; + + constexpr this_type operator*(T factor) const + { + return {x * factor, y * factor}; + } + + this_type& operator*=(T factor) + { + x *= factor; + y *= factor; + return *this; + } + + constexpr this_type operator/(T factor) const + { + return {x / factor, y / factor}; + } + + this_type& operator/=(T factor) + { + x /= factor; + y /= factor; + return *this; + } + + T x{}, y{}; +}; + +template +constexpr bool operator==(const CPointGen &point1, const CPointGen &point2) noexcept +{ + return (point1.x == point2.x && point1.y == point2.y); +} + +template +constexpr bool operator!=(const CPointGen &point1, const CPointGen &point2) noexcept +{ + return !(point1 == point2); +} + +using CPoint = CPointGen; +using CPointInt = CPointGen; + + +/** + * Generic two-dimensional size representation + * + * Class invariant: width and height are both non-negative + * Throws std::out_of_range if invariant would be violated. The class + * is exception-safe. If modification would violate the invariant, the size + * is not changed. + */ +template class CSizeGen +{ + T m_w{}, m_h{}; + + void CheckSet(T width, T height) + { + if (width < 0) + { + throw std::out_of_range("Size may not have negative width"); + } + if (height < 0) + { + throw std::out_of_range("Size may not have negative height"); + } + m_w = width; + m_h = height; + } + +public: + typedef CSizeGen this_type; + + CSizeGen() noexcept = default; + + CSizeGen(T width, T height) + { + CheckSet(width, height); + } + + T Width() const + { + return m_w; + } + + T Height() const + { + return m_h; + } + + void SetWidth(T width) + { + CheckSet(width, m_h); + } + + void SetHeight(T height) + { + CheckSet(m_w, height); + } + + void Set(T width, T height) + { + CheckSet(width, height); + } + + bool IsZero() const + { + return (m_w == static_cast (0) && m_h == static_cast (0)); + } + + T Area() const + { + return m_w * m_h; + } + + CPointGen ToPoint() const + { + return {m_w, m_h}; + } + + template explicit CSizeGen(const CSizeGen& rhs) + { + CheckSet(static_cast (rhs.m_w), static_cast (rhs.m_h)); + } + + this_type operator+(const this_type& size) const + { + return {m_w + size.m_w, m_h + size.m_h}; + }; + + this_type& operator+=(const this_type& size) + { + CheckSet(m_w + size.m_w, m_h + size.m_h); + return *this; + }; + + this_type operator-(const this_type& size) const + { + return {m_w - size.m_w, m_h - size.m_h}; + }; + + this_type& operator-=(const this_type& size) + { + CheckSet(m_w - size.m_w, m_h - size.m_h); + return *this; + }; + + this_type operator*(T factor) const + { + return {m_w * factor, m_h * factor}; + } + + this_type& operator*=(T factor) + { + CheckSet(m_w * factor, m_h * factor); + return *this; + } + + this_type operator/(T factor) const + { + return {m_w / factor, m_h / factor}; + } + + this_type& operator/=(T factor) + { + CheckSet(m_w / factor, m_h / factor); + return *this; + } +}; + +template +inline bool operator==(const CSizeGen& size1, const CSizeGen& size2) noexcept +{ + return (size1.Width() == size2.Width() && size1.Height() == size2.Height()); +} + +template +inline bool operator!=(const CSizeGen& size1, const CSizeGen& size2) noexcept +{ + return !(size1 == size2); +} + +using CSize = CSizeGen; +using CSizeInt = CSizeGen; + + +template class CRectGen +{ +public: + typedef CRectGen this_type; + typedef CPointGen point_type; + typedef CSizeGen size_type; + + CRectGen() noexcept = default; + + constexpr CRectGen(T left, T top, T right, T bottom) + : x1{left}, y1{top}, x2{right}, y2{bottom} + {} + + constexpr CRectGen(const point_type &p1, const point_type &p2) + : x1{p1.x}, y1{p1.y}, x2{p2.x}, y2{p2.y} + {} + + constexpr CRectGen(const point_type &origin, const size_type &size) + : x1{origin.x}, y1{origin.y}, x2{x1 + size.Width()}, y2{y1 + size.Height()} + {} + + template explicit constexpr CRectGen(const CRectGen& rhs) + : x1{static_cast (rhs.x1)}, y1{static_cast (rhs.y1)}, x2{static_cast (rhs.x2)}, y2{static_cast (rhs.y2)} + {} + + void SetRect(T left, T top, T right, T bottom) + { + x1 = left; + y1 = top; + x2 = right; + y2 = bottom; + } + + constexpr bool PtInRect(const point_type &point) const + { + return (x1 <= point.x && point.x <= x2 && y1 <= point.y && point.y <= y2); + }; + + this_type& operator-=(const point_type &point) XBMC_FORCE_INLINE + { + x1 -= point.x; + y1 -= point.y; + x2 -= point.x; + y2 -= point.y; + return *this; + }; + + constexpr this_type operator-(const point_type &point) const + { + return {x1 - point.x, y1 - point.y, x2 - point.x, y2 - point.y}; + } + + this_type& operator+=(const point_type &point) XBMC_FORCE_INLINE + { + x1 += point.x; + y1 += point.y; + x2 += point.x; + y2 += point.y; + return *this; + }; + + constexpr this_type operator+(const point_type &point) const + { + return {x1 + point.x, y1 + point.y, x2 + point.x, y2 + point.y}; + } + + this_type& operator-=(const size_type &size) + { + x2 -= size.Width(); + y2 -= size.Height(); + return *this; + }; + + constexpr this_type operator-(const size_type &size) const + { + return {x1, y1, x2 - size.Width(), y2 - size.Height()}; + } + + this_type& operator+=(const size_type &size) + { + x2 += size.Width(); + y2 += size.Height(); + return *this; + }; + + constexpr this_type operator+(const size_type &size) const + { + return {x1, y1, x2 + size.Width(), y2 + size.Height()}; + } + + this_type& Intersect(const this_type &rect) + { + x1 = clamp_range(x1, rect.x1, rect.x2); + x2 = clamp_range(x2, rect.x1, rect.x2); + y1 = clamp_range(y1, rect.y1, rect.y2); + y2 = clamp_range(y2, rect.y1, rect.y2); + return *this; + }; + + this_type& Union(const this_type &rect) + { + if (IsEmpty()) + *this = rect; + else if (!rect.IsEmpty()) + { + x1 = std::min(x1,rect.x1); + y1 = std::min(y1,rect.y1); + + x2 = std::max(x2,rect.x2); + y2 = std::max(y2,rect.y2); + } + + return *this; + }; + + constexpr bool IsEmpty() const XBMC_FORCE_INLINE + { + return (x2 - x1) * (y2 - y1) == 0; + }; + + constexpr point_type P1() const XBMC_FORCE_INLINE + { + return {x1, y1}; + } + + constexpr point_type P2() const XBMC_FORCE_INLINE + { + return {x2, y2}; + } + + constexpr T Width() const XBMC_FORCE_INLINE + { + return x2 - x1; + }; + + constexpr T Height() const XBMC_FORCE_INLINE + { + return y2 - y1; + }; + + constexpr T Area() const XBMC_FORCE_INLINE + { + return Width() * Height(); + }; + + size_type ToSize() const + { + return {Width(), Height()}; + }; + + std::vector SubtractRect(this_type splitterRect) + { + std::vector newRectanglesList; + this_type intersection = splitterRect.Intersect(*this); + + if (!intersection.IsEmpty()) + { + this_type add; + + // add rect above intersection if not empty + add = this_type(x1, y1, x2, intersection.y1); + if (!add.IsEmpty()) + newRectanglesList.push_back(add); + + // add rect below intersection if not empty + add = this_type(x1, intersection.y2, x2, y2); + if (!add.IsEmpty()) + newRectanglesList.push_back(add); + + // add rect left intersection if not empty + add = this_type(x1, intersection.y1, intersection.x1, intersection.y2); + if (!add.IsEmpty()) + newRectanglesList.push_back(add); + + // add rect right intersection if not empty + add = this_type(intersection.x2, intersection.y1, x2, intersection.y2); + if (!add.IsEmpty()) + newRectanglesList.push_back(add); + } + else + { + newRectanglesList.push_back(*this); + } + + return newRectanglesList; + } + + std::vector SubtractRects(std::vector intersectionList) + { + std::vector fragmentsList; + fragmentsList.push_back(*this); + + for (typename std::vector::iterator splitter = intersectionList.begin(); splitter != intersectionList.end(); ++splitter) + { + typename std::vector toAddList; + + for (typename std::vector::iterator fragment = fragmentsList.begin(); fragment != fragmentsList.end(); ++fragment) + { + std::vector newFragmentsList = fragment->SubtractRect(*splitter); + toAddList.insert(toAddList.end(), newFragmentsList.begin(), newFragmentsList.end()); + } + + fragmentsList.clear(); + fragmentsList.insert(fragmentsList.end(), toAddList.begin(), toAddList.end()); + } + + return fragmentsList; + } + + void GetQuad(point_type (&points)[4]) + { + points[0] = { x1, y1 }; + points[1] = { x2, y1 }; + points[2] = { x2, y2 }; + points[3] = { x1, y2 }; + } + + T x1{}, y1{}, x2{}, y2{}; +private: + static constexpr T clamp_range(T x, T l, T h) XBMC_FORCE_INLINE + { + return (x > h) ? h : ((x < l) ? l : x); + } +}; + +template +constexpr bool operator==(const CRectGen &rect1, const CRectGen &rect2) noexcept +{ + return (rect1.x1 == rect2.x1 && rect1.y1 == rect2.y1 && rect1.x2 == rect2.x2 && rect1.y2 == rect2.y2); +} + +template +constexpr bool operator!=(const CRectGen &rect1, const CRectGen &rect2) noexcept +{ + return !(rect1 == rect2); +} + +using CRect = CRectGen; +using CRectInt = CRectGen; diff --git a/xbmc/utils/GlobalsHandling.h b/xbmc/utils/GlobalsHandling.h new file mode 100644 index 0000000..a51cc08 --- /dev/null +++ b/xbmc/utils/GlobalsHandling.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +/** + * This file contains the pattern for moving "globals" from the BSS Segment to the heap. + * A note on usage of this pattern for globals replacement: + * + * This pattern uses a singleton pattern and some compiler/C preprocessor sugar to allow + * "global" variables to be lazy instantiated and initialized and moved from the BSS segment + * to the heap (that is, they are instantiated on the heap when they are first used rather + * than relying on the startup code to initialize the BSS segment). This eliminates the + * problem associated with global variable dependencies across compilation units. + * + * Reference counting from the BSS segment is used to destruct these globals at the time the + * last compilation unit that knows about it is finalized by the post-main shutdown. The book + * keeping is done by smuggling a smart pointer into every file that references a particular + * "global class" through the use of a 'static' declaration of an instance of that smart + * pointer in the header file of the global class (did you ever think you'd see a file scope + * 'static' variable in a header file - on purpose?) + * + * There are two different ways to use this pattern when replacing global variables. + * The selection of which one to use depends on whether or not there is a possibility + * that the code in the .cpp file for the global can be executed from a static method + * somewhere. This may take some explanation. + * + * The (at least) two ways to do this: + * + * 1) You can use the reference object std::shared_ptr to access the global variable. + * + * This would be the preferred means since it is (very slightly) more efficient than + * the alternative. To use this pattern you replace standard static references to + * the global with access through the reference. If you use the C preprocessor to + * do this for you can put the following code in the header file where the global's + * class is declared: + * + * static std::shared_ptr g_globalVariableRef(xbmcutil::GlobalsSingleton::getInstance()); + * #define g_globalVariable (*(g_globalVariableRef.get())) + * + * Note what this does. In every file that includes this header there will be a *static* + * instance of the std::shared_ptr smart pointer. This effectively + * reference counts the singleton from every compilation unit (ie, object code file that + * results from a compilation of a .c/.cpp file) that references this global directly. + * + * There is a problem with this, however. Keep in mind that the instance of the smart pointer + * (being in the BSS segment of the compilation unit) is ITSELF an object that depends on + * the BSS segment initialization in order to be initialized with an instance from the + * singleton. That means, depending on the code structure, it is possible to get into a + * circumstance where the above #define could be exercised PRIOR TO the setting of the + * value of the smart pointer. + * + * Some reflection on this should lead you to the conclusion that the only way for this to + * happen is if access to this global can take place through a static/global method, directly + * or indirectly (ie, the static/global method can call another method that uses the + * reference), where that static is called from initialization code exercised prior to + * the start of 'main.' + * + * Because of the "indirectly" in the above statement, this situation can be difficult to + * determine beforehand. + * + * 2) Alternatively, when you KNOW that the global variable can suffer from the above described + * problem, you can restrict all access to the variable to the singleton by changing + * the #define to: + * + * #define g_globalVariable (*(xbmcutil::Singleton::getInstance())) + * + * A few things to note about this. First, this separates the reference counting aspect + * from the access aspect of this solution. The smart pointers are no longer used for + * access, only for reference counting. Secondly, all access is through the singleton directly + * so there is no reliance on the state of the BSS segment for the code to operate + * correctly. + * + * This solution is required for g_Windowing because it's accessed (both directly and + * indirectly) from the static methods of CLog which are called repeatedly from + * code exercised during the initialization of the BSS segment. + */ + +namespace xbmcutil +{ + /** + * This class is an implementation detail of the macros defined below and + * is NOT meant to be used as a general purpose utility. IOW, DO NOT USE THIS + * CLASS to support a general singleton design pattern, it's specialized + * for solving the initialization/finalization order/dependency problem + * with global variables and should only be used via the macros below. + * + * Currently THIS IS NOT THREAD SAFE! Why not just add a lock you ask? + * Because this singleton is used to initialize global variables and + * there is an issue with having the lock used prior to its + * initialization. No matter what, if this class is used as a replacement + * for global variables there's going to be a race condition if it's used + * anywhere else. So currently this is the only prescribed use. + * + * Therefore this hack depends on the fact that compilation unit global/static + * initialization is done in a single thread. + */ + template class GlobalsSingleton + { + /** + * This thing just deletes the shared_ptr when the 'instance' + * goes out of scope (when the bss segment of the compilation unit + * that 'instance' is sitting in is deinitialized). See the comment + * on 'instance' for more information. + */ + template class Deleter + { + public: + K* guarded; + ~Deleter() { if (guarded) delete guarded; } + }; + + /** + * Is it possible that getInstance can be called prior to the shared_ptr 'instance' + * being initialized as a global? If so, then the shared_ptr constructor would + * effectively 'reset' the shared pointer after it had been set by the prior + * getInstance call, and a second instance would be created. We really don't + * want this to happen so 'instance' is a pointer to a smart pointer so that + * we can deterministically handle its construction. It is guarded by the + * Deleter class above so that when the bss segment that this static is + * sitting in is deinitialized, the shared_ptr pointer will be cleaned up. + */ + static Deleter > instance; + + /** + * See 'getQuick' below. + */ + static T* quick; + public: + + /** + * Retrieve an instance of the singleton using a shared pointer for + * reference counting. + */ + inline static std::shared_ptr getInstance() + { + if (!instance.guarded) + { + if (!quick) + quick = new T; + instance.guarded = new std::shared_ptr(quick); + } + return *(instance.guarded); + } + + /** + * This is for quick access when using form (2) of the pattern. Before 'mdd' points + * it out, this might be a case of 'solving problems we don't have' but this access + * is used frequently within the event loop so any help here should benefit the + * overall performance and there is nothing complicated or tricky here and not + * a lot of code to maintain. + */ + inline static T* getQuick() + { + if (!quick) + quick = new T; + + return quick; + } + + }; + + template typename GlobalsSingleton::template Deleter > GlobalsSingleton::instance; + template T* GlobalsSingleton::quick; + + /** + * This is another bit of hackery that will act as a flag for + * whether or not a global/static has been initialized yet. An instance + * should be placed in the cpp file after the static/global it's meant to + * monitor. + */ + class InitFlag { public: explicit InitFlag(bool& flag) { flag = true; } }; +} + +/** + * For pattern (2) above, you can use the following macro. This pattern is safe to + * use in all cases but may be very slightly less efficient. + * + * Also, you must also use a #define to replace the actual global variable since + * there's no way to use a macro to add a #define. An example would be: + * + * XBMC_GLOBAL_REF(CWinSystemWin32DX, g_Windowing); + * #define g_Windowing XBMC_GLOBAL_USE(CWinSystemWin32DX) + * + */ +#define XBMC_GLOBAL_REF(classname,g_variable) \ + static std::shared_ptr g_variable##Ref(xbmcutil::GlobalsSingleton::getInstance()) + +/** + * This declares the actual use of the variable. It needs to be used in another #define + * of the form: + * + * #define g_variable XBMC_GLOBAL_USE(classname) + */ +#define XBMC_GLOBAL_USE(classname) (*(xbmcutil::GlobalsSingleton::getQuick())) diff --git a/xbmc/utils/GroupUtils.cpp b/xbmc/utils/GroupUtils.cpp new file mode 100644 index 0000000..340c11a --- /dev/null +++ b/xbmc/utils/GroupUtils.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "GroupUtils.h" + +#include "FileItem.h" +#include "filesystem/MultiPathDirectory.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "video/VideoDbUrl.h" +#include "video/VideoInfoTag.h" + +#include +#include + +using SetMap = std::map >; + +bool GroupUtils::Group(GroupBy groupBy, const std::string &baseDir, const CFileItemList &items, CFileItemList &groupedItems, GroupAttribute groupAttributes /* = GroupAttributeNone */) +{ + CFileItemList ungroupedItems; + return Group(groupBy, baseDir, items, groupedItems, ungroupedItems, groupAttributes); +} + +bool GroupUtils::Group(GroupBy groupBy, const std::string &baseDir, const CFileItemList &items, CFileItemList &groupedItems, CFileItemList &ungroupedItems, GroupAttribute groupAttributes /* = GroupAttributeNone */) +{ + if (groupBy == GroupByNone) + return false; + + // nothing to do if there are no items to group + if (items.Size() <= 0) + return true; + + SetMap setMap; + for (int index = 0; index < items.Size(); index++) + { + bool ungrouped = true; + const CFileItemPtr item = items.Get(index); + + // group by sets + if ((groupBy & GroupBySet) && + item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_set.id > 0) + { + ungrouped = false; + setMap[item->GetVideoInfoTag()->m_set.id].insert(item); + } + + if (ungrouped) + ungroupedItems.Add(item); + } + + if ((groupBy & GroupBySet) && !setMap.empty()) + { + CVideoDbUrl itemsUrl; + if (!itemsUrl.FromString(baseDir)) + return false; + + for (SetMap::const_iterator set = setMap.begin(); set != setMap.end(); ++set) + { + // only one item in the set, so add it to the ungrouped items + if (set->second.size() == 1 && (groupAttributes & GroupAttributeIgnoreSingleItems)) + { + ungroupedItems.Add(*set->second.begin()); + continue; + } + + CFileItemPtr pItem(new CFileItem((*set->second.begin())->GetVideoInfoTag()->m_set.title)); + pItem->GetVideoInfoTag()->m_iDbId = set->first; + pItem->GetVideoInfoTag()->m_type = MediaTypeVideoCollection; + + std::string basePath = StringUtils::Format("videodb://movies/sets/%i/", set->first); + CVideoDbUrl videoUrl; + if (!videoUrl.FromString(basePath)) + pItem->SetPath(basePath); + else + { + videoUrl.AddOptions((*set->second.begin())->GetURL().GetOptions()); + pItem->SetPath(videoUrl.ToString()); + } + pItem->m_bIsFolder = true; + + CVideoInfoTag* setInfo = pItem->GetVideoInfoTag(); + setInfo->m_strPath = pItem->GetPath(); + setInfo->m_strTitle = pItem->GetLabel(); + setInfo->m_strPlot = (*set->second.begin())->GetVideoInfoTag()->m_set.overview; + + int ratings = 0; + float totalRatings = 0; + int iWatched = 0; // have all the movies been played at least once? + std::set pathSet; + for (std::set::const_iterator movie = set->second.begin(); movie != set->second.end(); ++movie) + { + CVideoInfoTag* movieInfo = (*movie)->GetVideoInfoTag(); + // handle rating + if (movieInfo->GetRating().rating > 0.0f) + { + ratings++; + totalRatings += movieInfo->GetRating().rating; + } + + // handle year + if (movieInfo->GetYear() > setInfo->GetYear()) + setInfo->SetYear(movieInfo->GetYear()); + + // handle lastplayed + if (movieInfo->m_lastPlayed.IsValid() && movieInfo->m_lastPlayed > setInfo->m_lastPlayed) + setInfo->m_lastPlayed = movieInfo->m_lastPlayed; + + // handle dateadded + if (movieInfo->m_dateAdded.IsValid() && movieInfo->m_dateAdded > setInfo->m_dateAdded) + setInfo->m_dateAdded = movieInfo->m_dateAdded; + + // handle playcount/watched + setInfo->SetPlayCount(setInfo->GetPlayCount() + movieInfo->GetPlayCount()); + if (movieInfo->GetPlayCount() > 0) + iWatched++; + + //accumulate the path for a multipath construction + CFileItem video(movieInfo->m_basePath, false); + if (video.IsVideo()) + pathSet.insert(URIUtils::GetParentPath(movieInfo->m_basePath)); + else + pathSet.insert(movieInfo->m_basePath); + } + setInfo->m_basePath = XFILE::CMultiPathDirectory::ConstructMultiPath(pathSet); + + if (ratings > 1) + pItem->GetVideoInfoTag()->SetRating(totalRatings / ratings); + + setInfo->SetPlayCount(iWatched >= static_cast(set->second.size()) ? (setInfo->GetPlayCount() / set->second.size()) : 0); + pItem->SetProperty("total", (int)set->second.size()); + pItem->SetProperty("watched", iWatched); + pItem->SetProperty("unwatched", (int)set->second.size() - iWatched); + pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, setInfo->GetPlayCount() > 0); + + groupedItems.Add(pItem); + } + } + + return true; +} + +bool GroupUtils::GroupAndMix(GroupBy groupBy, const std::string &baseDir, const CFileItemList &items, CFileItemList &groupedItemsMixed, GroupAttribute groupAttributes /* = GroupAttributeNone */) +{ + CFileItemList ungroupedItems; + if (!Group(groupBy, baseDir, items, groupedItemsMixed, ungroupedItems, groupAttributes)) + return false; + + // add all the ungrouped items as well + groupedItemsMixed.Append(ungroupedItems); + + return true; +} diff --git a/xbmc/utils/GroupUtils.h b/xbmc/utils/GroupUtils.h new file mode 100644 index 0000000..2ea7083 --- /dev/null +++ b/xbmc/utils/GroupUtils.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +class CFileItemList; + +// can be used as a flag +typedef enum { + GroupByNone = 0x0, + GroupBySet = 0x1 +} GroupBy; + +typedef enum { + GroupAttributeNone = 0x0, + GroupAttributeIgnoreSingleItems = 0x1 +} GroupAttribute; + +class GroupUtils +{ +public: + static bool Group(GroupBy groupBy, const std::string &baseDir, const CFileItemList &items, CFileItemList &groupedItems, GroupAttribute groupAttributes = GroupAttributeNone); + static bool Group(GroupBy groupBy, const std::string &baseDir, const CFileItemList &items, CFileItemList &groupedItems, CFileItemList &ungroupedItems, GroupAttribute groupAttributes = GroupAttributeNone); + static bool GroupAndMix(GroupBy groupBy, const std::string &baseDir, const CFileItemList &items, CFileItemList &groupedItemsMixed, GroupAttribute groupAttributes = GroupAttributeNone); +}; diff --git a/xbmc/utils/HTMLUtil.cpp b/xbmc/utils/HTMLUtil.cpp new file mode 100644 index 0000000..dbe1843 --- /dev/null +++ b/xbmc/utils/HTMLUtil.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "HTMLUtil.h" + +#include "utils/StringUtils.h" + +#include + +using namespace HTML; + +CHTMLUtil::CHTMLUtil(void) = default; + +CHTMLUtil::~CHTMLUtil(void) = default; + +void CHTMLUtil::RemoveTags(std::string& strHTML) +{ + int iNested = 0; + std::string strReturn = ""; + for (int i = 0; i < (int) strHTML.size(); ++i) + { + if (strHTML[i] == '<') iNested++; + else if (strHTML[i] == '>') iNested--; + else + { + if (!iNested) + { + strReturn += strHTML[i]; + } + } + } + + strHTML = strReturn; +} + +typedef struct +{ + const wchar_t* html; + const wchar_t w; +} HTMLMapping; + +static const HTMLMapping mappings[] = + {{L"&", 0x0026}, + {L"'", 0x0027}, + {L"´", 0x00B4}, + {L"à", 0x00E0}, + {L"á", 0x00E1}, + {L"â", 0x00E2}, + {L"ã", 0x00E3}, + {L"ä", 0x00E4}, + {L"å", 0x00E5}, + {L"æ", 0x00E6}, + {L"À", 0x00C0}, + {L"Á", 0x00C1}, + {L"Â", 0x00C2}, + {L"Ã", 0x00C3}, + {L"Ä", 0x00C4}, + {L"Å", 0x00C5}, + {L"Æ", 0x00C6}, + {L"„", 0x201E}, + {L"¦", 0x00A6}, + {L"•", 0x2022}, + {L"•", 0x2022}, + {L"¢", 0x00A2}, + {L"ˆ", 0x02C6}, + {L"¤", 0x00A4}, + {L"©", 0x00A9}, + {L"¸", 0x00B8}, + {L"Ç", 0x00C7}, + {L"ç", 0x00E7}, + {L"†", 0x2020}, + {L"°", 0x00B0}, + {L"÷", 0x00F7}, + {L"‡", 0x2021}, + {L"è", 0x00E8}, + {L"é", 0x00E9}, + {L"ê", 0x00EA}, + {L" ", 0x2003}, + {L" ", 0x2002}, + {L"ë", 0x00EB}, + {L"ð", 0x00F0}, + {L"€", 0x20AC}, + {L"È", 0x00C8}, + {L"É", 0x00C9}, + {L"Ê", 0x00CA}, + {L"Ë", 0x00CB}, + {L"Ð", 0x00D0}, + {L""", 0x0022}, + {L"⁄", 0x2044}, + {L"¼", 0x00BC}, + {L"½", 0x00BD}, + {L"¾", 0x00BE}, + {L">", 0x003E}, + {L"…", 0x2026}, + {L"¡", 0x00A1}, + {L"¿", 0x00BF}, + {L"ì", 0x00EC}, + {L"í", 0x00ED}, + {L"î", 0x00EE}, + {L"ï", 0x00EF}, + {L"Ì", 0x00CC}, + {L"Í", 0x00CD}, + {L"Î", 0x00CE}, + {L"Ï", 0x00CF}, + {L"‎", 0x200E}, + {L"<", 0x003C}, + {L"«", 0x00AB}, + {L"“", 0x201C}, + {L"‹", 0x2039}, + {L"‘", 0x2018}, + {L"¯", 0x00AF}, + {L"µ", 0x00B5}, + {L"·", 0x00B7}, + {L"—", 0x2014}, + {L" ", 0x00A0}, + {L"–", 0x2013}, + {L"ñ", 0x00F1}, + {L"¬", 0x00AC}, + {L"Ñ", 0x00D1}, + {L"ª", 0x00AA}, + {L"º", 0x00BA}, + {L"œ", 0x0153}, + {L"ò", 0x00F2}, + {L"ó", 0x00F3}, + {L"ô", 0x00F4}, + {L"õ", 0x00F5}, + {L"ö", 0x00F6}, + {L"ø", 0x00F8}, + {L"Œ", 0x0152}, + {L"Ò", 0x00D2}, + {L"Ó", 0x00D3}, + {L"Ô", 0x00D4}, + {L"Õ", 0x00D5}, + {L"Ö", 0x00D6}, + {L"Ø", 0x00D8}, + {L"¶", 0x00B6}, + {L"‰", 0x2030}, + {L"±", 0x00B1}, + {L"£", 0x00A3}, + {L"»", 0x00BB}, + {L"”", 0x201D}, + {L"®", 0x00AE}, + {L"‏", 0x200F}, + {L"›", 0x203A}, + {L"’", 0x2019}, + {L"‚", 0x201A}, + {L"š", 0x0161}, + {L"§", 0x00A7}, + {L"­", 0x00AD}, + {L"¹", 0x00B9}, + {L"²", 0x00B2}, + {L"³", 0x00B3}, + {L"ß", 0x00DF}, + {L"Š", 0x0160}, + {L" ", 0x2009}, + {L"þ", 0x00FE}, + {L"˜", 0x02DC}, + {L"×", 0x00D7}, + {L"™", 0x2122}, + {L"Þ", 0x00DE}, + {L"¨", 0x00A8}, + {L"ù", 0x00F9}, + {L"ú", 0x00FA}, + {L"û", 0x00FB}, + {L"ü", 0x00FC}, + {L"Ù", 0x00D9}, + {L"Ú", 0x00DA}, + {L"Û", 0x00DB}, + {L"Ü", 0x00DC}, + {L"¥", 0x00A5}, + {L"ÿ", 0x00FF}, + {L"ý", 0x00FD}, + {L"Ý", 0x00DD}, + {L"Ÿ", 0x0178}, + {L"‍", 0x200D}, + {L"‌", 0x200C}, + {NULL, L'\0'}}; + +void CHTMLUtil::ConvertHTMLToW(const std::wstring& strHTML, std::wstring& strStripped) +{ + //! @todo STRING_CLEANUP + if (strHTML.empty()) + { + strStripped.clear(); + return ; + } + size_t iPos = 0; + strStripped = strHTML; + while (mappings[iPos].html) + { + StringUtils::Replace(strStripped, mappings[iPos].html,std::wstring(1, mappings[iPos].w)); + iPos++; + } + + iPos = strStripped.find(L"&#"); + while (iPos > 0 && iPos < strStripped.size() - 4) + { + size_t iStart = iPos + 1; + iPos += 2; + std::wstring num; + int base = 10; + if (strStripped[iPos] == L'x') + { + base = 16; + iPos++; + } + + size_t i = iPos; + while (iPos < strStripped.size() && + (base == 16 ? iswxdigit(strStripped[iPos]) : iswdigit(strStripped[iPos]))) + iPos++; + + num = strStripped.substr(i, iPos-i); + wchar_t val = (wchar_t)wcstol(num.c_str(),NULL,base); + if (base == 10) + num = StringUtils::Format(L"&#%ls;", num.c_str()); + else + num = StringUtils::Format(L"&#x%ls;", num.c_str()); + + StringUtils::Replace(strStripped, num,std::wstring(1,val)); + iPos = strStripped.find(L"&#", iStart); + } +} + diff --git a/xbmc/utils/HTMLUtil.h b/xbmc/utils/HTMLUtil.h new file mode 100644 index 0000000..5295a9c --- /dev/null +++ b/xbmc/utils/HTMLUtil.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +namespace HTML +{ +class CHTMLUtil +{ +public: + CHTMLUtil(void); + virtual ~CHTMLUtil(void); + static void RemoveTags(std::string& strHTML); + static void ConvertHTMLToW(const std::wstring& strHTML, std::wstring& strStripped); +}; +} diff --git a/xbmc/utils/HttpHeader.cpp b/xbmc/utils/HttpHeader.cpp new file mode 100644 index 0000000..ad73bb2 --- /dev/null +++ b/xbmc/utils/HttpHeader.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "HttpHeader.h" + +#include "utils/StringUtils.h" + +// header white space characters according to RFC 2616 +const char* const CHttpHeader::m_whitespaceChars = " \t"; + + +CHttpHeader::CHttpHeader() +{ + m_headerdone = false; +} + +CHttpHeader::~CHttpHeader() = default; + +void CHttpHeader::Parse(const std::string& strData) +{ + size_t pos = 0; + const size_t len = strData.length(); + const char* const strDataC = strData.c_str(); + + // According to RFC 2616 any header line can have continuation on next line, if next line is started from whitespace char + // This code at first checks for whitespace char at the begging of the line, and if found, then current line is appended to m_lastHeaderLine + // If current line is NOT started from whitespace char, then previously stored (and completed) m_lastHeaderLine is parsed and current line is assigned to m_lastHeaderLine (to be parsed later) + while (pos < len) + { + size_t lineEnd = strData.find('\x0a', pos); // use '\x0a' instead of '\n' to be platform independent + + if (lineEnd == std::string::npos) + return; // error: expected only complete lines + + const size_t nextLine = lineEnd + 1; + if (lineEnd > pos && strDataC[lineEnd - 1] == '\x0d') // use '\x0d' instead of '\r' to be platform independent + lineEnd--; + + if (m_headerdone) + Clear(); // clear previous header and process new one + + if (strDataC[pos] == ' ' || strDataC[pos] == '\t') // same chars as in CHttpHeader::m_whitespaceChars + { // line is started from whitespace char: this is continuation of previous line + pos = strData.find_first_not_of(m_whitespaceChars, pos); + + m_lastHeaderLine.push_back(' '); // replace all whitespace chars at start of the line with single space + m_lastHeaderLine.append(strData, pos, lineEnd - pos); // append current line + } + else + { // this line is NOT continuation, this line is new header line + if (!m_lastHeaderLine.empty()) + ParseLine(m_lastHeaderLine); // process previously stored completed line (if any) + + m_lastHeaderLine.assign(strData, pos, lineEnd - pos); // store current line to (possibly) complete later. Will be parsed on next turns. + + if (pos == lineEnd) + m_headerdone = true; // current line is bare "\r\n" (or "\n"), means end of header; no need to process current m_lastHeaderLine + } + + pos = nextLine; // go to next line (if any) + } +} + +bool CHttpHeader::ParseLine(const std::string& headerLine) +{ + const size_t valueStart = headerLine.find(':'); + + if (valueStart != std::string::npos) + { + std::string strParam(headerLine, 0, valueStart); + std::string strValue(headerLine, valueStart + 1); + + StringUtils::Trim(strParam, m_whitespaceChars); + StringUtils::ToLower(strParam); + + StringUtils::Trim(strValue, m_whitespaceChars); + + if (!strParam.empty() && !strValue.empty()) + m_params.push_back(HeaderParams::value_type(strParam, strValue)); + else + return false; + } + else if (m_protoLine.empty()) + m_protoLine = headerLine; + + return true; +} + +void CHttpHeader::AddParam(const std::string& param, const std::string& value, const bool overwrite /*= false*/) +{ + std::string paramLower(param); + StringUtils::ToLower(paramLower); + StringUtils::Trim(paramLower, m_whitespaceChars); + if (paramLower.empty()) + return; + + if (overwrite) + { // delete ALL parameters with the same name + // note: 'GetValue' always returns last added parameter, + // so you probably don't need to overwrite + for (size_t i = 0; i < m_params.size();) + { + if (m_params[i].first == paramLower) + m_params.erase(m_params.begin() + i); + else + ++i; + } + } + + std::string valueTrim(value); + StringUtils::Trim(valueTrim, m_whitespaceChars); + if (valueTrim.empty()) + return; + + m_params.push_back(HeaderParams::value_type(paramLower, valueTrim)); +} + +std::string CHttpHeader::GetValue(const std::string& strParam) const +{ + std::string paramLower(strParam); + StringUtils::ToLower(paramLower); + + return GetValueRaw(paramLower); +} + +std::string CHttpHeader::GetValueRaw(const std::string& strParam) const +{ + // look in reverse to find last parameter (probably most important) + for (HeaderParams::const_reverse_iterator iter = m_params.rbegin(); iter != m_params.rend(); ++iter) + { + if (iter->first == strParam) + return iter->second; + } + + return ""; +} + +std::vector CHttpHeader::GetValues(std::string strParam) const +{ + StringUtils::ToLower(strParam); + std::vector values; + + for (HeaderParams::const_iterator iter = m_params.begin(); iter != m_params.end(); ++iter) + { + if (iter->first == strParam) + values.push_back(iter->second); + } + + return values; +} + +std::string CHttpHeader::GetHeader(void) const +{ + if (m_protoLine.empty() && m_params.empty()) + return ""; + + std::string strHeader(m_protoLine + "\r\n"); + + for (HeaderParams::const_iterator iter = m_params.begin(); iter != m_params.end(); ++iter) + strHeader += ((*iter).first + ": " + (*iter).second + "\r\n"); + + strHeader += "\r\n"; + return strHeader; +} + +std::string CHttpHeader::GetMimeType(void) const +{ + std::string strValue(GetValueRaw("content-type")); + + std::string mimeType(strValue, 0, strValue.find(';')); + StringUtils::TrimRight(mimeType, m_whitespaceChars); + + return mimeType; +} + +std::string CHttpHeader::GetCharset(void) const +{ + std::string strValue(GetValueRaw("content-type")); + if (strValue.empty()) + return strValue; + + StringUtils::ToUpper(strValue); + const size_t len = strValue.length(); + + // extract charset value from 'contenttype/contentsubtype;pram1=param1Val ; charset=XXXX\t;param2=param2Val' + // most common form: 'text/html; charset=XXXX' + // charset value can be in double quotes: 'text/xml; charset="XXX XX"' + + size_t pos = strValue.find(';'); + while (pos < len) + { + // move to the next non-whitespace character + pos = strValue.find_first_not_of(m_whitespaceChars, pos + 1); + + if (pos != std::string::npos) + { + if (strValue.compare(pos, 8, "CHARSET=", 8) == 0) + { + pos += 8; // move position to char after 'CHARSET=' + size_t len = strValue.find(';', pos); + if (len != std::string::npos) + len -= pos; + std::string charset(strValue, pos, len); // intentionally ignoring possible ';' inside quoted string + // as we don't support any charset with ';' in name + StringUtils::Trim(charset, m_whitespaceChars); + if (!charset.empty()) + { + if (charset[0] != '"') + return charset; + else + { // charset contains quoted string (allowed according to RFC 2616) + StringUtils::Replace(charset, "\\", ""); // unescape chars, ignoring possible '\"' and '\\' + const size_t closingQ = charset.find('"', 1); + if (closingQ == std::string::npos) + return ""; // no closing quote + + return charset.substr(1, closingQ - 1); + } + } + } + pos = strValue.find(';', pos); // find next parameter + } + } + + return ""; // no charset is detected +} + +void CHttpHeader::Clear() +{ + m_params.clear(); + m_protoLine.clear(); + m_headerdone = false; + m_lastHeaderLine.clear(); +} diff --git a/xbmc/utils/HttpHeader.h b/xbmc/utils/HttpHeader.h new file mode 100644 index 0000000..6d8b543 --- /dev/null +++ b/xbmc/utils/HttpHeader.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include + +class CHttpHeader +{ +public: + typedef std::pair HeaderParamValue; + typedef std::vector HeaderParams; + typedef HeaderParams::iterator HeaderParamsIter; + + CHttpHeader(); + ~CHttpHeader(); + + void Parse(const std::string& strData); + void AddParam(const std::string& param, const std::string& value, const bool overwrite = false); + + std::string GetValue(const std::string& strParam) const; + std::vector GetValues(std::string strParam) const; + + std::string GetHeader(void) const; + + std::string GetMimeType(void) const; + std::string GetCharset(void) const; + inline std::string GetProtoLine() const + { return m_protoLine; } + + inline bool IsHeaderDone(void) const + { return m_headerdone; } + + void Clear(); + +protected: + std::string GetValueRaw(const std::string& strParam) const; + bool ParseLine(const std::string& headerLine); + + HeaderParams m_params; + std::string m_protoLine; + bool m_headerdone; + std::string m_lastHeaderLine; + static const char* const m_whitespaceChars; +}; + diff --git a/xbmc/utils/HttpParser.cpp b/xbmc/utils/HttpParser.cpp new file mode 100644 index 0000000..9276d4c --- /dev/null +++ b/xbmc/utils/HttpParser.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2011-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + * + * This code implements parsing of HTTP requests. + * This code was written by Steve Hanov in 2009, no copyright is claimed. + * This code is in the public domain. + * Code was taken from http://refactormycode.com/codes/778-an-efficient-http-parser + */ + +#include "HttpParser.h" + +HttpParser::~HttpParser() = default; + +void +HttpParser::parseHeader() +{ + // run the fsm. + const int CR = 13; + const int LF = 10; + const int ANY = 256; + + enum Action { + // make lower case + LOWER = 0x1, + + // convert current character to null. + NULLIFY = 0x2, + + // set the header index to the current position + SET_HEADER_START = 0x4, + + // set the key index to the current position + SET_KEY = 0x8, + + // set value index to the current position. + SET_VALUE = 0x10, + + // store current key/value pair. + STORE_KEY_VALUE = 0x20, + + // sets content start to current position + 1 + SET_CONTENT_START = 0x40 + }; + + static const struct FSM { + State curState; + int c; + State nextState; + unsigned actions; + } fsm[] = { + { p_request_line, CR, p_request_line_cr, NULLIFY }, + { p_request_line, ANY, p_request_line, 0 }, + { p_request_line_cr, LF, p_request_line_crlf, 0 }, + { p_request_line_crlf, CR, p_request_line_crlfcr, 0 }, + { p_request_line_crlf, ANY, p_key, SET_HEADER_START | SET_KEY | LOWER }, + { p_request_line_crlfcr, LF, p_content, SET_CONTENT_START }, + { p_key, ':', p_key_colon, NULLIFY }, + { p_key, ANY, p_key, LOWER }, + { p_key_colon, ' ', p_key_colon_sp, 0 }, + { p_key_colon_sp, ANY, p_value, SET_VALUE }, + { p_value, CR, p_value_cr, NULLIFY | STORE_KEY_VALUE }, + { p_value, ANY, p_value, 0 }, + { p_value_cr, LF, p_value_crlf, 0 }, + { p_value_crlf, CR, p_value_crlfcr, 0 }, + { p_value_crlf, ANY, p_key, SET_KEY | LOWER }, + { p_value_crlfcr, LF, p_content, SET_CONTENT_START }, + { p_error, ANY, p_error, 0 } + }; + + for( unsigned i = _parsedTo; i < _data.length(); ++i) { + char c = _data[i]; + State nextState = p_error; + + for (const FSM& f : fsm) { + if ( f.curState == _state && + ( c == f.c || f.c == ANY ) ) { + + nextState = f.nextState; + + if ( f.actions & LOWER ) { + _data[i] = tolower( _data[i] ); + } + + if ( f.actions & NULLIFY ) { + _data[i] = 0; + } + + if ( f.actions & SET_HEADER_START ) { + _headerStart = i; + } + + if ( f.actions & SET_KEY ) { + _keyIndex = i; + } + + if ( f.actions & SET_VALUE ) { + _valueIndex = i; + } + + if ( f.actions & SET_CONTENT_START ) { + _contentStart = i + 1; + } + + if ( f.actions & STORE_KEY_VALUE ) { + // store position of first character of key. + _keys.push_back( _keyIndex ); + } + + break; + } + } + + _state = nextState; + + if ( _state == p_content ) { + const char* str = getValue("content-length"); + if ( str ) { + _contentLength = atoi( str ); + } + break; + } + } + + _parsedTo = _data.length(); + +} + +bool +HttpParser::parseRequestLine() +{ + size_t sp1; + size_t sp2; + + sp1 = _data.find( ' ', 0 ); + if ( sp1 == std::string::npos ) return false; + sp2 = _data.find( ' ', sp1 + 1 ); + if ( sp2 == std::string::npos ) return false; + + _data[sp1] = 0; + _data[sp2] = 0; + _uriIndex = sp1 + 1; + return true; +} + +HttpParser::status_t +HttpParser::addBytes( const char* bytes, unsigned len ) +{ + if ( _status != Incomplete ) { + return _status; + } + + // append the bytes to data. + _data.append( bytes, len ); + + if ( _state < p_content ) { + parseHeader(); + } + + if ( _state == p_error ) { + _status = Error; + } else if ( _state == p_content ) { + if ( _contentLength == 0 || _data.length() - _contentStart >= _contentLength ) { + if ( parseRequestLine() ) { + _status = Done; + } else { + _status = Error; + } + } + } + + return _status; +} + +const char* +HttpParser::getMethod() const +{ + return &_data[0]; +} + +const char* +HttpParser::getUri() const +{ + return &_data[_uriIndex]; +} + +const char* +HttpParser::getQueryString() const +{ + const char* pos = getUri(); + while( *pos ) { + if ( *pos == '?' ) { + pos++; + break; + } + pos++; + } + return pos; +} + +const char* +HttpParser::getBody() const +{ + if ( _contentLength > 0 ) { + return &_data[_contentStart]; + } else { + return NULL; + } +} + +// key should be in lower case. +const char* +HttpParser::getValue( const char* key ) const +{ + for( IntArray::const_iterator iter = _keys.begin(); + iter != _keys.end(); ++iter ) + { + unsigned index = *iter; + if ( strcmp( &_data[index], key ) == 0 ) { + return &_data[index + strlen(key) + 2]; + } + + } + + return NULL; +} + +unsigned +HttpParser::getContentLength() const +{ + return _contentLength; +} + diff --git a/xbmc/utils/HttpParser.h b/xbmc/utils/HttpParser.h new file mode 100644 index 0000000..47a3a9f --- /dev/null +++ b/xbmc/utils/HttpParser.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2011-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + * + * This code implements parsing of HTTP requests. + * This code was written by Steve Hanov in 2009, no copyright is claimed. + * This code is in the public domain. + * Code was taken from http://refactormycode.com/codes/778-an-efficient-http-parser + */ + +#pragma once + +#include +#include +#include +#include + +// A class to incrementally parse an HTTP header as it comes in. It +// lets you know when it has received all required bytes, as specified +// by the content-length header (if present). If there is no content-length, +// it will stop reading after the final "\n\r". +// +// Example usage: +// +// HttpParser parser; +// HttpParser::status_t status; +// +// for( ;; ) { +// // read bytes from socket into buffer, break on error +// status = parser.addBytes( buffer, length ); +// if ( status != HttpParser::Incomplete ) break; +// } +// +// if ( status == HttpParser::Done ) { +// // parse fully formed http message. +// } + + +class HttpParser +{ +public: + ~HttpParser(); + + enum status_t { + Done, + Error, + Incomplete + }; + + status_t addBytes( const char* bytes, unsigned len ); + + const char* getMethod() const; + const char* getUri() const; + const char* getQueryString() const; + const char* getBody() const; + // key should be in lower case when looking up. + const char* getValue( const char* key ) const; + unsigned getContentLength() const; + +private: + void parseHeader(); + bool parseRequestLine(); + + std::string _data; + unsigned _headerStart = 0; + unsigned _parsedTo = 0 ; + int _state = 0 ; + unsigned _keyIndex = 0; + unsigned _valueIndex = 0; + unsigned _contentLength = 0; + unsigned _contentStart = 0; + unsigned _uriIndex = 0; + + typedef std::vector IntArray; + IntArray _keys; + + enum State { + p_request_line=0, + p_request_line_cr=1, + p_request_line_crlf=2, + p_request_line_crlfcr=3, + p_key=4, + p_key_colon=5, + p_key_colon_sp=6, + p_value=7, + p_value_cr=8, + p_value_crlf=9, + p_value_crlfcr=10, + p_content=11, // here we are done parsing the header. + p_error=12 // here an error has occurred and the parse failed. + }; + + status_t _status = Incomplete ; +}; + diff --git a/xbmc/utils/HttpRangeUtils.cpp b/xbmc/utils/HttpRangeUtils.cpp new file mode 100644 index 0000000..e25ccf6 --- /dev/null +++ b/xbmc/utils/HttpRangeUtils.cpp @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include + +#include "HttpRangeUtils.h" +#include "Util.h" +#ifdef HAS_WEB_SERVER +#include "network/httprequesthandler/IHTTPRequestHandler.h" +#endif // HAS_WEB_SERVER +#include "utils/StringUtils.h" +#include "utils/Variant.h" + +#include + +#define HEADER_NEWLINE "\r\n" +#define HEADER_SEPARATOR HEADER_NEWLINE HEADER_NEWLINE +#define HEADER_BOUNDARY "--" + +#define HEADER_CONTENT_RANGE_VALUE "%" PRIu64 +#define HEADER_CONTENT_RANGE_VALUE_UNKNOWN "*" +#define HEADER_CONTENT_RANGE_FORMAT_BYTES "bytes " HEADER_CONTENT_RANGE_VALUE "-" HEADER_CONTENT_RANGE_VALUE "/" +#define CONTENT_RANGE_FORMAT_TOTAL HEADER_CONTENT_RANGE_FORMAT_BYTES HEADER_CONTENT_RANGE_VALUE +#define CONTENT_RANGE_FORMAT_TOTAL_UNKNOWN HEADER_CONTENT_RANGE_FORMAT_BYTES HEADER_CONTENT_RANGE_VALUE_UNKNOWN + +CHttpRange::CHttpRange(uint64_t firstPosition, uint64_t lastPosition) + : m_first(firstPosition), + m_last(lastPosition) +{ } + +bool CHttpRange::operator<(const CHttpRange &other) const +{ + return (m_first < other.m_first) || + (m_first == other.m_first && m_last < other.m_last); +} + +bool CHttpRange::operator==(const CHttpRange &other) const +{ + return m_first == other.m_first && m_last == other.m_last; +} + +bool CHttpRange::operator!=(const CHttpRange &other) const +{ + return !(*this == other); +} + +uint64_t CHttpRange::GetLength() const +{ + if (!IsValid()) + return 0; + + return m_last - m_first + 1; +} + +void CHttpRange::SetLength(uint64_t length) +{ + m_last = m_first + length - 1; +} + +bool CHttpRange::IsValid() const +{ + return m_last >= m_first; +} + +CHttpResponseRange::CHttpResponseRange() + : CHttpRange(), + m_data(NULL) +{ } + +CHttpResponseRange::CHttpResponseRange(uint64_t firstPosition, uint64_t lastPosition) + : CHttpRange(firstPosition, lastPosition), + m_data(NULL) +{ } + +CHttpResponseRange::CHttpResponseRange(const void* data, uint64_t firstPosition, uint64_t lastPosition) + : CHttpRange(firstPosition, lastPosition), + m_data(data) +{ } + +CHttpResponseRange::CHttpResponseRange(const void* data, uint64_t length) + : CHttpRange(0, length - 1), + m_data(data) +{ } + +bool CHttpResponseRange::operator==(const CHttpResponseRange &other) const +{ + if (!CHttpRange::operator==(other)) + return false; + + return m_data == other.m_data; +} + +bool CHttpResponseRange::operator!=(const CHttpResponseRange &other) const +{ + return !(*this == other); +} + +void CHttpResponseRange::SetData(const void* data, uint64_t length) +{ + if (length == 0) + return; + + m_first = 0; + + SetData(data); + SetLength(length); +} + +void CHttpResponseRange::SetData(const void* data, uint64_t firstPosition, uint64_t lastPosition) +{ + SetData(data); + SetFirstPosition(firstPosition); + SetLastPosition(lastPosition); +} + +bool CHttpResponseRange::IsValid() const +{ + if (!CHttpRange::IsValid()) + return false; + + return m_data != NULL; +} + +CHttpRanges::CHttpRanges() +: m_ranges() +{ } + +CHttpRanges::CHttpRanges(const HttpRanges& httpRanges) +: m_ranges(httpRanges) +{ + SortAndCleanup(); +} + +bool CHttpRanges::Get(size_t index, CHttpRange& range) const +{ + if (index >= Size()) + return false; + + range = m_ranges.at(index); + return true; +} + +bool CHttpRanges::GetFirst(CHttpRange& range) const +{ + if (m_ranges.empty()) + return false; + + range = m_ranges.front(); + return true; +} + +bool CHttpRanges::GetLast(CHttpRange& range) const +{ + if (m_ranges.empty()) + return false; + + range = m_ranges.back(); + return true; +} + +bool CHttpRanges::GetFirstPosition(uint64_t& position) const +{ + if (m_ranges.empty()) + return false; + + position = m_ranges.front().GetFirstPosition(); + return true; +} + +bool CHttpRanges::GetLastPosition(uint64_t& position) const +{ + if (m_ranges.empty()) + return false; + + position = m_ranges.back().GetLastPosition(); + return true; +} + +uint64_t CHttpRanges::GetLength() const +{ + uint64_t length = 0; + for (HttpRanges::const_iterator range = m_ranges.begin(); range != m_ranges.end(); ++range) + length += range->GetLength(); + + return length; +} + +bool CHttpRanges::GetTotalRange(CHttpRange& range) const +{ + if (m_ranges.empty()) + return false; + + uint64_t firstPosition, lastPosition; + if (!GetFirstPosition(firstPosition) || !GetLastPosition(lastPosition)) + return false; + + range.SetFirstPosition(firstPosition); + range.SetLastPosition(lastPosition); + + return range.IsValid(); +} + +void CHttpRanges::Add(const CHttpRange& range) +{ + if (!range.IsValid()) + return; + + m_ranges.push_back(range); + + SortAndCleanup(); +} + +void CHttpRanges::Remove(size_t index) +{ + if (index >= Size()) + return; + + m_ranges.erase(m_ranges.begin() + index); +} + +void CHttpRanges::Clear() +{ + m_ranges.clear(); +} + +bool CHttpRanges::Parse(const std::string& header) +{ + return Parse(header, std::numeric_limits::max()); +} + +bool CHttpRanges::Parse(const std::string& header, uint64_t totalLength) +{ + m_ranges.clear(); + + if (header.empty() || totalLength == 0 || !StringUtils::StartsWithNoCase(header, "bytes=")) + return false; + + uint64_t lastPossiblePosition = totalLength - 1; + + // remove "bytes=" from the beginning + std::string rangesValue = header.substr(6); + + // split the value of the "Range" header by "," + std::vector rangeValues = StringUtils::Split(rangesValue, ","); + + for (std::vector::const_iterator range = rangeValues.begin(); range != rangeValues.end(); ++range) + { + // there must be a "-" in the range definition + if (range->find("-") == std::string::npos) + return false; + + std::vector positions = StringUtils::Split(*range, "-"); + if (positions.size() != 2) + return false; + + bool hasStart = false; + uint64_t start = 0; + bool hasEnd = false; + uint64_t end = 0; + + // parse the start and end positions + if (!positions.front().empty()) + { + if (!StringUtils::IsNaturalNumber(positions.front())) + return false; + + start = str2uint64(positions.front(), 0); + hasStart = true; + } + if (!positions.back().empty()) + { + if (!StringUtils::IsNaturalNumber(positions.back())) + return false; + + end = str2uint64(positions.back(), 0); + hasEnd = true; + } + + // nothing defined at all + if (!hasStart && !hasEnd) + return false; + + // make sure that the end position makes sense + if (hasEnd) + end = std::min(end, lastPossiblePosition); + + if (!hasStart && hasEnd) + { + // the range is defined as the number of bytes from the end + start = totalLength - end; + end = lastPossiblePosition; + } + else if (hasStart && !hasEnd) + end = lastPossiblePosition; + + // make sure the start position makes sense + if (start > lastPossiblePosition) + return false; + + // make sure that the start position is smaller or equal to the end position + if (end < start) + return false; + + m_ranges.push_back(CHttpRange(start, end)); + } + + if (m_ranges.empty()) + return false; + + SortAndCleanup(); + return !m_ranges.empty(); +} + +void CHttpRanges::SortAndCleanup() +{ + // sort the ranges by their first position + std::sort(m_ranges.begin(), m_ranges.end()); + + // check for overlapping ranges + for (HttpRanges::iterator range = m_ranges.begin() + 1; range != m_ranges.end();) + { + HttpRanges::iterator previous = range - 1; + + // check if the current and the previous range overlap + if (previous->GetLastPosition() + 1 >= range->GetFirstPosition()) + { + // combine the previous and the current ranges by setting the last position of the previous range + // to the last position of the current range + previous->SetLastPosition(range->GetLastPosition()); + + // then remove the current range which is not needed anymore + range = m_ranges.erase(range); + } + else + ++range; + } +} + +std::string HttpRangeUtils::GenerateContentRangeHeaderValue(const CHttpRange* range) +{ + if (range == NULL) + return ""; + + return StringUtils::Format(CONTENT_RANGE_FORMAT_TOTAL, range->GetFirstPosition(), range->GetLastPosition(), range->GetLength()); +} + +std::string HttpRangeUtils::GenerateContentRangeHeaderValue(uint64_t start, uint64_t end, uint64_t total) +{ + if (total > 0) + return StringUtils::Format(CONTENT_RANGE_FORMAT_TOTAL, start, end, total); + + return StringUtils::Format(CONTENT_RANGE_FORMAT_TOTAL_UNKNOWN, start, end); +} + +#ifdef HAS_WEB_SERVER + +std::string HttpRangeUtils::GenerateMultipartBoundary() +{ + static char chars[] = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + // create a string of length 30 to 40 and pre-fill it with "-" + size_t count = static_cast(CUtil::GetRandomNumber()) % 11 + 30; + std::string boundary(count, '-'); + + for (size_t i = static_cast(CUtil::GetRandomNumber()) % 5 + 8; i < count; i++) + boundary.replace(i, 1, 1, chars[static_cast(CUtil::GetRandomNumber()) % 64]); + + return boundary; +} + +std::string HttpRangeUtils::GenerateMultipartBoundaryContentType(const std::string& multipartBoundary) +{ + if (multipartBoundary.empty()) + return ""; + + return "multipart/byteranges; boundary=" + multipartBoundary; +} + +std::string HttpRangeUtils::GenerateMultipartBoundaryWithHeader(const std::string& multipartBoundary, const std::string& contentType) +{ + if (multipartBoundary.empty()) + return ""; + + std::string boundaryWithHeader = HEADER_BOUNDARY + multipartBoundary + HEADER_NEWLINE; + if (!contentType.empty()) + boundaryWithHeader += MHD_HTTP_HEADER_CONTENT_TYPE ": " + contentType + HEADER_NEWLINE; + + return boundaryWithHeader; +} + +std::string HttpRangeUtils::GenerateMultipartBoundaryWithHeader(const std::string& multipartBoundary, const std::string& contentType, const CHttpRange* range) +{ + if (multipartBoundary.empty() || range == NULL) + return ""; + + return GenerateMultipartBoundaryWithHeader(GenerateMultipartBoundaryWithHeader(multipartBoundary, contentType), range); +} + +std::string HttpRangeUtils::GenerateMultipartBoundaryWithHeader(const std::string& multipartBoundaryWithContentType, const CHttpRange* range) +{ + if (multipartBoundaryWithContentType.empty() || range == NULL) + return ""; + + std::string boundaryWithHeader = multipartBoundaryWithContentType; + boundaryWithHeader += MHD_HTTP_HEADER_CONTENT_RANGE ": " + GenerateContentRangeHeaderValue(range); + boundaryWithHeader += HEADER_SEPARATOR; + + return boundaryWithHeader; +} + +std::string HttpRangeUtils::GenerateMultipartBoundaryEnd(const std::string& multipartBoundary) +{ + if (multipartBoundary.empty()) + return ""; + + return HEADER_NEWLINE HEADER_BOUNDARY + multipartBoundary + HEADER_BOUNDARY; +} + +#endif // HAS_WEB_SERVER diff --git a/xbmc/utils/HttpRangeUtils.h b/xbmc/utils/HttpRangeUtils.h new file mode 100644 index 0000000..7e0b66d --- /dev/null +++ b/xbmc/utils/HttpRangeUtils.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include + +class CHttpRange +{ +public: + CHttpRange() = default; + CHttpRange(uint64_t firstPosition, uint64_t lastPosition); + virtual ~CHttpRange() = default; + + bool operator<(const CHttpRange &other) const; + bool operator==(const CHttpRange &other) const; + bool operator!=(const CHttpRange &other) const; + + virtual uint64_t GetFirstPosition() const { return m_first; } + virtual void SetFirstPosition(uint64_t firstPosition) { m_first = firstPosition; } + virtual uint64_t GetLastPosition() const { return m_last; } + virtual void SetLastPosition(uint64_t lastPosition) { m_last = lastPosition; } + + virtual uint64_t GetLength() const; + virtual void SetLength(uint64_t length); + + virtual bool IsValid() const; + +protected: + uint64_t m_first = 1; + uint64_t m_last = 0; +}; + +typedef std::vector HttpRanges; + +class CHttpResponseRange : public CHttpRange +{ +public: + CHttpResponseRange(); + CHttpResponseRange(uint64_t firstPosition, uint64_t lastPosition); + CHttpResponseRange(const void* data, uint64_t firstPosition, uint64_t lastPosition); + CHttpResponseRange(const void* data, uint64_t length); + ~CHttpResponseRange() override = default; + + bool operator==(const CHttpResponseRange &other) const; + bool operator!=(const CHttpResponseRange &other) const; + + const void* GetData() const { return m_data; } + void SetData(const void* data) { m_data = data; } + void SetData(const void* data, uint64_t length); + void SetData(const void* data, uint64_t firstPosition, uint64_t lastPosition); + + bool IsValid() const override; + +protected: + const void* m_data; +}; + +typedef std::vector HttpResponseRanges; + +class CHttpRanges final +{ +public: + CHttpRanges(); + explicit CHttpRanges(const HttpRanges& httpRanges); + + const HttpRanges& Get() const { return m_ranges; } + bool Get(size_t index, CHttpRange& range) const; + bool GetFirst(CHttpRange& range) const; + bool GetLast(CHttpRange& range) const; + size_t Size() const { return m_ranges.size(); } + bool IsEmpty() const { return m_ranges.empty(); } + + bool GetFirstPosition(uint64_t& position) const; + bool GetLastPosition(uint64_t& position) const; + uint64_t GetLength() const; + + bool GetTotalRange(CHttpRange& range) const; + + void Add(const CHttpRange& range); + void Remove(size_t index); + void Clear(); + + HttpRanges::const_iterator Begin() const { return m_ranges.begin(); } + HttpRanges::const_iterator End() const { return m_ranges.end(); } + + bool Parse(const std::string& header); + bool Parse(const std::string& header, uint64_t totalLength); + +protected: + void SortAndCleanup(); + + HttpRanges m_ranges; +}; + +class HttpRangeUtils +{ +public: + /*! + * \brief Generates a valid Content-Range HTTP header value for the given HTTP + * range definition. + * + * \param range HTTP range definition used to generate the Content-Range HTTP header + * \return Content-Range HTTP header value + */ + static std::string GenerateContentRangeHeaderValue(const CHttpRange* range); + + /*! + * \brief Generates a valid Content-Range HTTP header value for the given HTTP + * range properties. + * + * \param start Start position of the HTTP range + * \param end Last/End position of the HTTP range + * \param total Total length of original content (not just the range) + * \return Content-Range HTTP header value + */ + static std::string GenerateContentRangeHeaderValue(uint64_t start, uint64_t end, uint64_t total); + +#ifdef HAS_WEB_SERVER + /*! + * \brief Generates a multipart boundary that can be used in ranged HTTP + * responses. + * + * \return Multipart boundary that can be used in ranged HTTP responses + */ + static std::string GenerateMultipartBoundary(); + + /*! + * \brief Generates the multipart/byteranges Content-Type HTTP header value + * containing the given multipart boundary for a ranged HTTP response. + * + * \param multipartBoundary Multipart boundary to be used in the ranged HTTP response + * \return multipart/byteranges Content-Type HTTP header value + */ + static std::string GenerateMultipartBoundaryContentType(const std::string& multipartBoundary); + + /*! + * \brief Generates a multipart boundary including the Content-Type HTTP + * header value with the (actual) given content type of the original + * content. + * + * \param multipartBoundary Multipart boundary to be used in the ranged HTTP response + * \param contentType (Actual) Content type of the original content + * \return Multipart boundary (including the Content-Type HTTP header) value that can be used in ranged HTTP responses + */ + static std::string GenerateMultipartBoundaryWithHeader(const std::string& multipartBoundary, const std::string& contentType); + + /*! + * \brief Generates a multipart boundary including the Content-Type HTTP + * header value with the (actual) given content type of the original + * content and the Content-Range HTTP header value for the given range. + * + * \param multipartBoundary Multipart boundary to be used in the ranged HTTP response + * \param contentType (Actual) Content type of the original content + * \param range HTTP range definition used to generate the Content-Range HTTP header + * \return Multipart boundary (including the Content-Type and Content-Range HTTP headers) value that can be used in ranged HTTP responses + */ + static std::string GenerateMultipartBoundaryWithHeader(const std::string& multipartBoundary, const std::string& contentType, const CHttpRange* range); + + /*! + * \brief Generates a multipart boundary including the Content-Type HTTP + * header value with the (actual) given content type of the original + * content and the Content-Range HTTP header value for the given range. + * + * \param multipartBoundaryWithContentType Multipart boundary (already including the Content-Type HTTP header value) to be used in the ranged HTTP response + * \param range HTTP range definition used to generate the Content-Range HTTP header + * \return Multipart boundary (including the Content-Type and Content-Range HTTP headers) value that can be used in ranged HTTP responses + */ + static std::string GenerateMultipartBoundaryWithHeader(const std::string& multipartBoundaryWithContentType, const CHttpRange* range); + + /*! + * \brief Generates a multipart boundary end that can be used in ranged HTTP + * responses. + * + * \param multipartBoundary Multipart boundary to be used in the ranged HTTP response + * \return Multipart boundary end that can be used in a ranged HTTP response + */ + static std::string GenerateMultipartBoundaryEnd(const std::string& multipartBoundary); +#endif // HAS_WEB_SERVER +}; diff --git a/xbmc/utils/HttpResponse.cpp b/xbmc/utils/HttpResponse.cpp new file mode 100644 index 0000000..33c7c27 --- /dev/null +++ b/xbmc/utils/HttpResponse.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2011-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "HttpResponse.h" + +#include + +#define SPACE " " +#define SEPARATOR ": " +#define LINEBREAK "\r\n" + +#define HEADER_CONTENT_LENGTH "Content-Length" + +std::map CHttpResponse::m_statusCodeText = CHttpResponse::createStatusCodes(); + +CHttpResponse::CHttpResponse(HTTP::Method method, HTTP::StatusCode status, HTTP::Version version /* = HTTPVersion1_1 */) +{ + m_method = method; + m_status = status; + m_version = version; + + m_content = NULL; + m_contentLength = 0; +} + +void CHttpResponse::AddHeader(const std::string &field, const std::string &value) +{ + if (field.empty()) + return; + + m_headers.emplace_back(field, value); +} + +void CHttpResponse::SetContent(const char* data, unsigned int length) +{ + m_content = data; + + if (m_content == NULL) + m_contentLength = 0; + else + m_contentLength = length; +} + +std::string CHttpResponse::Create() +{ + m_buffer.clear(); + + m_buffer.append("HTTP/"); + switch (m_version) + { + case HTTP::Version1_0: + m_buffer.append("1.0"); + break; + + case HTTP::Version1_1: + m_buffer.append("1.1"); + break; + + default: + return 0; + } + + char statusBuffer[4]; + sprintf(statusBuffer, "%d", (int)m_status); + m_buffer.append(SPACE); + m_buffer.append(statusBuffer); + + m_buffer.append(SPACE); + m_buffer.append(m_statusCodeText.find(m_status)->second); + m_buffer.append(LINEBREAK); + + bool hasContentLengthHeader = false; + for (unsigned int index = 0; index < m_headers.size(); index++) + { + m_buffer.append(m_headers[index].first); + m_buffer.append(SEPARATOR); + m_buffer.append(m_headers[index].second); + m_buffer.append(LINEBREAK); + + if (m_headers[index].first.compare(HEADER_CONTENT_LENGTH) == 0) + hasContentLengthHeader = true; + } + + if (!hasContentLengthHeader && m_content != NULL && m_contentLength > 0) + { + m_buffer.append(HEADER_CONTENT_LENGTH); + m_buffer.append(SEPARATOR); + char lengthBuffer[11]; + sprintf(lengthBuffer, "%u", m_contentLength); + m_buffer.append(lengthBuffer); + m_buffer.append(LINEBREAK); + } + + m_buffer.append(LINEBREAK); + if (m_content != NULL && m_contentLength > 0) + m_buffer.append(m_content, m_contentLength); + + return m_buffer; +} + +std::map CHttpResponse::createStatusCodes() +{ + std::map map; + map[HTTP::Continue] = "Continue"; + map[HTTP::SwitchingProtocols] = "Switching Protocols"; + map[HTTP::Processing] = "Processing"; + map[HTTP::ConnectionTimedOut] = "Connection timed out"; + map[HTTP::OK] = "OK"; + map[HTTP::Created] = "Created"; + map[HTTP::Accepted] = "Accepted"; + map[HTTP::NonAuthoritativeInformation] = "Non-Authoritative Information"; + map[HTTP::NoContent] = "No Content"; + map[HTTP::ResetContent] = "Reset Content"; + map[HTTP::PartialContent] = "Partial Content"; + map[HTTP::MultiStatus] = "Multi-Status"; + map[HTTP::MultipleChoices] = "Multiple Choices"; + map[HTTP::MovedPermanently] = "Moved Permanently"; + map[HTTP::Found] = "Found"; + map[HTTP::SeeOther] = "See Other"; + map[HTTP::NotModified] = "Not Modified"; + map[HTTP::UseProxy] = "Use Proxy"; + //map[HTTP::SwitchProxy] = "Switch Proxy"; + map[HTTP::TemporaryRedirect] = "Temporary Redirect"; + map[HTTP::BadRequest] = "Bad Request"; + map[HTTP::Unauthorized] = "Unauthorized"; + map[HTTP::PaymentRequired] = "Payment Required"; + map[HTTP::Forbidden] = "Forbidden"; + map[HTTP::NotFound] = "Not Found"; + map[HTTP::MethodNotAllowed] = "Method Not Allowed"; + map[HTTP::NotAcceptable] = "Not Acceptable"; + map[HTTP::ProxyAuthenticationRequired] = "Proxy Authentication Required"; + map[HTTP::RequestTimeout] = "Request Time-out"; + map[HTTP::Conflict] = "Conflict"; + map[HTTP::Gone] = "Gone"; + map[HTTP::LengthRequired] = "Length Required"; + map[HTTP::PreconditionFailed] = "Precondition Failed"; + map[HTTP::RequestEntityTooLarge] = "Request Entity Too Large"; + map[HTTP::RequestURITooLong] = "Request-URI Too Long"; + map[HTTP::UnsupportedMediaType] = "Unsupported Media Type"; + map[HTTP::RequestedRangeNotSatisfiable] = "Requested range not satisfiable"; + map[HTTP::ExpectationFailed] = "Expectation Failed"; + map[HTTP::ImATeapot] = "I'm a Teapot"; + map[HTTP::TooManyConnections] = "There are too many connections from your internet address"; + map[HTTP::UnprocessableEntity] = "Unprocessable Entity"; + map[HTTP::Locked] = "Locked"; + map[HTTP::FailedDependency] = "Failed Dependency"; + map[HTTP::UnorderedCollection] = "UnorderedCollection"; + map[HTTP::UpgradeRequired] = "Upgrade Required"; + map[HTTP::InternalServerError] = "Internal Server Error"; + map[HTTP::NotImplemented] = "Not Implemented"; + map[HTTP::BadGateway] = "Bad Gateway"; + map[HTTP::ServiceUnavailable] = "Service Unavailable"; + map[HTTP::GatewayTimeout] = "Gateway Time-out"; + map[HTTP::HTTPVersionNotSupported] = "HTTP Version not supported"; + map[HTTP::VariantAlsoNegotiates] = "Variant Also Negotiates"; + map[HTTP::InsufficientStorage] = "Insufficient Storage"; + map[HTTP::BandwidthLimitExceeded] = "Bandwidth Limit Exceeded"; + map[HTTP::NotExtended] = "Not Extended"; + + return map; +} diff --git a/xbmc/utils/HttpResponse.h b/xbmc/utils/HttpResponse.h new file mode 100644 index 0000000..50fc739 --- /dev/null +++ b/xbmc/utils/HttpResponse.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2011-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include +#include + +namespace HTTP +{ + enum Version + { + Version1_0, + Version1_1 + }; + + enum Method + { + Get, + Head, + POST, + PUT, + Delete, + Trace, + Connect + }; + + enum StatusCode + { + // Information 1xx + Continue = 100, + SwitchingProtocols = 101, + Processing = 102, + ConnectionTimedOut = 103, + + // Success 2xx + OK = 200, + Created = 201, + Accepted = 202, + NonAuthoritativeInformation = 203, + NoContent = 204, + ResetContent = 205, + PartialContent = 206, + MultiStatus = 207, + + // Redirects 3xx + MultipleChoices = 300, + MovedPermanently = 301, + Found = 302, + SeeOther = 303, + NotModified = 304, + UseProxy = 305, + //SwitchProxy = 306, + TemporaryRedirect = 307, + + // Client errors 4xx + BadRequest = 400, + Unauthorized = 401, + PaymentRequired = 402, + Forbidden = 403, + NotFound = 404, + MethodNotAllowed = 405, + NotAcceptable = 406, + ProxyAuthenticationRequired = 407, + RequestTimeout = 408, + Conflict = 409, + Gone = 410, + LengthRequired = 411, + PreconditionFailed = 412, + RequestEntityTooLarge = 413, + RequestURITooLong = 414, + UnsupportedMediaType = 415, + RequestedRangeNotSatisfiable = 416, + ExpectationFailed = 417, + ImATeapot = 418, + TooManyConnections = 421, + UnprocessableEntity = 422, + Locked = 423, + FailedDependency = 424, + UnorderedCollection = 425, + UpgradeRequired = 426, + + // Server errors 5xx + InternalServerError = 500, + NotImplemented = 501, + BadGateway = 502, + ServiceUnavailable = 503, + GatewayTimeout = 504, + HTTPVersionNotSupported = 505, + VariantAlsoNegotiates = 506, + InsufficientStorage = 507, + BandwidthLimitExceeded = 509, + NotExtended = 510 + }; +} + +class CHttpResponse +{ +public: + CHttpResponse(HTTP::Method method, HTTP::StatusCode status, HTTP::Version version = HTTP::Version1_1); + + void AddHeader(const std::string &field, const std::string &value); + void SetContent(const char* data, unsigned int length); + + std::string Create(); + +private: + HTTP::Method m_method; + HTTP::StatusCode m_status; + HTTP::Version m_version; + std::vector< std::pair > m_headers; + const char* m_content; + unsigned int m_contentLength; + std::string m_buffer; + + static std::map m_statusCodeText; + static std::map createStatusCodes(); +}; diff --git a/xbmc/utils/IArchivable.h b/xbmc/utils/IArchivable.h new file mode 100644 index 0000000..1ad58a1 --- /dev/null +++ b/xbmc/utils/IArchivable.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +class CArchive; + +class IArchivable +{ +protected: + /* make sure nobody deletes a pointer to this class */ + ~IArchivable() = default; + +public: + virtual void Archive(CArchive& ar) = 0; +}; + diff --git a/xbmc/utils/IBufferObject.h b/xbmc/utils/IBufferObject.h new file mode 100644 index 0000000..4588aff --- /dev/null +++ b/xbmc/utils/IBufferObject.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include + +/** + * @brief Interface to describe CBufferObjects. + * + * BufferObjects are used to abstract various memory types and present them + * with a generic interface. Typically on a posix system exists the concept + * of Direct Memory Access (DMA) which allows various systems to interact + * with a memory location directly without having to copy the data into + * userspace (ie. from kernel space). These DMA buffers are presented as + * file descriptors (fds) which can be passed around to gain access to + * the buffers memory location. + * + * In order to write to these buffer types typically the memory location has + * to be mapped into userspace via a call to mmap (or similar). This presents + * userspace with a memory location that can be initially written to (ie. by + * using memcpy or similar). Depending on the underlying implementation a + * stride might be specified if the memory type requires padding to a certain + * size (such as page size). The stride must be used when copying into the buffer. + * + * Some memory implementation may provide special memory layouts in which case + * modifiers are provided that describe tiling or compression. This should be + * transparent to the caller as the data copied into a BufferObject will likely + * be linear. The modifier will be needed when presenting the buffer via DRM or + * EGL even if it is linear. + * + */ +class IBufferObject +{ +public: + virtual ~IBufferObject() = default; + + /** + * @brief Create a BufferObject based on the format, width, and height of the desired buffer + * + * @param format framebuffer pixel formats are described using the fourcc codes defined in + * https://github.com/torvalds/linux/blob/master/include/uapi/drm/drm_fourcc.h + * @param width width of the requested buffer. + * @param height height of the requested buffer. + * @return true BufferObject creation was successful. + * @return false BufferObject creation was unsuccessful. + */ + virtual bool CreateBufferObject(uint32_t format, uint32_t width, uint32_t height) = 0; + + /** + * @brief Create a BufferObject based only on the size of the desired buffer. Not all + * CBufferObject implementations may support this. This method is required for + * use with the CAddonVideoCodec as it only knows the decoded buffer size. + * + * @param size of the requested buffer. + * @return true BufferObject creation was successful. + * @return false BufferObject creation was unsuccessful. + */ + virtual bool CreateBufferObject(uint64_t size) = 0; + + /** + * @brief Destroy a BufferObject. + * + */ + virtual void DestroyBufferObject() = 0; + + /** + * @brief Get the Memory location of the BufferObject. This method needs to be + * called to be able to copy data into the BufferObject. + * + * @return uint8_t* pointer to the memory location of the BufferObject. + */ + virtual uint8_t *GetMemory() = 0; + + /** + * @brief Release the mapped memory of the BufferObject. After calling this the memory + * location pointed to by GetMemory() will be invalid. + * + */ + virtual void ReleaseMemory() = 0; + + /** + * @brief Get the File Descriptor of the BufferObject. The fd is guaranteed to be + * available after calling CreateBufferObject(). + * + * @return int fd for the BufferObject. Invalid if -1. + */ + virtual int GetFd() = 0; + + /** + * @brief Get the Stride of the BufferObject. The stride is guaranteed to be + * available after calling GetMemory(). + * + * @return uint32_t stride of the BufferObject. + */ + virtual uint32_t GetStride() = 0; + + /** + * @brief Get the Modifier of the BufferObject. Format Modifiers further describe + * the buffer's format such as for tiling or compression. + * see https://github.com/torvalds/linux/blob/master/include/uapi/drm/drm_fourcc.h + * + * @return uint64_t modifier of the BufferObject. 0 means the layout is linear (default). + */ + virtual uint64_t GetModifier() = 0; + + /** + * @brief Must be called before reading/writing data to the BufferObject. + * + */ + virtual void SyncStart() = 0; + + /** + * @brief Must be called after reading/writing data to the BufferObject. + * + */ + virtual void SyncEnd() = 0; + + /** + * @brief Get the Name of the BufferObject type in use + * + * @return std::string name of the BufferObject type in use + */ + virtual std::string GetName() const = 0; +}; diff --git a/xbmc/utils/ILocalizer.h b/xbmc/utils/ILocalizer.h new file mode 100644 index 0000000..a81f7ce --- /dev/null +++ b/xbmc/utils/ILocalizer.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include + +class ILocalizer +{ +public: + virtual ~ILocalizer() = default; + + virtual std::string Localize(std::uint32_t code) const = 0; + +protected: + ILocalizer() = default; +}; diff --git a/xbmc/utils/IPlatformLog.h b/xbmc/utils/IPlatformLog.h new file mode 100644 index 0000000..6ccf98d --- /dev/null +++ b/xbmc/utils/IPlatformLog.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include + +#ifdef TARGET_WINDOWS +using spdlog_filename_t = std::wstring; +#else +using spdlog_filename_t = std::string; +#endif + +namespace spdlog +{ +namespace sinks +{ +template +class dist_sink; +} +} // namespace spdlog + +class IPlatformLog +{ +public: + virtual ~IPlatformLog() = default; + + static std::unique_ptr CreatePlatformLog(); + + virtual spdlog_filename_t GetLogFilename(const std::string& filename) const = 0; + virtual void AddSinks( + std::shared_ptr> distributionSink) const = 0; +}; diff --git a/xbmc/utils/IRssObserver.h b/xbmc/utils/IRssObserver.h new file mode 100644 index 0000000..fae240c --- /dev/null +++ b/xbmc/utils/IRssObserver.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +typedef uint32_t character_t; +typedef std::vector vecText; + +class IRssObserver +{ +protected: + /* make sure nobody deletes a pointer to this class */ + ~IRssObserver() = default; + +public: + virtual void OnFeedUpdate(const vecText &feed) = 0; + virtual void OnFeedRelease() = 0; +}; diff --git a/xbmc/utils/IScreenshotSurface.h b/xbmc/utils/IScreenshotSurface.h new file mode 100644 index 0000000..3414cbc --- /dev/null +++ b/xbmc/utils/IScreenshotSurface.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +class IScreenshotSurface +{ +public: + virtual ~IScreenshotSurface() = default; + virtual bool Capture() { return false; } + virtual void CaptureVideo(bool blendToBuffer) { }; + + int GetWidth() const { return m_width; } + int GetHeight() const { return m_height; } + int GetStride() const { return m_stride; } + unsigned char* GetBuffer() const { return m_buffer; } + void ReleaseBuffer() + { + if (m_buffer) + { + delete m_buffer; + m_buffer = nullptr; + } + }; + +protected: + int m_width{0}; + int m_height{0}; + int m_stride{0}; + unsigned char* m_buffer{nullptr}; +}; diff --git a/xbmc/utils/ISerializable.h b/xbmc/utils/ISerializable.h new file mode 100644 index 0000000..12f0fba --- /dev/null +++ b/xbmc/utils/ISerializable.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +class CVariant; + +class ISerializable +{ +protected: + /* make sure nobody deletes a pointer to this class */ + ~ISerializable() = default; + + public: + virtual void Serialize(CVariant& value) const = 0; +}; diff --git a/xbmc/utils/ISortable.h b/xbmc/utils/ISortable.h new file mode 100644 index 0000000..ea4a0d3 --- /dev/null +++ b/xbmc/utils/ISortable.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "SortUtils.h" + +#include + +class ISortable +{ +protected: + /* make sure nobody deletes a pointer to this class */ + ~ISortable() = default; + +public: + virtual void ToSortable(SortItem& sortable, Field field) const = 0; +}; diff --git a/xbmc/utils/IXmlDeserializable.h b/xbmc/utils/IXmlDeserializable.h new file mode 100644 index 0000000..edeec25 --- /dev/null +++ b/xbmc/utils/IXmlDeserializable.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +class TiXmlNode; + +class IXmlDeserializable +{ +public: + virtual ~IXmlDeserializable() = default; + + virtual bool Deserialize(const TiXmlNode *node) = 0; +}; diff --git a/xbmc/utils/InfoLoader.cpp b/xbmc/utils/InfoLoader.cpp new file mode 100644 index 0000000..cef6b70 --- /dev/null +++ b/xbmc/utils/InfoLoader.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "InfoLoader.h" + +#include "JobManager.h" +#include "TimeUtils.h" +#include "guilib/LocalizeStrings.h" + +CInfoLoader::CInfoLoader(unsigned int timeToRefresh) +{ + m_refreshTime = 0; + m_timeToRefresh = timeToRefresh; + m_busy = false; +} + +CInfoLoader::~CInfoLoader() = default; + +void CInfoLoader::OnJobComplete(unsigned int jobID, bool success, CJob *job) +{ + m_refreshTime = CTimeUtils::GetFrameTime() + m_timeToRefresh; + m_busy = false; +} + +std::string CInfoLoader::GetInfo(int info) +{ + // Refresh if need be + if (m_refreshTime < CTimeUtils::GetFrameTime() && !m_busy) + { // queue up the job + m_busy = true; + CJobManager::GetInstance().AddJob(GetJob(), this); + } + if (m_busy && CTimeUtils::GetFrameTime() - m_refreshTime > 1000) + { + return BusyInfo(info); + } + return TranslateInfo(info); +} + +std::string CInfoLoader::BusyInfo(int info) const +{ + return g_localizeStrings.Get(503); +} + +std::string CInfoLoader::TranslateInfo(int info) const +{ + return ""; +} + +void CInfoLoader::Refresh() +{ + m_refreshTime = CTimeUtils::GetFrameTime(); +} + diff --git a/xbmc/utils/InfoLoader.h b/xbmc/utils/InfoLoader.h new file mode 100644 index 0000000..720f0d7 --- /dev/null +++ b/xbmc/utils/InfoLoader.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "Job.h" + +#include + +class CInfoLoader : public IJobCallback +{ +public: + explicit CInfoLoader(unsigned int timeToRefresh = 5 * 60 * 1000); + ~CInfoLoader() override; + + std::string GetInfo(int info); + void Refresh(); + + void OnJobComplete(unsigned int jobID, bool success, CJob *job) override; +protected: + virtual CJob *GetJob() const=0; + virtual std::string TranslateInfo(int info) const; + virtual std::string BusyInfo(int info) const; +private: + unsigned int m_refreshTime; + unsigned int m_timeToRefresh; + bool m_busy; +}; diff --git a/xbmc/utils/JSONVariantParser.cpp b/xbmc/utils/JSONVariantParser.cpp new file mode 100644 index 0000000..f003cdf --- /dev/null +++ b/xbmc/utils/JSONVariantParser.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "JSONVariantParser.h" + +#include + +class CJSONVariantParserHandler +{ +public: + explicit CJSONVariantParserHandler(CVariant& parsedObject); + + bool Null(); + bool Bool(bool b); + bool Int(int i); + bool Uint(unsigned u); + bool Int64(int64_t i); + bool Uint64(uint64_t u); + bool Double(double d); + bool RawNumber(const char* str, rapidjson::SizeType length, bool copy); + bool String(const char* str, rapidjson::SizeType length, bool copy); + bool StartObject(); + bool Key(const char* str, rapidjson::SizeType length, bool copy); + bool EndObject(rapidjson::SizeType memberCount); + bool StartArray(); + bool EndArray(rapidjson::SizeType elementCount); + +private: + template + bool Primitive(TArgs... args) + { + PushObject(CVariant(std::forward(args)...)); + PopObject(); + + return true; + } + + void PushObject(CVariant variant); + void PopObject(); + + CVariant& m_parsedObject; + std::vector m_parse; + std::string m_key; + + enum class PARSE_STATUS + { + Variable, + Array, + Object + }; + PARSE_STATUS m_status; +}; + +CJSONVariantParserHandler::CJSONVariantParserHandler(CVariant& parsedObject) + : m_parsedObject(parsedObject), + m_parse(), + m_key(), + m_status(PARSE_STATUS::Variable) +{ } + +bool CJSONVariantParserHandler::Null() +{ + PushObject(CVariant::ConstNullVariant); + PopObject(); + + return true; +} + +bool CJSONVariantParserHandler::Bool(bool b) +{ + return Primitive(b); +} + +bool CJSONVariantParserHandler::Int(int i) +{ + return Primitive(i); +} + +bool CJSONVariantParserHandler::Uint(unsigned u) +{ + return Primitive(u); +} + +bool CJSONVariantParserHandler::Int64(int64_t i) +{ + return Primitive(i); +} + +bool CJSONVariantParserHandler::Uint64(uint64_t u) +{ + return Primitive(u); +} + +bool CJSONVariantParserHandler::Double(double d) +{ + return Primitive(d); +} + +bool CJSONVariantParserHandler::RawNumber(const char* str, rapidjson::SizeType length, bool copy) +{ + return Primitive(str, length); +} + +bool CJSONVariantParserHandler::String(const char* str, rapidjson::SizeType length, bool copy) +{ + return Primitive(str, length); +} + +bool CJSONVariantParserHandler::StartObject() +{ + PushObject(CVariant::VariantTypeObject); + + return true; +} + +bool CJSONVariantParserHandler::Key(const char* str, rapidjson::SizeType length, bool copy) +{ + m_key = std::string(str, 0, length); + + return true; +} + +bool CJSONVariantParserHandler::EndObject(rapidjson::SizeType memberCount) +{ + PopObject(); + + return true; +} + +bool CJSONVariantParserHandler::StartArray() +{ + PushObject(CVariant::VariantTypeArray); + + return true; +} + +bool CJSONVariantParserHandler::EndArray(rapidjson::SizeType elementCount) +{ + PopObject(); + + return true; +} + +void CJSONVariantParserHandler::PushObject(CVariant variant) +{ + if (m_status == PARSE_STATUS::Object) + { + (*m_parse[m_parse.size() - 1])[m_key] = variant; + m_parse.push_back(&(*m_parse[m_parse.size() - 1])[m_key]); + } + else if (m_status == PARSE_STATUS::Array) + { + CVariant *temp = m_parse[m_parse.size() - 1]; + temp->push_back(variant); + m_parse.push_back(&(*temp)[temp->size() - 1]); + } + else if (m_parse.empty()) + m_parse.push_back(new CVariant(variant)); + + if (variant.isObject()) + m_status = PARSE_STATUS::Object; + else if (variant.isArray()) + m_status = PARSE_STATUS::Array; + else + m_status = PARSE_STATUS::Variable; +} + +void CJSONVariantParserHandler::PopObject() +{ + CVariant *variant = m_parse[m_parse.size() - 1]; + m_parse.pop_back(); + + if (!m_parse.empty()) + { + variant = m_parse[m_parse.size() - 1]; + if (variant->isObject()) + m_status = PARSE_STATUS::Object; + else if (variant->isArray()) + m_status = PARSE_STATUS::Array; + else + m_status = PARSE_STATUS::Variable; + } + else + { + m_parsedObject = *variant; + delete variant; + + m_status = PARSE_STATUS::Variable; + } +} + +bool CJSONVariantParser::Parse(const char* json, CVariant& data) +{ + if (json == nullptr) + return false; + + rapidjson::Reader reader; + rapidjson::StringStream stringStream(json); + + CJSONVariantParserHandler handler(data); + // use kParseIterativeFlag to eliminate possible stack overflow + // from json parsing via reentrant calls + if (reader.Parse(stringStream, handler)) + return true; + + return false; +} + +bool CJSONVariantParser::Parse(const std::string& json, CVariant& data) +{ + return Parse(json.c_str(), data); +} diff --git a/xbmc/utils/JSONVariantParser.h b/xbmc/utils/JSONVariantParser.h new file mode 100644 index 0000000..17cfb61 --- /dev/null +++ b/xbmc/utils/JSONVariantParser.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/Variant.h" + +#include + +class CJSONVariantParser +{ +public: + CJSONVariantParser() = delete; + + static bool Parse(const char* json, CVariant& data); + static bool Parse(const std::string& json, CVariant& data); +}; diff --git a/xbmc/utils/JSONVariantWriter.cpp b/xbmc/utils/JSONVariantWriter.cpp new file mode 100644 index 0000000..b48a8ae --- /dev/null +++ b/xbmc/utils/JSONVariantWriter.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "JSONVariantWriter.h" + +#include "utils/Variant.h" + +#include +#include +#include + +template +bool InternalWrite(TWriter& writer, const CVariant &value) +{ + switch (value.type()) + { + case CVariant::VariantTypeInteger: + return writer.Int64(value.asInteger()); + + case CVariant::VariantTypeUnsignedInteger: + return writer.Uint64(value.asUnsignedInteger()); + + case CVariant::VariantTypeDouble: + return writer.Double(value.asDouble()); + + case CVariant::VariantTypeBoolean: + return writer.Bool(value.asBoolean()); + + case CVariant::VariantTypeString: + return writer.String(value.c_str(), value.size()); + + case CVariant::VariantTypeArray: + if (!writer.StartArray()) + return false; + + for (CVariant::const_iterator_array itr = value.begin_array(); itr != value.end_array(); ++itr) + { + if (!InternalWrite(writer, *itr)) + return false; + } + + return writer.EndArray(value.size()); + + case CVariant::VariantTypeObject: + if (!writer.StartObject()) + return false; + + for (CVariant::const_iterator_map itr = value.begin_map(); itr != value.end_map(); ++itr) + { + if (!writer.Key(itr->first.c_str()) || + !InternalWrite(writer, itr->second)) + return false; + } + + return writer.EndObject(value.size()); + + case CVariant::VariantTypeConstNull: + case CVariant::VariantTypeNull: + default: + return writer.Null(); + } + + return false; +} + +bool CJSONVariantWriter::Write(const CVariant &value, std::string& output, bool compact) +{ + rapidjson::StringBuffer stringBuffer; + if (compact) + { + rapidjson::Writer writer(stringBuffer); + + if (!InternalWrite(writer, value) || !writer.IsComplete()) + return false; + } + else + { + rapidjson::PrettyWriter writer(stringBuffer); + writer.SetIndent('\t', 1); + + if (!InternalWrite(writer, value) || !writer.IsComplete()) + return false; + } + + output = stringBuffer.GetString(); + return true; +} diff --git a/xbmc/utils/JSONVariantWriter.h b/xbmc/utils/JSONVariantWriter.h new file mode 100644 index 0000000..e1f5bd6 --- /dev/null +++ b/xbmc/utils/JSONVariantWriter.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +class CVariant; + +class CJSONVariantWriter +{ +public: + CJSONVariantWriter() = delete; + + static bool Write(const CVariant &value, std::string& output, bool compact); +}; diff --git a/xbmc/utils/Job.h b/xbmc/utils/Job.h new file mode 100644 index 0000000..8acdd4e --- /dev/null +++ b/xbmc/utils/Job.h @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +class CJob; + +#include + +#define kJobTypeMediaFlags "mediaflags" +#define kJobTypeCacheImage "cacheimage" +#define kJobTypeDDSCompress "ddscompress" + +/*! + \ingroup jobs + \brief Callback interface for asynchronous jobs. + + Used by clients of the CJobManager to receive progress and completion notification of jobs. + Clients of small jobs wishing to perform actions on job completion should implement the + IJobCallback::OnJobComplete() function. Clients of larger jobs may choose to implement the + IJobCallback::OnJobProgress() function in order to be kept informed of progress. + + \sa CJobManager and CJob + */ +class IJobCallback +{ +public: + /*! + \brief Destructor for job call back objects. + + \sa CJobManager and CJob + */ + virtual ~IJobCallback() = default; + + /*! + \brief The callback used when a job completes. + + OnJobComplete is called at the completion of the job's DoWork() function, and is used + to return information to the caller on the result of the job. On returning form this function + the CJobManager will destroy this job. + + \param jobID the unique id of the job (as retrieved from CJobManager::AddJob) + \param success the result from the DoWork call + \param job the job that has been processed. The job will be destroyed after this function returns + \sa CJobManager and CJob + */ + virtual void OnJobComplete(unsigned int jobID, bool success, CJob *job)=0; + + /*! + \brief An optional callback function that a job may call while processing. + + OnJobProgress may be called periodically by a job during it's DoWork() function. It is used + by the job to report on progress. + + \param jobID the unique id of the job (as retrieved from CJobManager::AddJob) + \param progress the current progress of the job, out of total. + \param total the total amount of work to be processed. + \param job the job that has been processed. + \sa CJobManager and CJob + */ + virtual void OnJobProgress(unsigned int jobID, unsigned int progress, unsigned int total, const CJob *job) {}; +}; + +class CJobManager; + +/*! + \ingroup jobs + \brief Base class for jobs that are executed asynchronously. + + Clients of the CJobManager should subclass CJob and provide the DoWork() function. Data should be + passed to the job on creation, and any data sharing between the job and the client should be kept to within + the callback functions if possible, and guarded with critical sections as appropriate. + + Jobs typically fall into two groups: small jobs that perform a single function, and larger jobs that perform a + sequence of functions. Clients with small jobs should implement the IJobCallback::OnJobComplete() callback to receive results. + Clients with larger jobs may wish to implement both the IJobCallback::OnJobComplete() and IJobCallback::OnJobProgress() + callbacks to receive updates. Jobs may be cancelled at any point by the client via CJobManager::CancelJob(), however + effort should be taken to ensure that any callbacks and cancellation is suitably guarded against simultaneous thread access. + + Handling cancellation of jobs within the OnJobProgress callback is a threadsafe operation, as all execution is + then in the Job thread. + + \sa CJobManager and IJobCallback + */ +class CJob +{ +public: + /*! + \brief Priority levels for jobs, specified by clients when adding jobs to the CJobManager. + \sa CJobManager + */ + enum PRIORITY { + PRIORITY_LOW_PAUSABLE = 0, + PRIORITY_LOW, + PRIORITY_NORMAL, + PRIORITY_HIGH, + PRIORITY_DEDICATED, // will create a new worker if no worker is available at queue time + }; + CJob() { m_callback = NULL; }; + + /*! + \brief Destructor for job objects. + + Jobs are destroyed by the CJobManager after the OnJobComplete() callback is complete. + CJob subclasses should therefore supply a virtual destructor to cleanup any memory allocated by + complete or cancelled jobs. + + \sa CJobManager + */ + virtual ~CJob() = default; + + /*! + \brief Main workhorse function of CJob instances + + All CJob subclasses must implement this function, performing all processing. Once this function + is complete, the OnJobComplete() callback is called, and the job is then destroyed. + + \sa CJobManager, IJobCallback::OnJobComplete() + */ + virtual bool DoWork() = 0; // function to do the work + + /*! + \brief Function that returns the type of job. + + CJob subclasses may optionally implement this function to specify the type of job. + This is useful for the CJobManager::AddLIFOJob() routine, which preempts similar jobs + with the new job. + + \return a unique character string describing the job. + \sa CJobManager + */ + virtual const char *GetType() const { return ""; }; + + virtual bool operator==(const CJob* job) const + { + return false; + } + + /*! + \brief Function for longer jobs to report progress and check whether they have been cancelled. + + Jobs that contain loops that may take time should check this routine each iteration of the loop, + both to (optionally) report progress, and to check for cancellation. + + \param progress the amount of the job performed, out of total. + \param total the total amount of processing to be performed + \return if true, the job has been asked to cancel. + + \sa IJobCallback::OnJobProgress() + */ + virtual bool ShouldCancel(unsigned int progress, unsigned int total) const; +private: + friend class CJobManager; + CJobManager *m_callback; +}; diff --git a/xbmc/utils/JobManager.cpp b/xbmc/utils/JobManager.cpp new file mode 100644 index 0000000..3c8e04b --- /dev/null +++ b/xbmc/utils/JobManager.cpp @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "JobManager.h" + +#include "threads/SingleLock.h" +#include "utils/XTimeUtils.h" +#include "utils/log.h" + +#include +#include +#include + +bool CJob::ShouldCancel(unsigned int progress, unsigned int total) const +{ + if (m_callback) + return m_callback->OnJobProgress(progress, total, this); + return false; +} + +CJobWorker::CJobWorker(CJobManager *manager) : CThread("JobWorker") +{ + m_jobManager = manager; + Create(true); // start work immediately, and kill ourselves when we're done +} + +CJobWorker::~CJobWorker() +{ + // while we should already be removed from the job manager, if an exception + // occurs during processing that we haven't caught, we may skip over that step. + // Thus, before we go out of scope, ensure the job manager knows we're gone. + m_jobManager->RemoveWorker(this); + if(!IsAutoDelete()) + StopThread(); +} + +void CJobWorker::Process() +{ + SetPriority( GetMinPriority() ); + while (true) + { + // request an item from our manager (this call is blocking) + CJob *job = m_jobManager->GetNextJob(this); + if (!job) + break; + + bool success = false; + try + { + success = job->DoWork(); + } + catch (...) + { + CLog::Log(LOGERROR, "%s error processing job %s", __FUNCTION__, job->GetType()); + } + m_jobManager->OnJobComplete(success, job); + } +} + +void CJobQueue::CJobPointer::CancelJob() +{ + CJobManager::GetInstance().CancelJob(m_id); + m_id = 0; +} + +CJobQueue::CJobQueue(bool lifo, unsigned int jobsAtOnce, CJob::PRIORITY priority) +: m_jobsAtOnce(jobsAtOnce), m_priority(priority), m_lifo(lifo) +{ +} + +CJobQueue::~CJobQueue() +{ + CancelJobs(); +} + +void CJobQueue::OnJobComplete(unsigned int jobID, bool success, CJob *job) +{ + CSingleLock lock(m_section); + // check if this job is in our processing list + Processing::iterator i = find(m_processing.begin(), m_processing.end(), job); + if (i != m_processing.end()) + m_processing.erase(i); + // request a new job be queued + QueueNextJob(); +} + +void CJobQueue::CancelJob(const CJob *job) +{ + CSingleLock lock(m_section); + Processing::iterator i = find(m_processing.begin(), m_processing.end(), job); + if (i != m_processing.end()) + { + i->CancelJob(); + m_processing.erase(i); + return; + } + Queue::iterator j = find(m_jobQueue.begin(), m_jobQueue.end(), job); + if (j != m_jobQueue.end()) + { + j->FreeJob(); + m_jobQueue.erase(j); + } +} + +bool CJobQueue::AddJob(CJob *job) +{ + CSingleLock lock(m_section); + // check if we have this job already. If so, we're done. + if (find(m_jobQueue.begin(), m_jobQueue.end(), job) != m_jobQueue.end() || + find(m_processing.begin(), m_processing.end(), job) != m_processing.end()) + { + delete job; + return false; + } + + if (m_lifo) + m_jobQueue.push_back(CJobPointer(job)); + else + m_jobQueue.push_front(CJobPointer(job)); + QueueNextJob(); + + return true; +} + +void CJobQueue::QueueNextJob() +{ + CSingleLock lock(m_section); + if (m_jobQueue.size() && m_processing.size() < m_jobsAtOnce) + { + CJobPointer &job = m_jobQueue.back(); + job.m_id = CJobManager::GetInstance().AddJob(job.m_job, this, m_priority); + m_processing.push_back(job); + m_jobQueue.pop_back(); + } +} + +void CJobQueue::CancelJobs() +{ + CSingleLock lock(m_section); + for_each(m_processing.begin(), m_processing.end(), [](CJobPointer& jp) { jp.CancelJob(); }); + for_each(m_jobQueue.begin(), m_jobQueue.end(), [](CJobPointer& jp) { jp.FreeJob(); }); + m_jobQueue.clear(); + m_processing.clear(); +} + +bool CJobQueue::IsProcessing() const +{ + return CJobManager::GetInstance().m_running && (!m_processing.empty() || !m_jobQueue.empty()); +} + +bool CJobQueue::QueueEmpty() const +{ + CSingleLock lock(m_section); + return m_jobQueue.empty(); +} + +CJobManager &CJobManager::GetInstance() +{ + static CJobManager sJobManager; + return sJobManager; +} + +CJobManager::CJobManager() +{ + m_jobCounter = 0; + m_running = true; + m_pauseJobs = false; +} + +void CJobManager::Restart() +{ + CSingleLock lock(m_section); + + if (m_running) + throw std::logic_error("CJobManager already running"); + m_running = true; +} + +void CJobManager::CancelJobs() +{ + CSingleLock lock(m_section); + m_running = false; + + // clear any pending jobs + for (unsigned int priority = CJob::PRIORITY_LOW_PAUSABLE; priority <= CJob::PRIORITY_DEDICATED; ++priority) + { + for_each(m_jobQueue[priority].begin(), m_jobQueue[priority].end(), [](CWorkItem& wi) { wi.FreeJob(); }); + m_jobQueue[priority].clear(); + } + + // cancel any callbacks on jobs still processing + for_each(m_processing.begin(), m_processing.end(), [](CWorkItem& wi) { wi.Cancel(); }); + + // tell our workers to finish + while (m_workers.size()) + { + lock.Leave(); + m_jobEvent.Set(); + std::this_thread::yield(); // yield after setting the event to give the workers some time to die + lock.Enter(); + } +} + +unsigned int CJobManager::AddJob(CJob *job, IJobCallback *callback, CJob::PRIORITY priority) +{ + CSingleLock lock(m_section); + + if (!m_running) + return 0; + + // increment the job counter, ensuring 0 (invalid job) is never hit + m_jobCounter++; + if (m_jobCounter == 0) + m_jobCounter++; + + // create a work item for this job + CWorkItem work(job, m_jobCounter, priority, callback); + m_jobQueue[priority].push_back(work); + + StartWorkers(priority); + return work.m_id; +} + +void CJobManager::CancelJob(unsigned int jobID) +{ + CSingleLock lock(m_section); + + // check whether we have this job in the queue + for (unsigned int priority = CJob::PRIORITY_LOW_PAUSABLE; priority <= CJob::PRIORITY_DEDICATED; ++priority) + { + JobQueue::iterator i = find(m_jobQueue[priority].begin(), m_jobQueue[priority].end(), jobID); + if (i != m_jobQueue[priority].end()) + { + delete i->m_job; + m_jobQueue[priority].erase(i); + return; + } + } + // or if we're processing it + Processing::iterator it = find(m_processing.begin(), m_processing.end(), jobID); + if (it != m_processing.end()) + it->m_callback = NULL; // job is in progress, so only thing to do is to remove callback +} + +void CJobManager::StartWorkers(CJob::PRIORITY priority) +{ + CSingleLock lock(m_section); + + // check how many free threads we have + if (m_processing.size() >= GetMaxWorkers(priority)) + return; + + // do we have any sleeping threads? + if (m_processing.size() < m_workers.size()) + { + m_jobEvent.Set(); + return; + } + + // everyone is busy - we need more workers + m_workers.push_back(new CJobWorker(this)); +} + +CJob *CJobManager::PopJob() +{ + CSingleLock lock(m_section); + for (int priority = CJob::PRIORITY_DEDICATED; priority >= CJob::PRIORITY_LOW_PAUSABLE; --priority) + { + // Check whether we're pausing pausable jobs + if (priority == CJob::PRIORITY_LOW_PAUSABLE && m_pauseJobs) + continue; + + if (m_jobQueue[priority].size() && m_processing.size() < GetMaxWorkers(CJob::PRIORITY(priority))) + { + // pop the job off the queue + CWorkItem job = m_jobQueue[priority].front(); + m_jobQueue[priority].pop_front(); + + // add to the processing vector + m_processing.push_back(job); + job.m_job->m_callback = this; + return job.m_job; + } + } + return NULL; +} + +void CJobManager::PauseJobs() +{ + CSingleLock lock(m_section); + m_pauseJobs = true; +} + +void CJobManager::UnPauseJobs() +{ + CSingleLock lock(m_section); + m_pauseJobs = false; +} + +bool CJobManager::IsProcessing(const CJob::PRIORITY &priority) const +{ + CSingleLock lock(m_section); + + if (m_pauseJobs) + return false; + + for(Processing::const_iterator it = m_processing.begin(); it < m_processing.end(); ++it) + { + if (priority == it->m_priority) + return true; + } + return false; +} + +int CJobManager::IsProcessing(const std::string &type) const +{ + int jobsMatched = 0; + CSingleLock lock(m_section); + + if (m_pauseJobs) + return 0; + + for(Processing::const_iterator it = m_processing.begin(); it < m_processing.end(); ++it) + { + if (type == std::string(it->m_job->GetType())) + jobsMatched++; + } + return jobsMatched; +} + +CJob *CJobManager::GetNextJob(const CJobWorker *worker) +{ + CSingleLock lock(m_section); + while (m_running) + { + // grab a job off the queue if we have one + CJob *job = PopJob(); + if (job) + return job; + // no jobs are left - sleep for 30 seconds to allow new jobs to come in + lock.Leave(); + bool newJob = m_jobEvent.WaitMSec(30000); + lock.Enter(); + if (!newJob) + break; + } + // ensure no jobs have come in during the period after + // timeout and before we held the lock + CJob *job = PopJob(); + if (job) + return job; + // have no jobs + RemoveWorker(worker); + return NULL; +} + +bool CJobManager::OnJobProgress(unsigned int progress, unsigned int total, const CJob *job) const +{ + CSingleLock lock(m_section); + // find the job in the processing queue, and check whether it's cancelled (no callback) + Processing::const_iterator i = find(m_processing.begin(), m_processing.end(), job); + if (i != m_processing.end()) + { + CWorkItem item(*i); + lock.Leave(); // leave section prior to call + if (item.m_callback) + { + item.m_callback->OnJobProgress(item.m_id, progress, total, job); + return false; + } + } + return true; // couldn't find the job, or it's been cancelled +} + +void CJobManager::OnJobComplete(bool success, CJob *job) +{ + CSingleLock lock(m_section); + // remove the job from the processing queue + Processing::iterator i = find(m_processing.begin(), m_processing.end(), job); + if (i != m_processing.end()) + { + // tell any listeners we're done with the job, then delete it + CWorkItem item(*i); + lock.Leave(); + try + { + if (item.m_callback) + item.m_callback->OnJobComplete(item.m_id, success, item.m_job); + } + catch (...) + { + CLog::Log(LOGERROR, "%s error processing job %s", __FUNCTION__, item.m_job->GetType()); + } + lock.Enter(); + Processing::iterator j = find(m_processing.begin(), m_processing.end(), job); + if (j != m_processing.end()) + m_processing.erase(j); + lock.Leave(); + item.FreeJob(); + } +} + +void CJobManager::RemoveWorker(const CJobWorker *worker) +{ + CSingleLock lock(m_section); + // remove our worker + Workers::iterator i = find(m_workers.begin(), m_workers.end(), worker); + if (i != m_workers.end()) + m_workers.erase(i); // workers auto-delete +} + +unsigned int CJobManager::GetMaxWorkers(CJob::PRIORITY priority) +{ + static const unsigned int max_workers = 5; + if (priority == CJob::PRIORITY_DEDICATED) + return 10000; // A large number.. + return max_workers - (CJob::PRIORITY_HIGH - priority); +} diff --git a/xbmc/utils/JobManager.h b/xbmc/utils/JobManager.h new file mode 100644 index 0000000..ac4aa4e --- /dev/null +++ b/xbmc/utils/JobManager.h @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "Job.h" +#include "threads/CriticalSection.h" +#include "threads/Thread.h" + +#include +#include +#include + +class CJobManager; + +class CJobWorker : public CThread +{ +public: + explicit CJobWorker(CJobManager *manager); + ~CJobWorker() override; + + void Process() override; +private: + CJobManager *m_jobManager; +}; + +template +class CLambdaJob : public CJob +{ +public: + CLambdaJob(F&& f) : m_f(std::forward(f)) {}; + bool DoWork() override + { + m_f(); + return true; + } + bool operator==(const CJob *job) const override + { + return this == job; + }; +private: + F m_f; +}; + +/*! + \ingroup jobs + \brief Job Queue class to handle a queue of unique jobs to be processed sequentially + + Holds a queue of jobs to be processed sequentially, either first in,first out + or last in, first out. Jobs are unique, so queueing multiple copies of the same job + (based on the CJob::operator==) will not add additional jobs. + + Classes should subclass this class and override OnJobCallback should they require + information from the job. + + \sa CJob and IJobCallback + */ +class CJobQueue: public IJobCallback +{ + class CJobPointer + { + public: + explicit CJobPointer(CJob *job) + { + m_job = job; + m_id = 0; + }; + void CancelJob(); + void FreeJob() + { + delete m_job; + m_job = NULL; + }; + bool operator==(const CJob *job) const + { + if (m_job) + return *m_job == job; + return false; + }; + CJob *m_job; + unsigned int m_id; + }; +public: + /*! + \brief CJobQueue constructor + \param lifo whether the queue should be processed last in first out or first in first out. Defaults to false (first in first out) + \param jobsAtOnce number of jobs at once to process. Defaults to 1. + \param priority priority of this queue. + \sa CJob + */ + CJobQueue(bool lifo = false, unsigned int jobsAtOnce = 1, CJob::PRIORITY priority = CJob::PRIORITY_LOW); + + /*! + \brief CJobQueue destructor + Cancels any in-process jobs, and destroys the job queue. + \sa CJob + */ + ~CJobQueue() override; + + /*! + \brief Add a job to the queue + On completion of the job (or destruction of the job queue) the CJob object will be destroyed. + \param job a pointer to the job to add. The job should be subclassed from CJob. + \sa CJob + */ + bool AddJob(CJob *job); + + /*! + \brief Add a function f to this job queue + */ + template + void Submit(F&& f) + { + AddJob(new CLambdaJob(std::forward(f))); + } + + /*! + \brief Cancel a job in the queue + Cancels a job in the queue. Any job currently being processed may complete after this + call has completed, but OnJobComplete will not be performed. If the job is only queued + then it will be removed from the queue and deleted. + \param job a pointer to the job to cancel. The job should be subclassed from CJob. + \sa CJob + */ + void CancelJob(const CJob *job); + + /*! + \brief Cancel all jobs in the queue + Removes all jobs from the queue. Any job currently being processed may complete after this + call has completed, but OnJobComplete will not be performed. + \sa CJob + */ + void CancelJobs(); + + /*! + \brief Check whether the queue is processing a job + */ + bool IsProcessing() const; + + /*! + \brief The callback used when a job completes. + + OnJobComplete is called at the completion of the CJob::DoWork function, and is used + to return information to the caller on the result of the job. On returning from this function + the CJobManager will destroy this job. + + Subclasses should override this function if they wish to transfer information from the job prior + to it's deletion. They must then call this base class function, which will move on to the next + job. + + \sa CJobManager, IJobCallback and CJob + */ + void OnJobComplete(unsigned int jobID, bool success, CJob *job) override; + +protected: + /*! + \brief Returns if we still have jobs waiting to be processed + NOTE: This function does not take into account the jobs that are currently processing + */ + bool QueueEmpty() const; + +private: + void QueueNextJob(); + + typedef std::deque Queue; + typedef std::vector Processing; + Queue m_jobQueue; + Processing m_processing; + + unsigned int m_jobsAtOnce; + CJob::PRIORITY m_priority; + mutable CCriticalSection m_section; + bool m_lifo; +}; + +/*! + \ingroup jobs + \brief Job Manager class for scheduling asynchronous jobs. + + Controls asynchronous job execution, by allowing clients to add and cancel jobs. + Should be accessed via CJobManager::GetInstance(). Jobs are allocated based on + priority levels. Lower priority jobs are executed only if there are sufficient + spare worker threads free to allow for higher priority jobs that may arise. + + \sa CJob and IJobCallback + */ +class CJobManager final +{ + class CWorkItem + { + public: + CWorkItem(CJob *job, unsigned int id, CJob::PRIORITY priority, IJobCallback *callback) + { + m_job = job; + m_id = id; + m_callback = callback; + m_priority = priority; + } + bool operator==(unsigned int jobID) const + { + return m_id == jobID; + }; + bool operator==(const CJob *job) const + { + return m_job == job; + }; + void FreeJob() + { + delete m_job; + m_job = NULL; + }; + void Cancel() + { + m_callback = NULL; + }; + CJob *m_job; + unsigned int m_id; + IJobCallback *m_callback; + CJob::PRIORITY m_priority; + }; + +public: + /*! + \brief The only way through which the global instance of the CJobManager should be accessed. + \return the global instance. + */ + static CJobManager &GetInstance(); + + /*! + \brief Add a job to the threaded job manager. + \param job a pointer to the job to add. The job should be subclassed from CJob + \param callback a pointer to an IJobCallback instance to receive job progress and completion notices. + \param priority the priority that this job should run at. + \return a unique identifier for this job, to be used with other interaction + \sa CJob, IJobCallback, CancelJob() + */ + unsigned int AddJob(CJob *job, IJobCallback *callback, CJob::PRIORITY priority = CJob::PRIORITY_LOW); + + /*! + \brief Add a function f to this job manager for asynchronously execution. + */ + template + void Submit(F&& f, CJob::PRIORITY priority = CJob::PRIORITY_LOW) + { + AddJob(new CLambdaJob(std::forward(f)), nullptr, priority); + } + + /*! + \brief Add a function f to this job manager for asynchronously execution. + */ + template + void Submit(F&& f, IJobCallback *callback, CJob::PRIORITY priority = CJob::PRIORITY_LOW) + { + AddJob(new CLambdaJob(std::forward(f)), callback, priority); + } + + /*! + \brief Cancel a job with the given id. + \param jobID the id of the job to cancel, retrieved previously from AddJob() + \sa AddJob() + */ + void CancelJob(unsigned int jobID); + + /*! + \brief Cancel all remaining jobs, preparing for shutdown + Should be called prior to destroying any objects that may be being used as callbacks + \sa CancelJob(), AddJob() + */ + void CancelJobs(); + + /*! + \brief Re-start accepting jobs again + Called after calling CancelJobs() to allow this manager to accept more jobs + \throws std::logic_error if the manager was not previously cancelled + \sa CancelJobs() + */ + void Restart(); + + /*! + \brief Checks to see if any jobs of a specific type are currently processing. + \param type Job type to search for + \return Number of matching jobs + */ + int IsProcessing(const std::string &type) const; + + /*! + \brief Suspends queueing of jobs with priority PRIORITY_LOW_PAUSABLE until unpaused + Useful to (for ex) stop queuing thumb jobs during video start/playback. + Does not affect currently processing jobs, use IsProcessing to see if any need to be waited on + \sa UnPauseJobs() + */ + void PauseJobs(); + + /*! + \brief Resumes queueing of (previously paused) jobs with priority PRIORITY_LOW_PAUSABLE + \sa PauseJobs() + */ + void UnPauseJobs(); + + /*! + \brief Checks to see if any jobs with specific priority are currently processing. + \param priority to search for + \return true if processing jobs, else returns false + */ + bool IsProcessing(const CJob::PRIORITY &priority) const; + +protected: + friend class CJobWorker; + friend class CJob; + friend class CJobQueue; + + /*! + \brief Get a new job to process. Blocks until a new job is available, or a timeout has occurred. + \param worker a pointer to the current CJobWorker instance requesting a job. + \sa CJob + */ + CJob *GetNextJob(const CJobWorker *worker); + + /*! + \brief Callback from CJobWorker after a job has completed. + Calls IJobCallback::OnJobComplete(), and then destroys job. + \param job a pointer to the calling subclassed CJob instance. + \param success the result from the DoWork call + \sa IJobCallback, CJob + */ + void OnJobComplete(bool success, CJob *job); + + /*! + \brief Callback from CJob to report progress and check for cancellation. + Checks for cancellation, and calls IJobCallback::OnJobProgress(). + \param progress amount of processing performed to date, out of total. + \param total total amount of processing. + \param job pointer to the calling subclassed CJob instance. + \return true if the job has been cancelled, else returns false. + \sa IJobCallback, CJob + */ + bool OnJobProgress(unsigned int progress, unsigned int total, const CJob *job) const; + +private: + // private construction, and no assignments; use the provided singleton methods + CJobManager(); + CJobManager(const CJobManager&) = delete; + CJobManager const& operator=(CJobManager const&) = delete; + + /*! \brief Pop a job off the job queue and add to the processing queue ready to process + \return the job to process, NULL if no jobs are available + */ + CJob *PopJob(); + + void StartWorkers(CJob::PRIORITY priority); + void RemoveWorker(const CJobWorker *worker); + static unsigned int GetMaxWorkers(CJob::PRIORITY priority); + + unsigned int m_jobCounter; + + typedef std::deque JobQueue; + typedef std::vector Processing; + typedef std::vector Workers; + + JobQueue m_jobQueue[CJob::PRIORITY_DEDICATED + 1]; + bool m_pauseJobs; + Processing m_processing; + Workers m_workers; + + mutable CCriticalSection m_section; + CEvent m_jobEvent; + bool m_running; +}; diff --git a/xbmc/utils/LabelFormatter.cpp b/xbmc/utils/LabelFormatter.cpp new file mode 100644 index 0000000..55eeb4f --- /dev/null +++ b/xbmc/utils/LabelFormatter.cpp @@ -0,0 +1,479 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "LabelFormatter.h" + +#include "FileItem.h" +#include "RegExp.h" +#include "ServiceBroker.h" +#include "StringUtils.h" +#include "URIUtils.h" +#include "Util.h" +#include "Variant.h" +#include "guilib/LocalizeStrings.h" +#include "music/tags/MusicInfoTag.h" +#include "pictures/PictureInfoTag.h" +#include "settings/AdvancedSettings.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "video/VideoInfoTag.h" + +#include +#include +#include + +using namespace MUSIC_INFO; + +/* LabelFormatter + * ============== + * + * The purpose of this class is to parse a mask string of the form + * + * [%N. ][%T] - [%A][ (%Y)] + * + * and provide methods to format up a CFileItem's label(s). + * + * The %N/%A/%B masks are replaced with the corresponding metadata (if available). + * + * Square brackets are treated as a metadata block. Anything inside the block other + * than the metadata mask is treated as either a prefix or postfix to the metadata. This + * information is only included in the formatted string when the metadata is non-empty. + * + * Any metadata tags not enclosed with square brackets are treated as if it were immediately + * enclosed - i.e. with no prefix or postfix. + * + * The special characters %, [, and ] can be produced using %%, %[, and %] respectively. + * + * Any static text outside of the metadata blocks is only shown if the blocks on either side + * (or just one side in the case of an end) are both non-empty. + * + * Examples (using the above expression): + * + * Track Title Artist Year Resulting Label + * ----- ----- ------ ---- --------------- + * 10 "40" U2 1983 10. "40" - U2 (1983) + * "40" U2 1983 "40" - U2 (1983) + * 10 U2 1983 10. U2 (1983) + * 10 "40" 1983 "40" (1983) + * 10 "40" U2 10. "40" - U2 + * 10 "40" 10. "40" + * + * Available metadata masks: + * + * %A - Artist + * %B - Album + * %C - Programs count + * %D - Duration + * %E - episode number + * %F - FileName + * %G - Genre + * %H - season*100+episode + * %I - Size + * %J - Date + * %K - Movie/Game title + * %L - existing Label + * %M - number of episodes + * %N - Track Number + * %O - mpaa rating + * %P - production code + * %Q - file time + * %R - Movie rating + * %S - Disc Number + * %T - Title + * %U - studio + * %V - Playcount + * %W - Listeners + * %X - Bitrate + * %Y - Year + * %Z - tvshow title + * %a - Date Added + * %b - Total number of discs + * %c - Relevance - Used for actors' appearances + * %d - Date and Time + * %e - Original release date + * %f - bpm + * %p - Last Played + * %r - User Rating + * *t - Date Taken (suitable for Pictures) + */ + +#define MASK_CHARS "NSATBGYFLDIJRCKMEPHZOQUVXWabcdefiprstuv" + +CLabelFormatter::CLabelFormatter(const std::string &mask, const std::string &mask2) +{ + // assemble our label masks + AssembleMask(0, mask); + AssembleMask(1, mask2); + // save a bool for faster lookups + m_hideFileExtensions = !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWEXTENSIONS); +} + +std::string CLabelFormatter::GetContent(unsigned int label, const CFileItem *item) const +{ + assert(label < 2); + assert(m_staticContent[label].size() == m_dynamicContent[label].size() + 1); + + if (!item) return ""; + + std::string strLabel, dynamicLeft, dynamicRight; + for (unsigned int i = 0; i < m_dynamicContent[label].size(); i++) + { + dynamicRight = GetMaskContent(m_dynamicContent[label][i], item); + if ((i == 0 || !dynamicLeft.empty()) && !dynamicRight.empty()) + strLabel += m_staticContent[label][i]; + strLabel += dynamicRight; + dynamicLeft = dynamicRight; + } + if (!dynamicLeft.empty()) + strLabel += m_staticContent[label][m_dynamicContent[label].size()]; + + return strLabel; +} + +void CLabelFormatter::FormatLabel(CFileItem *item) const +{ + std::string maskedLabel = GetContent(0, item); + if (!maskedLabel.empty()) + item->SetLabel(maskedLabel); + else if (!item->m_bIsFolder && m_hideFileExtensions) + item->RemoveExtension(); +} + +void CLabelFormatter::FormatLabel2(CFileItem *item) const +{ + item->SetLabel2(GetContent(1, item)); +} + +std::string CLabelFormatter::GetMaskContent(const CMaskString &mask, const CFileItem *item) const +{ + if (!item) return ""; + const CMusicInfoTag *music = item->GetMusicInfoTag(); + const CVideoInfoTag *movie = item->GetVideoInfoTag(); + const CPictureInfoTag *pic = item->GetPictureInfoTag(); + std::string value; + switch (mask.m_content) + { + case 'N': + if (music && music->GetTrackNumber() > 0) + value = StringUtils::Format("%2.2i", music->GetTrackNumber()); + if (movie&& movie->m_iTrack > 0) + value = StringUtils::Format("%2.2i", movie->m_iTrack); + break; + case 'S': + if (music && music->GetDiscNumber() > 0) + value = StringUtils::Format("%2.2i", music->GetDiscNumber()); + break; + case 'A': + if (music && music->GetArtistString().size()) + value = music->GetArtistString(); + if (movie && movie->m_artist.size()) + value = StringUtils::Join(movie->m_artist, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator); + break; + case 'T': + if (music && music->GetTitle().size()) + value = music->GetTitle(); + if (movie && movie->m_strTitle.size()) + value = movie->m_strTitle; + break; + case 'Z': + if (movie && !movie->m_strShowTitle.empty()) + value = movie->m_strShowTitle; + break; + case 'B': + if (music && music->GetAlbum().size()) + value = music->GetAlbum(); + else if (movie) + value = movie->m_strAlbum; + break; + case 'G': + if (music && music->GetGenre().size()) + value = StringUtils::Join(music->GetGenre(), CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator); + if (movie && movie->m_genre.size()) + value = StringUtils::Join(movie->m_genre, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator); + break; + case 'Y': + if (music) + value = music->GetYearString(); + if (movie) + { + if (movie->m_firstAired.IsValid()) + value = movie->m_firstAired.GetAsLocalizedDate(); + else if (movie->HasYear()) + value = StringUtils::Format("%i", movie->GetYear()); + } + break; + case 'F': // filename + value = CUtil::GetTitleFromPath(item->GetPath(), item->m_bIsFolder && !item->IsFileFolder()); + break; + case 'L': + value = item->GetLabel(); + // is the label the actual file or folder name? + if (value == URIUtils::GetFileName(item->GetPath())) + { // label is the same as filename, clean it up as appropriate + value = CUtil::GetTitleFromPath(item->GetPath(), item->m_bIsFolder && !item->IsFileFolder()); + } + break; + case 'D': + { // duration + int nDuration=0; + if (music) + nDuration = music->GetDuration(); + if (movie) + nDuration = movie->GetDuration(); + if (nDuration > 0) + value = StringUtils::SecondsToTimeString(nDuration, (nDuration >= 3600) ? TIME_FORMAT_H_MM_SS : TIME_FORMAT_MM_SS); + else if (item->m_dwSize > 0) + value = StringUtils::SizeToString(item->m_dwSize); + } + break; + case 'I': // size + if( (item->m_bIsFolder && item->m_dwSize != 0) || item->m_dwSize >= 0 ) + value = StringUtils::SizeToString(item->m_dwSize); + break; + case 'J': // date + if (item->m_dateTime.IsValid()) + value = item->m_dateTime.GetAsLocalizedDate(); + break; + case 'Q': // time + if (item->m_dateTime.IsValid()) + value = item->m_dateTime.GetAsLocalizedTime("", false); + break; + case 'R': // rating + if (music && music->GetRating() != 0.f) + value = StringUtils::Format("%.1f", music->GetRating()); + else if (movie && movie->GetRating().rating != 0.f) + value = StringUtils::Format("%.1f", movie->GetRating().rating); + break; + case 'C': // programs count + value = StringUtils::Format("%i", item->m_iprogramCount); + break; + case 'c': // relevance + value = StringUtils::Format("%i", movie->m_relevance); + break; + case 'K': + value = item->m_strTitle; + break; + case 'M': + if (movie && movie->m_iEpisode > 0) + value = StringUtils::Format("%i %s", + movie->m_iEpisode, + g_localizeStrings.Get(movie->m_iEpisode == 1 ? 20452 : 20453).c_str()); + break; + case 'E': + if (movie && movie->m_iEpisode > 0) + { // episode number + if (movie->m_iSeason == 0) + value = StringUtils::Format("S%2.2i", movie->m_iEpisode); + else + value = StringUtils::Format("%2.2i", movie->m_iEpisode); + } + break; + case 'P': + if (movie) // tvshow production code + value = movie->m_strProductionCode; + break; + case 'H': + if (movie && movie->m_iEpisode > 0) + { // season*100+episode number + if (movie->m_iSeason == 0) + value = StringUtils::Format("S%2.2i", movie->m_iEpisode); + else + value = StringUtils::Format("%ix%2.2i", movie->m_iSeason,movie->m_iEpisode); + } + break; + case 'O': + if (movie) + {// MPAA Rating + value = movie->m_strMPAARating; + } + break; + case 'U': + if (movie && !movie->m_studio.empty()) + {// Studios + value = StringUtils::Join(movie ->m_studio, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator); + } + break; + case 'V': // Playcount + if (music) + value = StringUtils::Format("%i", music->GetPlayCount()); + if (movie) + value = StringUtils::Format("%i", movie->GetPlayCount()); + break; + case 'X': // Bitrate + if( !item->m_bIsFolder && item->m_dwSize != 0 ) + value = StringUtils::Format("%" PRId64" kbps", item->m_dwSize); + break; + case 'W': // Listeners + if( !item->m_bIsFolder && music && music->GetListeners() != 0 ) + value = StringUtils::Format("%i %s", + music->GetListeners(), + g_localizeStrings.Get(music->GetListeners() == 1 ? 20454 : 20455).c_str()); + break; + case 'a': // Date Added + if (movie && movie->m_dateAdded.IsValid()) + value = movie->m_dateAdded.GetAsLocalizedDate(); + if (music && music->GetDateAdded().IsValid()) + value = music->GetDateAdded().GetAsLocalizedDate(); + break; + case 'b': // Total number of discs + if (music) + value = StringUtils::Format("%i", music->GetTotalDiscs()); + break; + case 'e': // Original release date + if (music) + { + value = music->GetOriginalDate(); + if (!CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bMusicLibraryUseISODates) + value = StringUtils::ISODateToLocalizedDate(value); + break; + } + case 'd': // date and time + if (item->m_dateTime.IsValid()) + value = item->m_dateTime.GetAsLocalizedDateTime(); + break; + case 'p': // Last played + if (movie && movie->m_lastPlayed.IsValid()) + value = movie->m_lastPlayed.GetAsLocalizedDate(); + if (music && music->GetLastPlayed().IsValid()) + value = music->GetLastPlayed().GetAsLocalizedDate(); + break; + case 'r': // userrating + if (movie && movie->m_iUserRating != 0) + value = StringUtils::Format("%i", movie->m_iUserRating); + if (music && music->GetUserrating() != 0) + value = StringUtils::Format("%i", music->GetUserrating()); + break; + case 't': // Date Taken + if (pic && pic->GetDateTimeTaken().IsValid()) + value = pic->GetDateTimeTaken().GetAsLocalizedDate(); + break; + case 's': // Addon status + if (item->HasProperty("Addon.Status")) + value = item->GetProperty("Addon.Status").asString(); + break; + case 'i': // Install date + if (item->HasAddonInfo() && item->GetAddonInfo()->InstallDate().IsValid()) + value = item->GetAddonInfo()->InstallDate().GetAsLocalizedDate(); + break; + case 'u': // Last used + if (item->HasAddonInfo() && item->GetAddonInfo()->LastUsed().IsValid()) + value = item->GetAddonInfo()->LastUsed().GetAsLocalizedDate(); + break; + case 'v': // Last updated + if (item->HasAddonInfo() && item->GetAddonInfo()->LastUpdated().IsValid()) + value = item->GetAddonInfo()->LastUpdated().GetAsLocalizedDate(); + break; + case 'f': // BPM + if (music) + value = StringUtils::Format("%i", music->GetBPM()); + break; + } + if (!value.empty()) + return mask.m_prefix + value + mask.m_postfix; + return ""; +} + +void CLabelFormatter::SplitMask(unsigned int label, const std::string &mask) +{ + assert(label < 2); + CRegExp reg; + reg.RegComp("%([" MASK_CHARS "])"); + std::string work(mask); + int findStart = -1; + while ((findStart = reg.RegFind(work.c_str())) >= 0) + { // we've found a match + m_staticContent[label].push_back(work.substr(0, findStart)); + m_dynamicContent[label].emplace_back("", reg.GetMatch(1)[0], ""); + work = work.substr(findStart + reg.GetFindLen()); + } + m_staticContent[label].push_back(work); +} + +void CLabelFormatter::AssembleMask(unsigned int label, const std::string& mask) +{ + assert(label < 2); + m_staticContent[label].clear(); + m_dynamicContent[label].clear(); + + // we want to match [%A= 0) + { // we've found a match for a pre/postfixed string + // send anything + SplitMask(label, work.substr(0, findStart) + reg.GetMatch(1)); + m_dynamicContent[label].emplace_back(reg.GetMatch(2), reg.GetMatch(4)[0], reg.GetMatch(5)); + work = work.substr(findStart + reg.GetFindLen()); + } + SplitMask(label, work); + assert(m_staticContent[label].size() == m_dynamicContent[label].size() + 1); +} + +bool CLabelFormatter::FillMusicTag(const std::string &fileName, CMusicInfoTag *tag) const +{ + // run through and find static content to split the string up + size_t pos1 = fileName.find(m_staticContent[0][0], 0); + if (pos1 == std::string::npos) + return false; + for (unsigned int i = 1; i < m_staticContent[0].size(); i++) + { + size_t pos2 = m_staticContent[0][i].size() ? fileName.find(m_staticContent[0][i], pos1) : fileName.size(); + if (pos2 == std::string::npos) + return false; + // found static content - thus we have the dynamic content surrounded + FillMusicMaskContent(m_dynamicContent[0][i - 1].m_content, fileName.substr(pos1, pos2 - pos1), tag); + pos1 = pos2 + m_staticContent[0][i].size(); + } + return true; +} + +void CLabelFormatter::FillMusicMaskContent(const char mask, const std::string &value, CMusicInfoTag *tag) const +{ + if (!tag) return; + switch (mask) + { + case 'N': + tag->SetTrackNumber(atol(value.c_str())); + break; + case 'S': + tag->SetDiscNumber(atol(value.c_str())); + break; + case 'A': + tag->SetArtist(value); + break; + case 'T': + tag->SetTitle(value); + break; + case 'B': + tag->SetAlbum(value); + break; + case 'G': + tag->SetGenre(value); + break; + case 'Y': + tag->SetYear(atol(value.c_str())); + break; + case 'D': + tag->SetDuration(StringUtils::TimeStringToSeconds(value)); + break; + case 'R': // rating + tag->SetRating(value[0]); + break; + case 'r': // userrating + tag->SetUserrating(value[0]); + break; + case 'b': // total discs + tag->SetTotalDiscs(atol(value.c_str())); + break; + } +} + diff --git a/xbmc/utils/LabelFormatter.h b/xbmc/utils/LabelFormatter.h new file mode 100644 index 0000000..a10eae6 --- /dev/null +++ b/xbmc/utils/LabelFormatter.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include + +namespace MUSIC_INFO +{ + class CMusicInfoTag; +} + +class CFileItem; // forward + +struct LABEL_MASKS +{ + LABEL_MASKS(const std::string& strLabelFile="", const std::string& strLabel2File="", const std::string& strLabelFolder="", const std::string& strLabel2Folder="") : + m_strLabelFile(strLabelFile), + m_strLabel2File(strLabel2File), + m_strLabelFolder(strLabelFolder), + m_strLabel2Folder(strLabel2Folder) + {} + std::string m_strLabelFile; + std::string m_strLabel2File; + std::string m_strLabelFolder; + std::string m_strLabel2Folder; +}; + +class CLabelFormatter +{ +public: + CLabelFormatter(const std::string &mask, const std::string &mask2); + + void FormatLabel(CFileItem *item) const; + void FormatLabel2(CFileItem *item) const; + void FormatLabels(CFileItem *item) const // convenient shorthand + { + FormatLabel(item); + FormatLabel2(item); + } + + bool FillMusicTag(const std::string &fileName, MUSIC_INFO::CMusicInfoTag *tag) const; + +private: + class CMaskString + { + public: + CMaskString(const std::string &prefix, char content, const std::string &postfix) : + m_prefix(prefix), + m_postfix(postfix), + m_content(content) + {}; + std::string m_prefix; + std::string m_postfix; + char m_content; + }; + + // functions for assembling the mask vectors + void AssembleMask(unsigned int label, const std::string &mask); + void SplitMask(unsigned int label, const std::string &mask); + + // functions for retrieving content based on our mask vectors + std::string GetContent(unsigned int label, const CFileItem *item) const; + std::string GetMaskContent(const CMaskString &mask, const CFileItem *item) const; + void FillMusicMaskContent(const char mask, const std::string &value, MUSIC_INFO::CMusicInfoTag *tag) const; + + std::vector m_staticContent[2]; + std::vector m_dynamicContent[2]; + bool m_hideFileExtensions; +}; diff --git a/xbmc/utils/LangCodeExpander.cpp b/xbmc/utils/LangCodeExpander.cpp new file mode 100644 index 0000000..bc1e06b --- /dev/null +++ b/xbmc/utils/LangCodeExpander.cpp @@ -0,0 +1,1738 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "LangCodeExpander.h" + +#include "utils/StringUtils.h" +#include "utils/XBMCTinyXML.h" + +#include +#include + +#define MAKECODE(a, b, c, d) \ + ((((long)(a)) << 24) | (((long)(b)) << 16) | (((long)(c)) << 8) | (long)(d)) +#define MAKETWOCHARCODE(a, b) ((((long)(a)) << 8) | (long)(b)) + +typedef struct LCENTRY +{ + long code; + const char* name; +} LCENTRY; + +extern const std::array g_iso639_1; +extern const std::array g_iso639_2; + +struct ISO639 +{ + const char* iso639_1; + const char* iso639_2b; + const char* iso639_2t; + const char* win_id; +}; + +struct ISO3166_1 +{ + const char* alpha2; + const char* alpha3; +}; + +// declared as extern to allow forward declaration +extern const std::array LanguageCodes; +extern const std::array RegionCodes; + +CLangCodeExpander::CLangCodeExpander() = default; + +CLangCodeExpander::~CLangCodeExpander() = default; + +void CLangCodeExpander::Clear() +{ + m_mapUser.clear(); +} + +void CLangCodeExpander::LoadUserCodes(const TiXmlElement* pRootElement) +{ + if (pRootElement != NULL) + { + m_mapUser.clear(); + + std::string sShort, sLong; + + const TiXmlNode* pLangCode = pRootElement->FirstChild("code"); + while (pLangCode != NULL) + { + const TiXmlNode* pShort = pLangCode->FirstChildElement("short"); + const TiXmlNode* pLong = pLangCode->FirstChildElement("long"); + if (pShort != NULL && pLong != NULL) + { + sShort = pShort->FirstChild()->Value(); + sLong = pLong->FirstChild()->Value(); + StringUtils::ToLower(sShort); + + m_mapUser[sShort] = sLong; + } + + pLangCode = pLangCode->NextSibling(); + } + } +} + +bool CLangCodeExpander::Lookup(const std::string& code, std::string& desc) +{ + int iSplit = code.find("-"); + if (iSplit > 0) + { + std::string strLeft, strRight; + const bool bLeft = Lookup(code.substr(0, iSplit), strLeft); + const bool bRight = Lookup(code.substr(iSplit + 1), strRight); + if (bLeft || bRight) + { + desc = ""; + if (strLeft.length() > 0) + desc = strLeft; + else + desc = code.substr(0, iSplit); + + if (strRight.length() > 0) + { + desc += " - "; + desc += strRight; + } + else + { + desc += " - "; + desc += code.substr(iSplit + 1); + } + + return true; + } + + return false; + } + + if (LookupInUserMap(code, desc)) + return true; + + if (LookupInISO639Tables(code, desc)) + return true; + + return false; +} + +bool CLangCodeExpander::Lookup(const int code, std::string& desc) +{ + char lang[3]; + lang[2] = 0; + lang[1] = (code & 0xFF); + lang[0] = (code >> 8) & 0xFF; + + return Lookup(lang, desc); +} + +bool CLangCodeExpander::ConvertISO6391ToISO6392B(const std::string& strISO6391, + std::string& strISO6392B, + bool checkWin32Locales /*= false*/) +{ + // not a 2 char code + if (strISO6391.length() != 2) + return false; + + std::string strISO6391Lower(strISO6391); + StringUtils::ToLower(strISO6391Lower); + StringUtils::Trim(strISO6391Lower); + + for (const auto& codes : LanguageCodes) + { + if (strISO6391Lower == codes.iso639_1) + { + if (checkWin32Locales && codes.win_id) + { + strISO6392B = codes.win_id; + return true; + } + + strISO6392B = codes.iso639_2b; + return true; + } + } + + return false; +} + +bool CLangCodeExpander::ConvertToISO6392B(const std::string& strCharCode, + std::string& strISO6392B, + bool checkWin32Locales /* = false */) +{ + + //first search in the user defined map + if (LookupUserCode(strCharCode, strISO6392B)) + return true; + + if (strCharCode.size() == 2) + return g_LangCodeExpander.ConvertISO6391ToISO6392B(strCharCode, strISO6392B, checkWin32Locales); + + if (strCharCode.size() == 3) + { + std::string charCode(strCharCode); + StringUtils::ToLower(charCode); + for (const auto& codes : LanguageCodes) + { + if (charCode == codes.iso639_2b || + (checkWin32Locales && codes.win_id != NULL && charCode == codes.win_id)) + { + strISO6392B = charCode; + return true; + } + } + + for (const auto& codes : RegionCodes) + { + if (charCode == codes.alpha3) + { + strISO6392B = charCode; + return true; + } + } + } + else if (strCharCode.size() > 3) + { + for (const auto& codes : g_iso639_2) + { + if (StringUtils::EqualsNoCase(strCharCode, codes.name)) + { + CodeToString(codes.code, strISO6392B); + return true; + } + } + } + return false; +} + +bool CLangCodeExpander::ConvertToISO6392T(const std::string& strCharCode, + std::string& strISO6392T, + bool checkWin32Locales /* = false */) +{ + if (!ConvertToISO6392B(strCharCode, strISO6392T, checkWin32Locales)) + return false; + + for (const auto& codes : LanguageCodes) + { + if (strISO6392T == codes.iso639_2b || + (checkWin32Locales && codes.win_id != NULL && strISO6392T == codes.win_id)) + { + if (codes.iso639_2t != nullptr) + strISO6392T = codes.iso639_2t; + return true; + } + } + return false; +} + + +bool CLangCodeExpander::LookupUserCode(const std::string& desc, std::string& userCode) +{ + for (STRINGLOOKUPTABLE::const_iterator it = m_mapUser.begin(); it != m_mapUser.end(); ++it) + { + if (StringUtils::EqualsNoCase(desc, it->first) || StringUtils::EqualsNoCase(desc, it->second)) + { + userCode = it->first; + return true; + } + } + return false; +} + +#ifdef TARGET_WINDOWS +bool CLangCodeExpander::ConvertISO31661Alpha2ToISO31661Alpha3(const std::string& strISO31661Alpha2, + std::string& strISO31661Alpha3) +{ + if (strISO31661Alpha2.length() != 2) + return false; + + std::string strLower(strISO31661Alpha2); + StringUtils::ToLower(strLower); + StringUtils::Trim(strLower); + for (const auto& codes : RegionCodes) + { + if (strLower == codes.alpha2) + { + strISO31661Alpha3 = codes.alpha3; + return true; + } + } + + return true; +} + +bool CLangCodeExpander::ConvertWindowsLanguageCodeToISO6392B( + const std::string& strWindowsLanguageCode, std::string& strISO6392B) +{ + if (strWindowsLanguageCode.length() != 3) + return false; + + std::string strLower(strWindowsLanguageCode); + StringUtils::ToLower(strLower); + for (const auto& codes : LanguageCodes) + { + if ((codes.win_id && strLower == codes.win_id) || strLower == codes.iso639_2b) + { + strISO6392B = codes.iso639_2b; + return true; + } + } + + return false; +} +#endif + +bool CLangCodeExpander::ConvertToISO6391(const std::string& lang, std::string& code) +{ + if (lang.empty()) + return false; + + //first search in the user defined map + if (LookupUserCode(lang, code)) + return true; + + if (lang.length() == 2) + { + std::string tmp; + if (Lookup(lang, tmp)) + { + code = lang; + return true; + } + } + else if (lang.length() == 3) + { + std::string lower(lang); + StringUtils::ToLower(lower); + for (const auto& codes : LanguageCodes) + { + if (lower == codes.iso639_2b || (codes.win_id && lower == codes.win_id)) + { + code = codes.iso639_1; + return true; + } + } + + for (const auto& codes : RegionCodes) + { + if (lower == codes.alpha3) + { + code = codes.alpha2; + return true; + } + } + } + + // check if lang is full language name + std::string tmp; + if (ReverseLookup(lang, tmp)) + { + if (tmp.length() == 2) + { + code = tmp; + return true; + } + + if (tmp.length() == 3) + { + // there's only an iso639-2 code that is identical to the language name, e.g. Yao + if (StringUtils::EqualsNoCase(tmp, lang)) + return false; + + return ConvertToISO6391(tmp, code); + } + } + + return false; +} + +bool CLangCodeExpander::ReverseLookup(const std::string& desc, std::string& code) +{ + if (desc.empty()) + return false; + + std::string descTmp(desc); + StringUtils::Trim(descTmp); + for (STRINGLOOKUPTABLE::const_iterator it = m_mapUser.begin(); it != m_mapUser.end(); ++it) + { + if (StringUtils::EqualsNoCase(descTmp, it->second)) + { + code = it->first; + return true; + } + } + + for (const auto& codes : g_iso639_1) + { + if (StringUtils::EqualsNoCase(descTmp, codes.name)) + { + CodeToString(codes.code, code); + return true; + } + } + + for (const auto& codes : g_iso639_2) + { + if (StringUtils::EqualsNoCase(descTmp, codes.name)) + { + CodeToString(codes.code, code); + return true; + } + } + + return false; +} + +bool CLangCodeExpander::LookupInUserMap(const std::string& code, std::string& desc) +{ + if (code.empty()) + return false; + + // make sure we convert to lowercase before trying to find it + std::string sCode(code); + StringUtils::ToLower(sCode); + StringUtils::Trim(sCode); + + STRINGLOOKUPTABLE::iterator it = m_mapUser.find(sCode); + if (it != m_mapUser.end()) + { + desc = it->second; + return true; + } + + return false; +} + +bool CLangCodeExpander::LookupInISO639Tables(const std::string& code, std::string& desc) +{ + if (code.empty()) + return false; + + long longcode; + std::string sCode(code); + StringUtils::ToLower(sCode); + StringUtils::Trim(sCode); + + if (sCode.length() == 2) + { + longcode = MAKECODE('\0', '\0', sCode[0], sCode[1]); + for (const auto& codes : g_iso639_1) + { + if (codes.code == longcode) + { + desc = codes.name; + return true; + } + } + } + else if (sCode.length() == 3) + { + longcode = MAKECODE('\0', sCode[0], sCode[1], sCode[2]); + for (const auto& codes : g_iso639_2) + { + if (codes.code == longcode) + { + desc = codes.name; + return true; + } + } + } + return false; +} + +void CLangCodeExpander::CodeToString(long code, std::string& ret) +{ + ret.clear(); + for (unsigned int j = 0; j < 4; j++) + { + char c = (char)code & 0xFF; + if (c == '\0') + return; + + ret.insert(0, 1, c); + code >>= 8; + } +} + +bool CLangCodeExpander::CompareFullLanguageNames(const std::string& lang1, const std::string& lang2) +{ + if (StringUtils::EqualsNoCase(lang1, lang2)) + return true; + + std::string expandedLang1, expandedLang2, code1, code2; + + if (!ReverseLookup(lang1, code1)) + return false; + + code1 = lang1; + if (!ReverseLookup(lang2, code2)) + return false; + + code2 = lang2; + Lookup(expandedLang1, code1); + Lookup(expandedLang2, code2); + + return StringUtils::EqualsNoCase(expandedLang1, expandedLang2); +} + +std::vector CLangCodeExpander::GetLanguageNames( + LANGFORMATS format /* = CLangCodeExpander::ISO_639_1 */, bool customNames /* = false */) +{ + std::vector languages; + + if (format == CLangCodeExpander::ISO_639_2) + std::transform(g_iso639_2.begin(), g_iso639_2.end(), std::back_inserter(languages), + [](const LCENTRY& e) { return e.name; }); + else + std::transform(g_iso639_1.begin(), g_iso639_1.end(), std::back_inserter(languages), + [](const LCENTRY& e) { return e.name; }); + + if (customNames) + std::transform(m_mapUser.begin(), m_mapUser.end(), std::back_inserter(languages), + [](const STRINGLOOKUPTABLE::value_type& e) { return e.second; }); + + return languages; +} + +bool CLangCodeExpander::CompareISO639Codes(const std::string& code1, const std::string& code2) +{ + if (StringUtils::EqualsNoCase(code1, code2)) + return true; + + std::string expandedLang1; + if (!Lookup(code1, expandedLang1)) + return false; + + std::string expandedLang2; + if (!Lookup(code2, expandedLang2)) + return false; + + return StringUtils::EqualsNoCase(expandedLang1, expandedLang2); +} + +std::string CLangCodeExpander::ConvertToISO6392B(const std::string& lang) +{ + if (lang.empty()) + return lang; + + std::string two, three; + if (ConvertToISO6391(lang, two)) + { + if (ConvertToISO6392B(two, three)) + return three; + } + + return lang; +} + +std::string CLangCodeExpander::ConvertToISO6392T(const std::string& lang) +{ + if (lang.empty()) + return lang; + + std::string two, three; + if (ConvertToISO6391(lang, two)) + { + if (ConvertToISO6392T(two, three)) + return three; + } + + return lang; +} + +// clang-format off +const std::array g_iso639_1 = {{ + {MAKECODE('\0', '\0', 'a', 'a'), "Afar"}, + {MAKECODE('\0', '\0', 'a', 'b'), "Abkhazian"}, + {MAKECODE('\0', '\0', 'a', 'e'), "Avestan"}, + {MAKECODE('\0', '\0', 'a', 'f'), "Afrikaans"}, + {MAKECODE('\0', '\0', 'a', 'k'), "Akan"}, + {MAKECODE('\0', '\0', 'a', 'm'), "Amharic"}, + {MAKECODE('\0', '\0', 'a', 'n'), "Aragonese"}, + {MAKECODE('\0', '\0', 'a', 'r'), "Arabic"}, + {MAKECODE('\0', '\0', 'a', 's'), "Assamese"}, + {MAKECODE('\0', '\0', 'a', 'v'), "Avaric"}, + {MAKECODE('\0', '\0', 'a', 'y'), "Aymara"}, + {MAKECODE('\0', '\0', 'a', 'z'), "Azerbaijani"}, + {MAKECODE('\0', '\0', 'b', 'a'), "Bashkir"}, + {MAKECODE('\0', '\0', 'b', 'e'), "Belarusian"}, + {MAKECODE('\0', '\0', 'b', 'g'), "Bulgarian"}, + {MAKECODE('\0', '\0', 'b', 'h'), "Bihari"}, + {MAKECODE('\0', '\0', 'b', 'i'), "Bislama"}, + {MAKECODE('\0', '\0', 'b', 'm'), "Bambara"}, + {MAKECODE('\0', '\0', 'b', 'n'), "Bengali; Bangla"}, + {MAKECODE('\0', '\0', 'b', 'o'), "Tibetan"}, + {MAKECODE('\0', '\0', 'b', 'r'), "Breton"}, + {MAKECODE('\0', '\0', 'b', 's'), "Bosnian"}, + {MAKECODE('\0', '\0', 'c', 'a'), "Catalan"}, + {MAKECODE('\0', '\0', 'c', 'e'), "Chechen"}, + {MAKECODE('\0', '\0', 'c', 'h'), "Chamorro"}, + {MAKECODE('\0', '\0', 'c', 'o'), "Corsican"}, + {MAKECODE('\0', '\0', 'c', 'r'), "Cree"}, + {MAKECODE('\0', '\0', 'c', 's'), "Czech"}, + {MAKECODE('\0', '\0', 'c', 'u'), "Church Slavic"}, + {MAKECODE('\0', '\0', 'c', 'v'), "Chuvash"}, + {MAKECODE('\0', '\0', 'c', 'y'), "Welsh"}, + {MAKECODE('\0', '\0', 'd', 'a'), "Danish"}, + {MAKECODE('\0', '\0', 'd', 'e'), "German"}, + {MAKECODE('\0', '\0', 'd', 'v'), "Dhivehi"}, + {MAKECODE('\0', '\0', 'd', 'z'), "Dzongkha"}, + {MAKECODE('\0', '\0', 'e', 'e'), "Ewe"}, + {MAKECODE('\0', '\0', 'e', 'l'), "Greek"}, + {MAKECODE('\0', '\0', 'e', 'n'), "English"}, + {MAKECODE('\0', '\0', 'e', 'o'), "Esperanto"}, + {MAKECODE('\0', '\0', 'e', 's'), "Spanish"}, + {MAKECODE('\0', '\0', 'e', 't'), "Estonian"}, + {MAKECODE('\0', '\0', 'e', 'u'), "Basque"}, + {MAKECODE('\0', '\0', 'f', 'a'), "Persian"}, + {MAKECODE('\0', '\0', 'f', 'f'), "Fulah"}, + {MAKECODE('\0', '\0', 'f', 'i'), "Finnish"}, + {MAKECODE('\0', '\0', 'f', 'j'), "Fijian"}, + {MAKECODE('\0', '\0', 'f', 'o'), "Faroese"}, + {MAKECODE('\0', '\0', 'f', 'r'), "French"}, + {MAKECODE('\0', '\0', 'f', 'y'), "Western Frisian"}, + {MAKECODE('\0', '\0', 'g', 'a'), "Irish"}, + {MAKECODE('\0', '\0', 'g', 'd'), "Scottish Gaelic"}, + {MAKECODE('\0', '\0', 'g', 'l'), "Galician"}, + {MAKECODE('\0', '\0', 'g', 'n'), "Guarani"}, + {MAKECODE('\0', '\0', 'g', 'u'), "Gujarati"}, + {MAKECODE('\0', '\0', 'g', 'v'), "Manx"}, + {MAKECODE('\0', '\0', 'h', 'a'), "Hausa"}, + {MAKECODE('\0', '\0', 'h', 'e'), "Hebrew"}, + {MAKECODE('\0', '\0', 'h', 'i'), "Hindi"}, + {MAKECODE('\0', '\0', 'h', 'o'), "Hiri Motu"}, + {MAKECODE('\0', '\0', 'h', 'r'), "Croatian"}, + {MAKECODE('\0', '\0', 'h', 't'), "Haitian"}, + {MAKECODE('\0', '\0', 'h', 'u'), "Hungarian"}, + {MAKECODE('\0', '\0', 'h', 'y'), "Armenian"}, + {MAKECODE('\0', '\0', 'h', 'z'), "Herero"}, + {MAKECODE('\0', '\0', 'i', 'a'), "Interlingua"}, + {MAKECODE('\0', '\0', 'i', 'd'), "Indonesian"}, + {MAKECODE('\0', '\0', 'i', 'e'), "Interlingue"}, + {MAKECODE('\0', '\0', 'i', 'g'), "Igbo"}, + {MAKECODE('\0', '\0', 'i', 'i'), "Sichuan Yi"}, + {MAKECODE('\0', '\0', 'i', 'k'), "Inupiat"}, + {MAKECODE('\0', '\0', 'i', 'o'), "Ido"}, + {MAKECODE('\0', '\0', 'i', 's'), "Icelandic"}, + {MAKECODE('\0', '\0', 'i', 't'), "Italian"}, + {MAKECODE('\0', '\0', 'i', 'u'), "Inuktitut"}, + {MAKECODE('\0', '\0', 'j', 'a'), "Japanese"}, + {MAKECODE('\0', '\0', 'j', 'v'), "Javanese"}, + {MAKECODE('\0', '\0', 'k', 'a'), "Georgian"}, + {MAKECODE('\0', '\0', 'k', 'g'), "Kongo"}, + {MAKECODE('\0', '\0', 'k', 'i'), "Kikuyu"}, + {MAKECODE('\0', '\0', 'k', 'j'), "Kuanyama"}, + {MAKECODE('\0', '\0', 'k', 'k'), "Kazakh"}, + {MAKECODE('\0', '\0', 'k', 'l'), "Kalaallisut"}, + {MAKECODE('\0', '\0', 'k', 'm'), "Khmer"}, + {MAKECODE('\0', '\0', 'k', 'n'), "Kannada"}, + {MAKECODE('\0', '\0', 'k', 'o'), "Korean"}, + {MAKECODE('\0', '\0', 'k', 'r'), "Kanuri"}, + {MAKECODE('\0', '\0', 'k', 's'), "Kashmiri"}, + {MAKECODE('\0', '\0', 'k', 'u'), "Kurdish"}, + {MAKECODE('\0', '\0', 'k', 'v'), "Komi"}, + {MAKECODE('\0', '\0', 'k', 'w'), "Cornish"}, + {MAKECODE('\0', '\0', 'k', 'y'), "Kirghiz"}, + {MAKECODE('\0', '\0', 'l', 'a'), "Latin"}, + {MAKECODE('\0', '\0', 'l', 'b'), "Luxembourgish"}, + {MAKECODE('\0', '\0', 'l', 'g'), "Ganda"}, + {MAKECODE('\0', '\0', 'l', 'i'), "Limburgan"}, + {MAKECODE('\0', '\0', 'l', 'n'), "Lingala"}, + {MAKECODE('\0', '\0', 'l', 'o'), "Lao"}, + {MAKECODE('\0', '\0', 'l', 't'), "Lithuanian"}, + {MAKECODE('\0', '\0', 'l', 'u'), "Luba-Katanga"}, + {MAKECODE('\0', '\0', 'l', 'v'), "Latvian, Lettish"}, + {MAKECODE('\0', '\0', 'm', 'g'), "Malagasy"}, + {MAKECODE('\0', '\0', 'm', 'h'), "Marshallese"}, + {MAKECODE('\0', '\0', 'm', 'i'), "Maori"}, + {MAKECODE('\0', '\0', 'm', 'k'), "Macedonian"}, + {MAKECODE('\0', '\0', 'm', 'l'), "Malayalam"}, + {MAKECODE('\0', '\0', 'm', 'n'), "Mongolian"}, + {MAKECODE('\0', '\0', 'm', 'r'), "Marathi"}, + {MAKECODE('\0', '\0', 'm', 's'), "Malay"}, + {MAKECODE('\0', '\0', 'm', 't'), "Maltese"}, + {MAKECODE('\0', '\0', 'm', 'y'), "Burmese"}, + {MAKECODE('\0', '\0', 'n', 'a'), "Nauru"}, + {MAKECODE('\0', '\0', 'n', 'b'), "Norwegian Bokm\xC3\xA5l"}, + {MAKECODE('\0', '\0', 'n', 'd'), "Ndebele, North"}, + {MAKECODE('\0', '\0', 'n', 'e'), "Nepali"}, + {MAKECODE('\0', '\0', 'n', 'g'), "Ndonga"}, + {MAKECODE('\0', '\0', 'n', 'l'), "Dutch"}, + {MAKECODE('\0', '\0', 'n', 'n'), "Norwegian Nynorsk"}, + {MAKECODE('\0', '\0', 'n', 'o'), "Norwegian"}, + {MAKECODE('\0', '\0', 'n', 'r'), "Ndebele, South"}, + {MAKECODE('\0', '\0', 'n', 'v'), "Navajo"}, + {MAKECODE('\0', '\0', 'n', 'y'), "Chichewa"}, + {MAKECODE('\0', '\0', 'o', 'c'), "Occitan"}, + {MAKECODE('\0', '\0', 'o', 'j'), "Ojibwa"}, + {MAKECODE('\0', '\0', 'o', 'm'), "Oromo"}, + {MAKECODE('\0', '\0', 'o', 'r'), "Oriya"}, + {MAKECODE('\0', '\0', 'o', 's'), "Ossetic"}, + {MAKECODE('\0', '\0', 'p', 'a'), "Punjabi"}, + {MAKECODE('\0', '\0', 'p', 'i'), "Pali"}, + {MAKECODE('\0', '\0', 'p', 'l'), "Polish"}, + {MAKECODE('\0', '\0', 'p', 's'), "Pashto, Pushto"}, + {MAKECODE('\0', '\0', 'p', 't'), "Portuguese"}, + // pb = unofficial language code for Brazilian Portuguese + {MAKECODE('\0', '\0', 'p', 'b'), "Portuguese (Brazil)"}, + {MAKECODE('\0', '\0', 'q', 'u'), "Quechua"}, + {MAKECODE('\0', '\0', 'r', 'm'), "Romansh"}, + {MAKECODE('\0', '\0', 'r', 'n'), "Kirundi"}, + {MAKECODE('\0', '\0', 'r', 'o'), "Romanian"}, + {MAKECODE('\0', '\0', 'r', 'u'), "Russian"}, + {MAKECODE('\0', '\0', 'r', 'w'), "Kinyarwanda"}, + {MAKECODE('\0', '\0', 's', 'a'), "Sanskrit"}, + {MAKECODE('\0', '\0', 's', 'c'), "Sardinian"}, + {MAKECODE('\0', '\0', 's', 'd'), "Sindhi"}, + {MAKECODE('\0', '\0', 's', 'e'), "Northern Sami"}, + {MAKECODE('\0', '\0', 's', 'g'), "Sangho"}, + {MAKECODE('\0', '\0', 's', 'h'), "Serbo-Croatian"}, + {MAKECODE('\0', '\0', 's', 'i'), "Sinhalese"}, + {MAKECODE('\0', '\0', 's', 'k'), "Slovak"}, + {MAKECODE('\0', '\0', 's', 'l'), "Slovenian"}, + {MAKECODE('\0', '\0', 's', 'm'), "Samoan"}, + {MAKECODE('\0', '\0', 's', 'n'), "Shona"}, + {MAKECODE('\0', '\0', 's', 'o'), "Somali"}, + {MAKECODE('\0', '\0', 's', 'q'), "Albanian"}, + {MAKECODE('\0', '\0', 's', 'r'), "Serbian"}, + {MAKECODE('\0', '\0', 's', 's'), "Swati"}, + {MAKECODE('\0', '\0', 's', 't'), "Sesotho"}, + {MAKECODE('\0', '\0', 's', 'u'), "Sundanese"}, + {MAKECODE('\0', '\0', 's', 'v'), "Swedish"}, + {MAKECODE('\0', '\0', 's', 'w'), "Swahili"}, + {MAKECODE('\0', '\0', 't', 'a'), "Tamil"}, + {MAKECODE('\0', '\0', 't', 'e'), "Telugu"}, + {MAKECODE('\0', '\0', 't', 'g'), "Tajik"}, + {MAKECODE('\0', '\0', 't', 'h'), "Thai"}, + {MAKECODE('\0', '\0', 't', 'i'), "Tigrinya"}, + {MAKECODE('\0', '\0', 't', 'k'), "Turkmen"}, + {MAKECODE('\0', '\0', 't', 'l'), "Tagalog"}, + {MAKECODE('\0', '\0', 't', 'n'), "Tswana"}, + {MAKECODE('\0', '\0', 't', 'o'), "Tonga"}, + {MAKECODE('\0', '\0', 't', 'r'), "Turkish"}, + {MAKECODE('\0', '\0', 't', 's'), "Tsonga"}, + {MAKECODE('\0', '\0', 't', 't'), "Tatar"}, + {MAKECODE('\0', '\0', 't', 'w'), "Twi"}, + {MAKECODE('\0', '\0', 't', 'y'), "Tahitian"}, + {MAKECODE('\0', '\0', 'u', 'g'), "Uighur"}, + {MAKECODE('\0', '\0', 'u', 'k'), "Ukrainian"}, + {MAKECODE('\0', '\0', 'u', 'r'), "Urdu"}, + {MAKECODE('\0', '\0', 'u', 'z'), "Uzbek"}, + {MAKECODE('\0', '\0', 'v', 'e'), "Venda"}, + {MAKECODE('\0', '\0', 'v', 'i'), "Vietnamese"}, + {MAKECODE('\0', '\0', 'v', 'o'), "Volapuk"}, + {MAKECODE('\0', '\0', 'w', 'a'), "Walloon"}, + {MAKECODE('\0', '\0', 'w', 'o'), "Wolof"}, + {MAKECODE('\0', '\0', 'x', 'h'), "Xhosa"}, + {MAKECODE('\0', '\0', 'y', 'i'), "Yiddish"}, + {MAKECODE('\0', '\0', 'y', 'o'), "Yoruba"}, + {MAKECODE('\0', '\0', 'z', 'a'), "Zhuang"}, + {MAKECODE('\0', '\0', 'z', 'h'), "Chinese"}, + {MAKECODE('\0', '\0', 'z', 'u'), "Zulu"}, +}}; +// clang-format on + +// clang-format off +const std::array g_iso639_2 = {{ + {MAKECODE('\0', 'a', 'b', 'k'), "Abkhaz"}, + {MAKECODE('\0', 'a', 'b', 'k'), "Abkhazian"}, + {MAKECODE('\0', 'a', 'c', 'e'), "Achinese"}, + {MAKECODE('\0', 'a', 'c', 'h'), "Acoli"}, + {MAKECODE('\0', 'a', 'd', 'a'), "Adangme"}, + {MAKECODE('\0', 'a', 'd', 'y'), "Adygei"}, + {MAKECODE('\0', 'a', 'd', 'y'), "Adyghe"}, + {MAKECODE('\0', 'a', 'a', 'r'), "Afar"}, + {MAKECODE('\0', 'a', 'f', 'h'), "Afrihili"}, + {MAKECODE('\0', 'a', 'f', 'r'), "Afrikaans"}, + {MAKECODE('\0', 'a', 'f', 'a'), "Afro-Asiatic (Other)"}, + {MAKECODE('\0', 'a', 'k', 'a'), "Akan"}, + {MAKECODE('\0', 'a', 'k', 'k'), "Akkadian"}, + {MAKECODE('\0', 'a', 'l', 'b'), "Albanian"}, + {MAKECODE('\0', 's', 'q', 'i'), "Albanian"}, + {MAKECODE('\0', 'a', 'l', 'e'), "Aleut"}, + {MAKECODE('\0', 'a', 'l', 'g'), "Algonquian languages"}, + {MAKECODE('\0', 't', 'u', 't'), "Altaic (Other)"}, + {MAKECODE('\0', 'a', 'm', 'h'), "Amharic"}, + {MAKECODE('\0', 'a', 'p', 'a'), "Apache languages"}, + {MAKECODE('\0', 'a', 'r', 'a'), "Arabic"}, + {MAKECODE('\0', 'a', 'r', 'g'), "Aragonese"}, + {MAKECODE('\0', 'a', 'r', 'c'), "Aramaic"}, + {MAKECODE('\0', 'a', 'r', 'p'), "Arapaho"}, + {MAKECODE('\0', 'a', 'r', 'n'), "Araucanian"}, + {MAKECODE('\0', 'a', 'r', 'w'), "Arawak"}, + {MAKECODE('\0', 'a', 'r', 'm'), "Armenian"}, + {MAKECODE('\0', 'h', 'y', 'e'), "Armenian"}, + {MAKECODE('\0', 'a', 'r', 't'), "Artificial (Other)"}, + {MAKECODE('\0', 'a', 's', 'm'), "Assamese"}, + {MAKECODE('\0', 'a', 's', 't'), "Asturian"}, + {MAKECODE('\0', 'a', 't', 'h'), "Athapascan languages"}, + {MAKECODE('\0', 'a', 'u', 's'), "Australian languages"}, + {MAKECODE('\0', 'm', 'a', 'p'), "Austronesian (Other)"}, + {MAKECODE('\0', 'a', 'v', 'a'), "Avaric"}, + {MAKECODE('\0', 'a', 'v', 'e'), "Avestan"}, + {MAKECODE('\0', 'a', 'w', 'a'), "Awadhi"}, + {MAKECODE('\0', 'a', 'y', 'm'), "Aymara"}, + {MAKECODE('\0', 'a', 'z', 'e'), "Azerbaijani"}, + {MAKECODE('\0', 'a', 's', 't'), "Bable"}, + {MAKECODE('\0', 'b', 'a', 'n'), "Balinese"}, + {MAKECODE('\0', 'b', 'a', 't'), "Baltic (Other)"}, + {MAKECODE('\0', 'b', 'a', 'l'), "Baluchi"}, + {MAKECODE('\0', 'b', 'a', 'm'), "Bambara"}, + {MAKECODE('\0', 'b', 'a', 'i'), "Bamileke languages"}, + {MAKECODE('\0', 'b', 'a', 'd'), "Banda"}, + {MAKECODE('\0', 'b', 'n', 't'), "Bantu (Other)"}, + {MAKECODE('\0', 'b', 'a', 's'), "Basa"}, + {MAKECODE('\0', 'b', 'a', 'k'), "Bashkir"}, + {MAKECODE('\0', 'b', 'a', 'q'), "Basque"}, + {MAKECODE('\0', 'e', 'u', 's'), "Basque"}, + {MAKECODE('\0', 'b', 't', 'k'), "Batak (Indonesia)"}, + {MAKECODE('\0', 'b', 'e', 'j'), "Beja"}, + {MAKECODE('\0', 'b', 'e', 'l'), "Belarusian"}, + {MAKECODE('\0', 'b', 'e', 'm'), "Bemba"}, + {MAKECODE('\0', 'b', 'e', 'n'), "Bengali"}, + {MAKECODE('\0', 'b', 'e', 'r'), "Berber (Other)"}, + {MAKECODE('\0', 'b', 'h', 'o'), "Bhojpuri"}, + {MAKECODE('\0', 'b', 'i', 'h'), "Bihari"}, + {MAKECODE('\0', 'b', 'i', 'k'), "Bikol"}, + {MAKECODE('\0', 'b', 'y', 'n'), "Bilin"}, + {MAKECODE('\0', 'b', 'i', 'n'), "Bini"}, + {MAKECODE('\0', 'b', 'i', 's'), "Bislama"}, + {MAKECODE('\0', 'b', 'y', 'n'), "Blin"}, + {MAKECODE('\0', 'n', 'o', 'b'), "Bokm\xC3\xA5l, Norwegian"}, + {MAKECODE('\0', 'b', 'o', 's'), "Bosnian"}, + {MAKECODE('\0', 'b', 'r', 'a'), "Braj"}, + {MAKECODE('\0', 'b', 'r', 'e'), "Breton"}, + {MAKECODE('\0', 'b', 'u', 'g'), "Buginese"}, + {MAKECODE('\0', 'b', 'u', 'l'), "Bulgarian"}, + {MAKECODE('\0', 'b', 'u', 'a'), "Buriat"}, + {MAKECODE('\0', 'b', 'u', 'r'), "Burmese"}, + {MAKECODE('\0', 'm', 'y', 'a'), "Burmese"}, + {MAKECODE('\0', 'c', 'a', 'd'), "Caddo"}, + {MAKECODE('\0', 'c', 'a', 'r'), "Carib"}, + {MAKECODE('\0', 's', 'p', 'a'), "Spanish"}, + {MAKECODE('\0', 'c', 'a', 't'), "Catalan"}, + {MAKECODE('\0', 'c', 'a', 'u'), "Caucasian (Other)"}, + {MAKECODE('\0', 'c', 'e', 'b'), "Cebuano"}, + {MAKECODE('\0', 'c', 'e', 'l'), "Celtic (Other)"}, + {MAKECODE('\0', 'c', 'h', 'g'), "Chagatai"}, + {MAKECODE('\0', 'c', 'm', 'c'), "Chamic languages"}, + {MAKECODE('\0', 'c', 'h', 'a'), "Chamorro"}, + {MAKECODE('\0', 'c', 'h', 'e'), "Chechen"}, + {MAKECODE('\0', 'c', 'h', 'r'), "Cherokee"}, + {MAKECODE('\0', 'n', 'y', 'a'), "Chewa"}, + {MAKECODE('\0', 'c', 'h', 'y'), "Cheyenne"}, + {MAKECODE('\0', 'c', 'h', 'b'), "Chibcha"}, + {MAKECODE('\0', 'n', 'y', 'a'), "Chichewa"}, + {MAKECODE('\0', 'c', 'h', 'i'), "Chinese"}, + {MAKECODE('\0', 'z', 'h', 'o'), "Chinese"}, + {MAKECODE('\0', 'c', 'h', 'n'), "Chinook jargon"}, + {MAKECODE('\0', 'c', 'h', 'p'), "Chipewyan"}, + {MAKECODE('\0', 'c', 'h', 'o'), "Choctaw"}, + {MAKECODE('\0', 'z', 'h', 'a'), "Chuang"}, + {MAKECODE('\0', 'c', 'h', 'u'), "Church Slavonic"}, + {MAKECODE('\0', 'c', 'h', 'k'), "Chuukese"}, + {MAKECODE('\0', 'c', 'h', 'v'), "Chuvash"}, + {MAKECODE('\0', 'n', 'w', 'c'), "Classical Nepal Bhasa"}, + {MAKECODE('\0', 'n', 'w', 'c'), "Classical Newari"}, + {MAKECODE('\0', 'c', 'o', 'p'), "Coptic"}, + {MAKECODE('\0', 'c', 'o', 'r'), "Cornish"}, + {MAKECODE('\0', 'c', 'o', 's'), "Corsican"}, + {MAKECODE('\0', 'c', 'r', 'e'), "Cree"}, + {MAKECODE('\0', 'm', 'u', 's'), "Creek"}, + {MAKECODE('\0', 'c', 'r', 'p'), "Creoles and pidgins (Other)"}, + {MAKECODE('\0', 'c', 'p', 'e'), "English-based (Other)"}, + {MAKECODE('\0', 'c', 'p', 'f'), "French-based (Other)"}, + {MAKECODE('\0', 'c', 'p', 'p'), "Portuguese-based (Other)"}, + {MAKECODE('\0', 'c', 'r', 'h'), "Crimean Tatar"}, + {MAKECODE('\0', 'c', 'r', 'h'), "Crimean Turkish"}, + {MAKECODE('\0', 'h', 'r', 'v'), "Croatian"}, + {MAKECODE('\0', 's', 'c', 'r'), "Croatian"}, + {MAKECODE('\0', 'c', 'u', 's'), "Cushitic (Other)"}, + {MAKECODE('\0', 'c', 'z', 'e'), "Czech"}, + {MAKECODE('\0', 'c', 'e', 's'), "Czech"}, + {MAKECODE('\0', 'd', 'a', 'k'), "Dakota"}, + {MAKECODE('\0', 'd', 'a', 'n'), "Danish"}, + {MAKECODE('\0', 'd', 'a', 'r'), "Dargwa"}, + {MAKECODE('\0', 'd', 'a', 'y'), "Dayak"}, + {MAKECODE('\0', 'd', 'e', 'l'), "Delaware"}, + {MAKECODE('\0', 'd', 'i', 'n'), "Dinka"}, + {MAKECODE('\0', 'd', 'i', 'v'), "Divehi"}, + {MAKECODE('\0', 'd', 'o', 'i'), "Dogri"}, + {MAKECODE('\0', 'd', 'g', 'r'), "Dogrib"}, + {MAKECODE('\0', 'd', 'r', 'a'), "Dravidian (Other)"}, + {MAKECODE('\0', 'd', 'u', 'a'), "Duala"}, + {MAKECODE('\0', 'd', 'u', 't'), "Dutch"}, + {MAKECODE('\0', 'n', 'l', 'd'), "Dutch"}, + {MAKECODE('\0', 'd', 'u', 'm'), "Dutch, Middle (ca. 1050-1350)"}, + {MAKECODE('\0', 'd', 'y', 'u'), "Dyula"}, + {MAKECODE('\0', 'd', 'z', 'o'), "Dzongkha"}, + {MAKECODE('\0', 'e', 'f', 'i'), "Efik"}, + {MAKECODE('\0', 'e', 'g', 'y'), "Egyptian (Ancient)"}, + {MAKECODE('\0', 'e', 'k', 'a'), "Ekajuk"}, + {MAKECODE('\0', 'e', 'l', 'x'), "Elamite"}, + {MAKECODE('\0', 'e', 'n', 'g'), "English"}, + {MAKECODE('\0', 'e', 'n', 'm'), "English, Middle (1100-1500)"}, + {MAKECODE('\0', 'a', 'n', 'g'), "English, Old (ca.450-1100)"}, + {MAKECODE('\0', 'm', 'y', 'v'), "Erzya"}, + {MAKECODE('\0', 'e', 'p', 'o'), "Esperanto"}, + {MAKECODE('\0', 'e', 's', 't'), "Estonian"}, + {MAKECODE('\0', 'e', 'w', 'e'), "Ewe"}, + {MAKECODE('\0', 'e', 'w', 'o'), "Ewondo"}, + {MAKECODE('\0', 'f', 'a', 'n'), "Fang"}, + {MAKECODE('\0', 'f', 'a', 't'), "Fanti"}, + {MAKECODE('\0', 'f', 'a', 'o'), "Faroese"}, + {MAKECODE('\0', 'f', 'i', 'j'), "Fijian"}, + {MAKECODE('\0', 'f', 'i', 'l'), "Filipino"}, + {MAKECODE('\0', 'f', 'i', 'n'), "Finnish"}, + {MAKECODE('\0', 'f', 'i', 'u'), "Finno-Ugrian (Other)"}, + {MAKECODE('\0', 'd', 'u', 't'), "Flemish"}, + {MAKECODE('\0', 'n', 'l', 'd'), "Flemish"}, + {MAKECODE('\0', 'f', 'o', 'n'), "Fon"}, + {MAKECODE('\0', 'f', 'r', 'e'), "French"}, + {MAKECODE('\0', 'f', 'r', 'a'), "French"}, + {MAKECODE('\0', 'f', 'r', 'm'), "French, Middle (ca.1400-1600)"}, + {MAKECODE('\0', 'f', 'r', 'o'), "French, Old (842-ca.1400)"}, + {MAKECODE('\0', 'f', 'r', 'y'), "Frisian"}, + {MAKECODE('\0', 'f', 'u', 'r'), "Friulian"}, + {MAKECODE('\0', 'f', 'u', 'l'), "Fulah"}, + {MAKECODE('\0', 'g', 'a', 'a'), "Ga"}, + {MAKECODE('\0', 'g', 'l', 'a'), "Gaelic"}, + {MAKECODE('\0', 'g', 'l', 'g'), "Gallegan"}, + {MAKECODE('\0', 'l', 'u', 'g'), "Ganda"}, + {MAKECODE('\0', 'g', 'a', 'y'), "Gayo"}, + {MAKECODE('\0', 'g', 'b', 'a'), "Gbaya"}, + {MAKECODE('\0', 'g', 'e', 'z'), "Geez"}, + {MAKECODE('\0', 'g', 'e', 'o'), "Georgian"}, + {MAKECODE('\0', 'k', 'a', 't'), "Georgian"}, + {MAKECODE('\0', 'g', 'e', 'r'), "German"}, + {MAKECODE('\0', 'd', 'e', 'u'), "German"}, + {MAKECODE('\0', 'n', 'd', 's'), "German, Low"}, + {MAKECODE('\0', 'g', 'm', 'h'), "German, Middle High (ca.1050-1500)"}, + {MAKECODE('\0', 'g', 'o', 'h'), "German, Old High (ca.750-1050)"}, + {MAKECODE('\0', 'g', 's', 'w'), "German, Swiss German"}, + {MAKECODE('\0', 'g', 'e', 'm'), "Germanic (Other)"}, + {MAKECODE('\0', 'k', 'i', 'k'), "Gikuyu"}, + {MAKECODE('\0', 'g', 'i', 'l'), "Gilbertese"}, + {MAKECODE('\0', 'g', 'o', 'n'), "Gondi"}, + {MAKECODE('\0', 'g', 'o', 'r'), "Gorontalo"}, + {MAKECODE('\0', 'g', 'o', 't'), "Gothic"}, + {MAKECODE('\0', 'g', 'r', 'b'), "Grebo"}, + {MAKECODE('\0', 'g', 'r', 'c'), "Greek, Ancient (to 1453)"}, + {MAKECODE('\0', 'g', 'r', 'e'), "Greek, Modern (1453-)"}, + {MAKECODE('\0', 'e', 'l', 'l'), "Greek, Modern (1453-)"}, + {MAKECODE('\0', 'k', 'a', 'l'), "Greenlandic"}, + {MAKECODE('\0', 'g', 'r', 'n'), "Guarani"}, + {MAKECODE('\0', 'g', 'u', 'j'), "Gujarati"}, + {MAKECODE('\0', 'g', 'w', 'i'), "Gwich\xC2\xB4in"}, + {MAKECODE('\0', 'h', 'a', 'i'), "Haida"}, + {MAKECODE('\0', 'h', 'a', 't'), "Haitian"}, + {MAKECODE('\0', 'h', 'a', 't'), "Haitian Creole"}, + {MAKECODE('\0', 'h', 'a', 'u'), "Hausa"}, + {MAKECODE('\0', 'h', 'a', 'w'), "Hawaiian"}, + {MAKECODE('\0', 'h', 'e', 'b'), "Hebrew"}, + {MAKECODE('\0', 'h', 'e', 'r'), "Herero"}, + {MAKECODE('\0', 'h', 'i', 'l'), "Hiligaynon"}, + {MAKECODE('\0', 'h', 'i', 'm'), "Himachali"}, + {MAKECODE('\0', 'h', 'i', 'n'), "Hindi"}, + {MAKECODE('\0', 'h', 'm', 'o'), "Hiri Motu"}, + {MAKECODE('\0', 'h', 'i', 't'), "Hittite"}, + {MAKECODE('\0', 'h', 'm', 'n'), "Hmong"}, + {MAKECODE('\0', 'h', 'u', 'n'), "Hungarian"}, + {MAKECODE('\0', 'h', 'u', 'p'), "Hupa"}, + {MAKECODE('\0', 'i', 'b', 'a'), "Iban"}, + {MAKECODE('\0', 'i', 'c', 'e'), "Icelandic"}, + {MAKECODE('\0', 'i', 's', 'l'), "Icelandic"}, + {MAKECODE('\0', 'i', 'd', 'o'), "Ido"}, + {MAKECODE('\0', 'i', 'b', 'o'), "Igbo"}, + {MAKECODE('\0', 'i', 'j', 'o'), "Ijo"}, + {MAKECODE('\0', 'i', 'l', 'o'), "Iloko"}, + {MAKECODE('\0', 's', 'm', 'n'), "Inari Sami"}, + {MAKECODE('\0', 'i', 'n', 'c'), "Indic (Other)"}, + {MAKECODE('\0', 'i', 'n', 'e'), "Indo-European (Other)"}, + {MAKECODE('\0', 'i', 'n', 'd'), "Indonesian"}, + {MAKECODE('\0', 'i', 'n', 'h'), "Ingush"}, + {MAKECODE('\0', 'i', 'n', 'a'), "Auxiliary Language Association)"}, + {MAKECODE('\0', 'i', 'l', 'e'), "Interlingue"}, + {MAKECODE('\0', 'i', 'k', 'u'), "Inuktitut"}, + {MAKECODE('\0', 'i', 'p', 'k'), "Inupiaq"}, + {MAKECODE('\0', 'i', 'r', 'a'), "Iranian (Other)"}, + {MAKECODE('\0', 'g', 'l', 'e'), "Irish"}, + {MAKECODE('\0', 'm', 'g', 'a'), "Irish, Middle (900-1200)"}, + {MAKECODE('\0', 's', 'g', 'a'), "Irish, Old (to 900)"}, + {MAKECODE('\0', 'i', 'r', 'o'), "Iroquoian languages"}, + {MAKECODE('\0', 'i', 't', 'a'), "Italian"}, + {MAKECODE('\0', 'j', 'p', 'n'), "Japanese"}, + {MAKECODE('\0', 'j', 'a', 'v'), "Javanese"}, + {MAKECODE('\0', 'j', 'r', 'b'), "Judeo-Arabic"}, + {MAKECODE('\0', 'j', 'p', 'r'), "Judeo-Persian"}, + {MAKECODE('\0', 'k', 'b', 'd'), "Kabardian"}, + {MAKECODE('\0', 'k', 'a', 'b'), "Kabyle"}, + {MAKECODE('\0', 'k', 'a', 'c'), "Kachin"}, + {MAKECODE('\0', 'k', 'a', 'l'), "Kalaallisut"}, + {MAKECODE('\0', 'x', 'a', 'l'), "Kalmyk"}, + {MAKECODE('\0', 'k', 'a', 'm'), "Kamba"}, + {MAKECODE('\0', 'k', 'a', 'n'), "Kannada"}, + {MAKECODE('\0', 'k', 'a', 'u'), "Kanuri"}, + {MAKECODE('\0', 'k', 'r', 'c'), "Karachay-Balkar"}, + {MAKECODE('\0', 'k', 'a', 'a'), "Kara-Kalpak"}, + {MAKECODE('\0', 'k', 'a', 'r'), "Karen"}, + {MAKECODE('\0', 'k', 'a', 's'), "Kashmiri"}, + {MAKECODE('\0', 'c', 's', 'b'), "Kashubian"}, + {MAKECODE('\0', 'k', 'a', 'w'), "Kawi"}, + {MAKECODE('\0', 'k', 'a', 'z'), "Kazakh"}, + {MAKECODE('\0', 'k', 'h', 'a'), "Khasi"}, + {MAKECODE('\0', 'k', 'h', 'm'), "Khmer"}, + {MAKECODE('\0', 'k', 'h', 'i'), "Khoisan (Other)"}, + {MAKECODE('\0', 'k', 'h', 'o'), "Khotanese"}, + {MAKECODE('\0', 'k', 'i', 'k'), "Kikuyu"}, + {MAKECODE('\0', 'k', 'm', 'b'), "Kimbundu"}, + {MAKECODE('\0', 'k', 'i', 'n'), "Kinyarwanda"}, + {MAKECODE('\0', 'k', 'i', 'r'), "Kirghiz"}, + {MAKECODE('\0', 't', 'l', 'h'), "Klingon"}, + {MAKECODE('\0', 'k', 'o', 'm'), "Komi"}, + {MAKECODE('\0', 'k', 'o', 'n'), "Kongo"}, + {MAKECODE('\0', 'k', 'o', 'k'), "Konkani"}, + {MAKECODE('\0', 'k', 'o', 'r'), "Korean"}, + {MAKECODE('\0', 'k', 'o', 's'), "Kosraean"}, + {MAKECODE('\0', 'k', 'p', 'e'), "Kpelle"}, + {MAKECODE('\0', 'k', 'r', 'o'), "Kru"}, + {MAKECODE('\0', 'k', 'u', 'a'), "Kuanyama"}, + {MAKECODE('\0', 'k', 'u', 'm'), "Kumyk"}, + {MAKECODE('\0', 'k', 'u', 'r'), "Kurdish"}, + {MAKECODE('\0', 'k', 'r', 'u'), "Kurukh"}, + {MAKECODE('\0', 'k', 'u', 't'), "Kutenai"}, + {MAKECODE('\0', 'k', 'u', 'a'), "Kwanyama, Kuanyama"}, + {MAKECODE('\0', 'l', 'a', 'd'), "Ladino"}, + {MAKECODE('\0', 'l', 'a', 'h'), "Lahnda"}, + {MAKECODE('\0', 'l', 'a', 'm'), "Lamba"}, + {MAKECODE('\0', 'l', 'a', 'o'), "Lao"}, + {MAKECODE('\0', 'l', 'a', 't'), "Latin"}, + {MAKECODE('\0', 'l', 'a', 'v'), "Latvian"}, + {MAKECODE('\0', 'l', 't', 'z'), "Letzeburgesch"}, + {MAKECODE('\0', 'l', 'e', 'z'), "Lezghian"}, + {MAKECODE('\0', 'l', 'i', 'm'), "Limburgan"}, + {MAKECODE('\0', 'l', 'i', 'm'), "Limburger"}, + {MAKECODE('\0', 'l', 'i', 'm'), "Limburgish"}, + {MAKECODE('\0', 'l', 'i', 'n'), "Lingala"}, + {MAKECODE('\0', 'l', 'i', 't'), "Lithuanian"}, + {MAKECODE('\0', 'j', 'b', 'o'), "Lojban"}, + {MAKECODE('\0', 'n', 'd', 's'), "Low German"}, + {MAKECODE('\0', 'n', 'd', 's'), "Low Saxon"}, + {MAKECODE('\0', 'd', 's', 'b'), "Lower Sorbian"}, + {MAKECODE('\0', 'l', 'o', 'z'), "Lozi"}, + {MAKECODE('\0', 'l', 'u', 'b'), "Luba-Katanga"}, + {MAKECODE('\0', 'l', 'u', 'a'), "Luba-Lulua"}, + {MAKECODE('\0', 'l', 'u', 'i'), "Luiseno"}, + {MAKECODE('\0', 's', 'm', 'j'), "Lule Sami"}, + {MAKECODE('\0', 'l', 'u', 'n'), "Lunda"}, + {MAKECODE('\0', 'l', 'u', 'o'), "Luo (Kenya and Tanzania)"}, + {MAKECODE('\0', 'l', 'u', 's'), "Lushai"}, + {MAKECODE('\0', 'l', 't', 'z'), "Luxembourgish"}, + {MAKECODE('\0', 'm', 'a', 'c'), "Macedonian"}, + {MAKECODE('\0', 'm', 'k', 'd'), "Macedonian"}, + {MAKECODE('\0', 'm', 'a', 'd'), "Madurese"}, + {MAKECODE('\0', 'm', 'a', 'g'), "Magahi"}, + {MAKECODE('\0', 'm', 'a', 'i'), "Maithili"}, + {MAKECODE('\0', 'm', 'a', 'k'), "Makasar"}, + {MAKECODE('\0', 'm', 'l', 'g'), "Malagasy"}, + {MAKECODE('\0', 'm', 'a', 'y'), "Malay"}, + {MAKECODE('\0', 'm', 's', 'a'), "Malay"}, + {MAKECODE('\0', 'm', 'a', 'l'), "Malayalam"}, + {MAKECODE('\0', 'm', 'l', 't'), "Maltese"}, + {MAKECODE('\0', 'm', 'n', 'c'), "Manchu"}, + {MAKECODE('\0', 'm', 'd', 'r'), "Mandar"}, + {MAKECODE('\0', 'm', 'a', 'n'), "Mandingo"}, + {MAKECODE('\0', 'm', 'n', 'i'), "Manipuri"}, + {MAKECODE('\0', 'm', 'n', 'o'), "Manobo languages"}, + {MAKECODE('\0', 'g', 'l', 'v'), "Manx"}, + {MAKECODE('\0', 'm', 'a', 'o'), "Maori"}, + {MAKECODE('\0', 'm', 'r', 'i'), "Maori"}, + {MAKECODE('\0', 'm', 'a', 'r'), "Marathi"}, + {MAKECODE('\0', 'c', 'h', 'm'), "Mari"}, + {MAKECODE('\0', 'm', 'a', 'h'), "Marshallese"}, + {MAKECODE('\0', 'm', 'w', 'r'), "Marwari"}, + {MAKECODE('\0', 'm', 'a', 's'), "Masai"}, + {MAKECODE('\0', 'm', 'y', 'n'), "Mayan languages"}, + {MAKECODE('\0', 'm', 'e', 'n'), "Mende"}, + {MAKECODE('\0', 'm', 'i', 'c'), "Micmac"}, + {MAKECODE('\0', 'm', 'i', 'c'), "Mi'kmaq"}, + {MAKECODE('\0', 'm', 'i', 'n'), "Minangkabau"}, + {MAKECODE('\0', 'm', 'w', 'l'), "Mirandese"}, + {MAKECODE('\0', 'm', 'i', 's'), "Miscellaneous languages"}, + {MAKECODE('\0', 'm', 'o', 'h'), "Mohawk"}, + {MAKECODE('\0', 'm', 'd', 'f'), "Moksha"}, + {MAKECODE('\0', 'm', 'o', 'l'), "Moldavian"}, + {MAKECODE('\0', 'm', 'k', 'h'), "Mon-Khmer (Other)"}, + {MAKECODE('\0', 'l', 'o', 'l'), "Mongo"}, + {MAKECODE('\0', 'm', 'o', 'n'), "Mongolian"}, + {MAKECODE('\0', 'm', 'o', 's'), "Mossi"}, + {MAKECODE('\0', 'm', 'u', 'l'), "Multiple languages"}, + {MAKECODE('\0', 'm', 'u', 'n'), "Munda languages"}, + {MAKECODE('\0', 'n', 'a', 'h'), "Nahuatl"}, + {MAKECODE('\0', 'n', 'a', 'u'), "Nauru"}, + {MAKECODE('\0', 'n', 'a', 'v'), "Navaho, Navajo"}, + {MAKECODE('\0', 'n', 'a', 'v'), "Navajo"}, + {MAKECODE('\0', 'n', 'd', 'e'), "Ndebele, North"}, + {MAKECODE('\0', 'n', 'b', 'l'), "Ndebele, South"}, + {MAKECODE('\0', 'n', 'd', 'o'), "Ndonga"}, + {MAKECODE('\0', 'n', 'a', 'p'), "Neapolitan"}, + {MAKECODE('\0', 'n', 'e', 'w'), "Nepal Bhasa"}, + {MAKECODE('\0', 'n', 'e', 'p'), "Nepali"}, + {MAKECODE('\0', 'n', 'e', 'w'), "Newari"}, + {MAKECODE('\0', 'n', 'i', 'a'), "Nias"}, + {MAKECODE('\0', 'n', 'i', 'c'), "Niger-Kordofanian (Other)"}, + {MAKECODE('\0', 's', 's', 'a'), "Nilo-Saharan (Other)"}, + {MAKECODE('\0', 'n', 'i', 'u'), "Niuean"}, + {MAKECODE('\0', 'z', 'x', 'x'), "No linguistic content"}, + {MAKECODE('\0', 'n', 'o', 'g'), "Nogai"}, + {MAKECODE('\0', 'n', 'o', 'n'), "Norse, Old"}, + {MAKECODE('\0', 'n', 'a', 'i'), "North American Indian (Other)"}, + {MAKECODE('\0', 's', 'm', 'e'), "Northern Sami"}, + {MAKECODE('\0', 'n', 's', 'o'), "Northern Sotho"}, + {MAKECODE('\0', 'n', 'd', 'e'), "North Ndebele"}, + {MAKECODE('\0', 'n', 'o', 'r'), "Norwegian"}, + {MAKECODE('\0', 'n', 'o', 'b'), "Norwegian Bokm\xC3\xA5l"}, + {MAKECODE('\0', 'n', 'n', 'o'), "Norwegian Nynorsk"}, + {MAKECODE('\0', 'n', 'u', 'b'), "Nubian languages"}, + {MAKECODE('\0', 'n', 'y', 'm'), "Nyamwezi"}, + {MAKECODE('\0', 'n', 'y', 'a'), "Nyanja"}, + {MAKECODE('\0', 'n', 'y', 'n'), "Nyankole"}, + {MAKECODE('\0', 'n', 'n', 'o'), "Nynorsk, Norwegian"}, + {MAKECODE('\0', 'n', 'y', 'o'), "Nyoro"}, + {MAKECODE('\0', 'n', 'z', 'i'), "Nzima"}, + {MAKECODE('\0', 'o', 'c', 'i'), "Occitan (post 1500)"}, + {MAKECODE('\0', 'o', 'j', 'i'), "Ojibwa"}, + {MAKECODE('\0', 'c', 'h', 'u'), "Old Bulgarian"}, + {MAKECODE('\0', 'c', 'h', 'u'), "Old Church Slavonic"}, + {MAKECODE('\0', 'n', 'w', 'c'), "Old Newari"}, + {MAKECODE('\0', 'c', 'h', 'u'), "Old Slavonic"}, + {MAKECODE('\0', 'o', 'r', 'i'), "Oriya"}, + {MAKECODE('\0', 'o', 'r', 'm'), "Oromo"}, + {MAKECODE('\0', 'o', 's', 'a'), "Osage"}, + {MAKECODE('\0', 'o', 's', 's'), "Ossetian"}, + {MAKECODE('\0', 'o', 's', 's'), "Ossetic"}, + {MAKECODE('\0', 'o', 't', 'o'), "Otomian languages"}, + {MAKECODE('\0', 'p', 'a', 'l'), "Pahlavi"}, + {MAKECODE('\0', 'p', 'a', 'u'), "Palauan"}, + {MAKECODE('\0', 'p', 'l', 'i'), "Pali"}, + {MAKECODE('\0', 'p', 'a', 'm'), "Pampanga"}, + {MAKECODE('\0', 'p', 'a', 'g'), "Pangasinan"}, + {MAKECODE('\0', 'p', 'a', 'n'), "Panjabi"}, + {MAKECODE('\0', 'p', 'a', 'p'), "Papiamento"}, + {MAKECODE('\0', 'p', 'a', 'a'), "Papuan (Other)"}, + {MAKECODE('\0', 'n', 's', 'o'), "Pedi"}, + {MAKECODE('\0', 'p', 'e', 'r'), "Persian"}, + {MAKECODE('\0', 'f', 'a', 's'), "Persian"}, + {MAKECODE('\0', 'p', 'e', 'o'), "Persian, Old (ca.600-400 B.C.)"}, + {MAKECODE('\0', 'p', 'h', 'i'), "Philippine (Other)"}, + {MAKECODE('\0', 'p', 'h', 'n'), "Phoenician"}, + {MAKECODE('\0', 'f', 'i', 'l'), "Pilipino"}, + {MAKECODE('\0', 'p', 'o', 'n'), "Pohnpeian"}, + {MAKECODE('\0', 'p', 'o', 'l'), "Polish"}, + {MAKECODE('\0', 'p', 'o', 'r'), "Portuguese"}, + // pob = unofficial language code for Brazilian Portuguese + {MAKECODE('\0', 'p', 'o', 'b'), "Portuguese (Brazil)"}, + {MAKECODE('\0', 'p', 'r', 'a'), "Prakrit languages"}, + {MAKECODE('\0', 'o', 'c', 'i'), "Proven\xC3\xA7" + "al"}, + {MAKECODE('\0', 'p', 'r', 'o'), "Proven\xC3\xA7" + "al, Old (to 1500)"}, + {MAKECODE('\0', 'p', 'a', 'n'), "Punjabi"}, + {MAKECODE('\0', 'p', 'u', 's'), "Pushto"}, + {MAKECODE('\0', 'q', 'u', 'e'), "Quechua"}, + {MAKECODE('\0', 'r', 'o', 'h'), "Raeto-Romance"}, + {MAKECODE('\0', 'r', 'a', 'j'), "Rajasthani"}, + {MAKECODE('\0', 'r', 'a', 'p'), "Rapanui"}, + {MAKECODE('\0', 'r', 'a', 'r'), "Rarotongan"}, + // { "qaa-qtz", "Reserved for local use" }, + {MAKECODE('\0', 'r', 'o', 'a'), "Romance (Other)"}, + {MAKECODE('\0', 'r', 'u', 'm'), "Romanian"}, + {MAKECODE('\0', 'r', 'o', 'n'), "Romanian"}, + {MAKECODE('\0', 'r', 'o', 'm'), "Romany"}, + {MAKECODE('\0', 'r', 'u', 'n'), "Rundi"}, + {MAKECODE('\0', 'r', 'u', 's'), "Russian"}, + {MAKECODE('\0', 's', 'a', 'l'), "Salishan languages"}, + {MAKECODE('\0', 's', 'a', 'm'), "Samaritan Aramaic"}, + {MAKECODE('\0', 's', 'm', 'i'), "Sami languages (Other)"}, + {MAKECODE('\0', 's', 'm', 'o'), "Samoan"}, + {MAKECODE('\0', 's', 'a', 'd'), "Sandawe"}, + {MAKECODE('\0', 's', 'a', 'g'), "Sango"}, + {MAKECODE('\0', 's', 'a', 'n'), "Sanskrit"}, + {MAKECODE('\0', 's', 'a', 't'), "Santali"}, + {MAKECODE('\0', 's', 'r', 'd'), "Sardinian"}, + {MAKECODE('\0', 's', 'a', 's'), "Sasak"}, + {MAKECODE('\0', 'n', 'd', 's'), "Saxon, Low"}, + {MAKECODE('\0', 's', 'c', 'o'), "Scots"}, + {MAKECODE('\0', 'g', 'l', 'a'), "Scottish Gaelic"}, + {MAKECODE('\0', 's', 'e', 'l'), "Selkup"}, + {MAKECODE('\0', 's', 'e', 'm'), "Semitic (Other)"}, + {MAKECODE('\0', 'n', 's', 'o'), "Sepedi"}, + {MAKECODE('\0', 's', 'c', 'c'), "Serbian"}, + {MAKECODE('\0', 's', 'r', 'p'), "Serbian"}, + {MAKECODE('\0', 's', 'r', 'r'), "Serer"}, + {MAKECODE('\0', 's', 'h', 'n'), "Shan"}, + {MAKECODE('\0', 's', 'n', 'a'), "Shona"}, + {MAKECODE('\0', 'i', 'i', 'i'), "Sichuan Yi"}, + {MAKECODE('\0', 's', 'c', 'n'), "Sicilian"}, + {MAKECODE('\0', 's', 'i', 'd'), "Sidamo"}, + {MAKECODE('\0', 's', 'g', 'n'), "Sign languages"}, + {MAKECODE('\0', 'b', 'l', 'a'), "Siksika"}, + {MAKECODE('\0', 's', 'n', 'd'), "Sindhi"}, + {MAKECODE('\0', 's', 'i', 'n'), "Sinhala"}, + {MAKECODE('\0', 's', 'i', 'n'), "Sinhalese"}, + {MAKECODE('\0', 's', 'i', 't'), "Sino-Tibetan (Other)"}, + {MAKECODE('\0', 's', 'i', 'o'), "Siouan languages"}, + {MAKECODE('\0', 's', 'm', 's'), "Skolt Sami"}, + {MAKECODE('\0', 'd', 'e', 'n'), "Slave (Athapascan)"}, + {MAKECODE('\0', 's', 'l', 'a'), "Slavic (Other)"}, + {MAKECODE('\0', 's', 'l', 'o'), "Slovak"}, + {MAKECODE('\0', 's', 'l', 'k'), "Slovak"}, + {MAKECODE('\0', 's', 'l', 'v'), "Slovenian"}, + {MAKECODE('\0', 's', 'o', 'g'), "Sogdian"}, + {MAKECODE('\0', 's', 'o', 'm'), "Somali"}, + {MAKECODE('\0', 's', 'o', 'n'), "Songhai"}, + {MAKECODE('\0', 's', 'n', 'k'), "Soninke"}, + {MAKECODE('\0', 'w', 'e', 'n'), "Sorbian languages"}, + {MAKECODE('\0', 'n', 's', 'o'), "Sotho, Northern"}, + {MAKECODE('\0', 's', 'o', 't'), "Sotho, Southern"}, + {MAKECODE('\0', 's', 'a', 'i'), "South American Indian (Other)"}, + {MAKECODE('\0', 's', 'm', 'a'), "Southern Sami"}, + {MAKECODE('\0', 'n', 'b', 'l'), "South Ndebele"}, + {MAKECODE('\0', 's', 'p', 'a'), "Castilian"}, + {MAKECODE('\0', 's', 'u', 'k'), "Sukuma"}, + {MAKECODE('\0', 's', 'u', 'x'), "Sumerian"}, + {MAKECODE('\0', 's', 'u', 'n'), "Sundanese"}, + {MAKECODE('\0', 's', 'u', 's'), "Susu"}, + {MAKECODE('\0', 's', 'w', 'a'), "Swahili"}, + {MAKECODE('\0', 's', 's', 'w'), "Swati"}, + {MAKECODE('\0', 's', 'w', 'e'), "Swedish"}, + {MAKECODE('\0', 's', 'y', 'r'), "Syriac"}, + {MAKECODE('\0', 't', 'g', 'l'), "Tagalog"}, + {MAKECODE('\0', 't', 'a', 'h'), "Tahitian"}, + {MAKECODE('\0', 't', 'a', 'i'), "Tai (Other)"}, + {MAKECODE('\0', 't', 'g', 'k'), "Tajik"}, + {MAKECODE('\0', 't', 'm', 'h'), "Tamashek"}, + {MAKECODE('\0', 't', 'a', 'm'), "Tamil"}, + {MAKECODE('\0', 't', 'a', 't'), "Tatar"}, + {MAKECODE('\0', 't', 'e', 'l'), "Telugu"}, + {MAKECODE('\0', 't', 'e', 'r'), "Tereno"}, + {MAKECODE('\0', 't', 'e', 't'), "Tetum"}, + {MAKECODE('\0', 't', 'h', 'a'), "Thai"}, + {MAKECODE('\0', 't', 'i', 'b'), "Tibetan"}, + {MAKECODE('\0', 'b', 'o', 'd'), "Tibetan"}, + {MAKECODE('\0', 't', 'i', 'g'), "Tigre"}, + {MAKECODE('\0', 't', 'i', 'r'), "Tigrinya"}, + {MAKECODE('\0', 't', 'e', 'm'), "Timne"}, + {MAKECODE('\0', 't', 'i', 'v'), "Tiv"}, + {MAKECODE('\0', 't', 'l', 'h'), "tlhIngan-Hol"}, + {MAKECODE('\0', 't', 'l', 'i'), "Tlingit"}, + {MAKECODE('\0', 't', 'p', 'i'), "Tok Pisin"}, + {MAKECODE('\0', 't', 'k', 'l'), "Tokelau"}, + {MAKECODE('\0', 't', 'o', 'g'), "Tonga (Nyasa)"}, + {MAKECODE('\0', 't', 'o', 'n'), "Tonga (Tonga Islands)"}, + {MAKECODE('\0', 't', 's', 'i'), "Tsimshian"}, + {MAKECODE('\0', 't', 's', 'o'), "Tsonga"}, + {MAKECODE('\0', 't', 's', 'n'), "Tswana"}, + {MAKECODE('\0', 't', 'u', 'm'), "Tumbuka"}, + {MAKECODE('\0', 't', 'u', 'p'), "Tupi languages"}, + {MAKECODE('\0', 't', 'u', 'r'), "Turkish"}, + {MAKECODE('\0', 'o', 't', 'a'), "Turkish, Ottoman (1500-1928)"}, + {MAKECODE('\0', 't', 'u', 'k'), "Turkmen"}, + {MAKECODE('\0', 't', 'v', 'l'), "Tuvalu"}, + {MAKECODE('\0', 't', 'y', 'v'), "Tuvinian"}, + {MAKECODE('\0', 't', 'w', 'i'), "Twi"}, + {MAKECODE('\0', 'u', 'd', 'm'), "Udmurt"}, + {MAKECODE('\0', 'u', 'g', 'a'), "Ugaritic"}, + {MAKECODE('\0', 'u', 'i', 'g'), "Uighur"}, + {MAKECODE('\0', 'u', 'k', 'r'), "Ukrainian"}, + {MAKECODE('\0', 'u', 'm', 'b'), "Umbundu"}, + {MAKECODE('\0', 'u', 'n', 'd'), "Undetermined"}, + {MAKECODE('\0', 'h', 's', 'b'), "Upper Sorbian"}, + {MAKECODE('\0', 'u', 'r', 'd'), "Urdu"}, + {MAKECODE('\0', 'u', 'i', 'g'), "Uyghur"}, + {MAKECODE('\0', 'u', 'z', 'b'), "Uzbek"}, + {MAKECODE('\0', 'v', 'a', 'i'), "Vai"}, + {MAKECODE('\0', 'c', 'a', 't'), "Valencian"}, + {MAKECODE('\0', 'v', 'e', 'n'), "Venda"}, + {MAKECODE('\0', 'v', 'i', 'e'), "Vietnamese"}, + {MAKECODE('\0', 'v', 'o', 'l'), "Volap\xC3\xBCk"}, + {MAKECODE('\0', 'v', 'o', 't'), "Votic"}, + {MAKECODE('\0', 'w', 'a', 'k'), "Wakashan languages"}, + {MAKECODE('\0', 'w', 'a', 'l'), "Walamo"}, + {MAKECODE('\0', 'w', 'l', 'n'), "Walloon"}, + {MAKECODE('\0', 'w', 'a', 'r'), "Waray"}, + {MAKECODE('\0', 'w', 'a', 's'), "Washo"}, + {MAKECODE('\0', 'w', 'e', 'l'), "Welsh"}, + {MAKECODE('\0', 'c', 'y', 'm'), "Welsh"}, + {MAKECODE('\0', 'w', 'o', 'l'), "Wolof"}, + {MAKECODE('\0', 'x', 'h', 'o'), "Xhosa"}, + {MAKECODE('\0', 's', 'a', 'h'), "Yakut"}, + {MAKECODE('\0', 'y', 'a', 'o'), "Yao"}, + {MAKECODE('\0', 'y', 'a', 'p'), "Yapese"}, + {MAKECODE('\0', 'y', 'i', 'd'), "Yiddish"}, + {MAKECODE('\0', 'y', 'o', 'r'), "Yoruba"}, + {MAKECODE('\0', 'y', 'p', 'k'), "Yupik languages"}, + {MAKECODE('\0', 'z', 'n', 'd'), "Zande"}, + {MAKECODE('\0', 'z', 'a', 'p'), "Zapotec"}, + {MAKECODE('\0', 'z', 'e', 'n'), "Zenaga"}, + {MAKECODE('\0', 'z', 'h', 'a'), "Zhuang"}, + {MAKECODE('\0', 'z', 'u', 'l'), "Zulu"}, + {MAKECODE('\0', 'z', 'u', 'n'), "Zuni"}, +}}; +// clang-format on + +// clang-format off +const std::array LanguageCodes = {{ + {"aa", "aar", NULL, NULL}, + {"ab", "abk", NULL, NULL}, + {"af", "afr", NULL, NULL}, + {"ak", "aka", NULL, NULL}, + {"am", "amh", NULL, NULL}, + {"ar", "ara", NULL, NULL}, + {"an", "arg", NULL, NULL}, + {"as", "asm", NULL, NULL}, + {"av", "ava", NULL, NULL}, + {"ae", "ave", NULL, NULL}, + {"ay", "aym", NULL, NULL}, + {"az", "aze", NULL, NULL}, + {"ba", "bak", NULL, NULL}, + {"bm", "bam", NULL, NULL}, + {"be", "bel", NULL, NULL}, + {"bn", "ben", NULL, NULL}, + {"bh", "bih", NULL, NULL}, + {"bi", "bis", NULL, NULL}, + {"bo", "tib", NULL, "bod"}, + {"bs", "bos", NULL, NULL}, + {"br", "bre", NULL, NULL}, + {"bg", "bul", NULL, NULL}, + {"ca", "cat", NULL, NULL}, + {"cs", "cze", "ces", "ces"}, + {"ch", "cha", NULL, NULL}, + {"ce", "che", NULL, NULL}, + {"cu", "chu", NULL, NULL}, + {"cv", "chv", NULL, NULL}, + {"kw", "cor", NULL, NULL}, + {"co", "cos", NULL, NULL}, + {"cr", "cre", NULL, NULL}, + {"cy", "wel", NULL, "cym"}, + {"da", "dan", NULL, NULL}, + {"de", "ger", "deu", "deu"}, + {"dv", "div", NULL, NULL}, + {"dz", "dzo", NULL, NULL}, + {"el", "gre", "ell", "ell"}, + {"en", "eng", NULL, NULL}, + {"eo", "epo", NULL, NULL}, + {"et", "est", NULL, NULL}, + {"eu", "baq", NULL, "eus"}, + {"ee", "ewe", NULL, NULL}, + {"fo", "fao", NULL, NULL}, + {"fa", "per", NULL, "fas"}, + {"fj", "fij", NULL, NULL}, + {"fi", "fin", NULL, NULL}, + {"fr", "fre", "fra", "fra"}, + {"fy", "fry", NULL, NULL}, + {"ff", "ful", NULL, NULL}, + {"gd", "gla", NULL, NULL}, + {"ga", "gle", NULL, NULL}, + {"gl", "glg", NULL, NULL}, + {"gv", "glv", NULL, NULL}, + {"gn", "grn", NULL, NULL}, + {"gu", "guj", NULL, NULL}, + {"ht", "hat", NULL, NULL}, + {"ha", "hau", NULL, NULL}, + {"he", "heb", NULL, NULL}, + {"hz", "her", NULL, NULL}, + {"hi", "hin", NULL, NULL}, + {"ho", "hmo", NULL, NULL}, + {"hr", "hrv", NULL, NULL}, + {"hu", "hun", NULL, NULL}, + {"hy", "arm", NULL, "hye"}, + {"ig", "ibo", NULL, NULL}, + {"io", "ido", NULL, NULL}, + {"ii", "iii", NULL, NULL}, + {"iu", "iku", NULL, NULL}, + {"ie", "ile", NULL, NULL}, + {"ia", "ina", NULL, NULL}, + {"id", "ind", NULL, NULL}, + {"ik", "ipk", NULL, NULL}, + {"is", "ice", "isl", "isl"}, + {"it", "ita", NULL, NULL}, + {"jv", "jav", NULL, NULL}, + {"ja", "jpn", NULL, NULL}, + {"kl", "kal", NULL, NULL}, + {"kn", "kan", NULL, NULL}, + {"ks", "kas", NULL, NULL}, + {"ka", "geo", NULL, "kat"}, + {"kr", "kau", NULL, NULL}, + {"kk", "kaz", NULL, NULL}, + {"km", "khm", NULL, NULL}, + {"ki", "kik", NULL, NULL}, + {"rw", "kin", NULL, NULL}, + {"ky", "kir", NULL, NULL}, + {"kv", "kom", NULL, NULL}, + {"kg", "kon", NULL, NULL}, + {"ko", "kor", NULL, NULL}, + {"kj", "kua", NULL, NULL}, + {"ku", "kur", NULL, NULL}, + {"lo", "lao", NULL, NULL}, + {"la", "lat", NULL, NULL}, + {"lv", "lav", NULL, NULL}, + {"li", "lim", NULL, NULL}, + {"ln", "lin", NULL, NULL}, + {"lt", "lit", NULL, NULL}, + {"lb", "ltz", NULL, NULL}, + {"lu", "lub", NULL, NULL}, + {"lg", "lug", NULL, NULL}, + {"mk", "mac", NULL, "mdk"}, + {"mh", "mah", NULL, NULL}, + {"ml", "mal", NULL, NULL}, + {"mi", "mao", NULL, "mri"}, + {"mr", "mar", NULL, NULL}, + {"ms", "may", NULL, "msa"}, + {"mg", "mlg", NULL, NULL}, + {"mt", "mlt", NULL, NULL}, + {"mn", "mon", NULL, NULL}, + {"my", "bur", NULL, "mya"}, + {"na", "nau", NULL, NULL}, + {"nv", "nav", NULL, NULL}, + {"nr", "nbl", NULL, NULL}, + {"nd", "nde", NULL, NULL}, + {"ng", "ndo", NULL, NULL}, + {"ne", "nep", NULL, NULL}, + {"nl", "dut", "nld", "nld"}, + {"nn", "nno", NULL, NULL}, + {"nb", "nob", NULL, NULL}, + {"no", "nor", NULL, NULL}, + {"ny", "nya", NULL, NULL}, + {"oc", "oci", NULL, NULL}, + {"oj", "oji", NULL, NULL}, + {"or", "ori", NULL, NULL}, + {"om", "orm", NULL, NULL}, + {"os", "oss", NULL, NULL}, + {"pa", "pan", NULL, NULL}, + // pb / pob = unofficial language code for Brazilian Portuguese + {"pb", "pob", NULL, NULL}, + {"pi", "pli", NULL, NULL}, + {"pl", "pol", "plk", NULL}, + {"pt", "por", "ptg", NULL}, + {"ps", "pus", NULL, NULL}, + {"qu", "que", NULL, NULL}, + {"rm", "roh", NULL, NULL}, + {"ro", "rum", "ron", "ron"}, + {"rn", "run", NULL, NULL}, + {"ru", "rus", NULL, NULL}, + {"sh", "scr", NULL, NULL}, + {"sg", "sag", NULL, NULL}, + {"sa", "san", NULL, NULL}, + {"si", "sin", NULL, NULL}, + {"sk", "slo", "sky", "slk"}, + {"sl", "slv", NULL, NULL}, + {"se", "sme", NULL, NULL}, + {"sm", "smo", NULL, NULL}, + {"sn", "sna", NULL, NULL}, + {"sd", "snd", NULL, NULL}, + {"so", "som", NULL, NULL}, + {"st", "sot", NULL, NULL}, + {"es", "spa", "esp", NULL}, + {"sq", "alb", NULL, "sqi"}, + {"sc", "srd", NULL, NULL}, + {"sr", "srp", NULL, NULL}, + {"ss", "ssw", NULL, NULL}, + {"su", "sun", NULL, NULL}, + {"sw", "swa", NULL, NULL}, + {"sv", "swe", "sve", NULL}, + {"ty", "tah", NULL, NULL}, + {"ta", "tam", NULL, NULL}, + {"tt", "tat", NULL, NULL}, + {"te", "tel", NULL, NULL}, + {"tg", "tgk", NULL, NULL}, + {"tl", "tgl", NULL, NULL}, + {"th", "tha", NULL, NULL}, + {"ti", "tir", NULL, NULL}, + {"to", "ton", NULL, NULL}, + {"tn", "tsn", NULL, NULL}, + {"ts", "tso", NULL, NULL}, + {"tk", "tuk", NULL, NULL}, + {"tr", "tur", "trk", NULL}, + {"tw", "twi", NULL, NULL}, + {"ug", "uig", NULL, NULL}, + {"uk", "ukr", NULL, NULL}, + {"ur", "urd", NULL, NULL}, + {"uz", "uzb", NULL, NULL}, + {"ve", "ven", NULL, NULL}, + {"vi", "vie", NULL, NULL}, + {"vo", "vol", NULL, NULL}, + {"wa", "wln", NULL, NULL}, + {"wo", "wol", NULL, NULL}, + {"xh", "xho", NULL, NULL}, + {"yi", "yid", NULL, NULL}, + {"yo", "yor", NULL, NULL}, + {"za", "zha", NULL, NULL}, + {"zh", "chi", "zho", "zho"}, + {"zu", "zul", NULL, NULL}, + {"zv", "und", NULL, NULL}, // Kodi intern mapping for missing "Undetermined" iso639-1 code + {"zx", "zxx", NULL, + NULL}, // Kodi intern mapping for missing "No linguistic content" iso639-1 code + {"zy", "mis", NULL, + NULL}, // Kodi intern mapping for missing "Miscellaneous languages" iso639-1 code + {"zz", "mul", NULL, NULL} // Kodi intern mapping for missing "Multiple languages" iso639-1 code +}}; +// clang-format on + +// Based on ISO 3166 +// clang-format off +const std::array RegionCodes = {{ + {"af", "afg"}, + {"ax", "ala"}, + {"al", "alb"}, + {"dz", "dza"}, + {"as", "asm"}, + {"ad", "and"}, + {"ao", "ago"}, + {"ai", "aia"}, + {"aq", "ata"}, + {"ag", "atg"}, + {"ar", "arg"}, + {"am", "arm"}, + {"aw", "abw"}, + {"au", "aus"}, + {"at", "aut"}, + {"az", "aze"}, + {"bs", "bhs"}, + {"bh", "bhr"}, + {"bd", "bgd"}, + {"bb", "brb"}, + {"by", "blr"}, + {"be", "bel"}, + {"bz", "blz"}, + {"bj", "ben"}, + {"bm", "bmu"}, + {"bt", "btn"}, + {"bo", "bol"}, + {"ba", "bih"}, + {"bw", "bwa"}, + {"bv", "bvt"}, + {"br", "bra"}, + {"io", "iot"}, + {"bn", "brn"}, + {"bg", "bgr"}, + {"bf", "bfa"}, + {"bi", "bdi"}, + {"kh", "khm"}, + {"cm", "cmr"}, + {"ca", "can"}, + {"cv", "cpv"}, + {"ky", "cym"}, + {"cf", "caf"}, + {"td", "tcd"}, + {"cl", "chl"}, + {"cn", "chn"}, + {"cx", "cxr"}, + {"co", "col"}, + {"km", "com"}, + {"cg", "cog"}, + {"cd", "cod"}, + {"ck", "cok"}, + {"cr", "cri"}, + {"ci", "civ"}, + {"hr", "hrv"}, + {"cu", "cub"}, + {"cy", "cyp"}, + {"cz", "cze"}, + {"dk", "dnk"}, + {"dj", "dji"}, + {"dm", "dma"}, + {"do", "dom"}, + {"ec", "ecu"}, + {"eg", "egy"}, + {"sv", "slv"}, + {"gq", "gnq"}, + {"er", "eri"}, + {"ee", "est"}, + {"et", "eth"}, + {"fk", "flk"}, + {"fo", "fro"}, + {"fj", "fji"}, + {"fi", "fin"}, + {"fr", "fra"}, + {"gf", "guf"}, + {"pf", "pyf"}, + {"tf", "atf"}, + {"ga", "gab"}, + {"gm", "gmb"}, + {"ge", "geo"}, + {"de", "deu"}, + {"gh", "gha"}, + {"gi", "gib"}, + {"gr", "grc"}, + {"gl", "grl"}, + {"gd", "grd"}, + {"gp", "glp"}, + {"gu", "gum"}, + {"gt", "gtm"}, + {"gg", "ggy"}, + {"gn", "gin"}, + {"gw", "gnb"}, + {"gy", "guy"}, + {"ht", "hti"}, + {"hm", "hmd"}, + {"va", "vat"}, + {"hn", "hnd"}, + {"hk", "hkg"}, + {"hu", "hun"}, + {"is", "isl"}, + {"in", "ind"}, + {"id", "idn"}, + {"ir", "irn"}, + {"iq", "irq"}, + {"ie", "irl"}, + {"im", "imn"}, + {"il", "isr"}, + {"it", "ita"}, + {"jm", "jam"}, + {"jp", "jpn"}, + {"je", "jey"}, + {"jo", "jor"}, + {"kz", "kaz"}, + {"ke", "ken"}, + {"ki", "kir"}, + {"kp", "prk"}, + {"kr", "kor"}, + {"kw", "kwt"}, + {"kg", "kgz"}, + {"la", "lao"}, + {"lv", "lva"}, + {"lb", "lbn"}, + {"ls", "lso"}, + {"lr", "lbr"}, + {"ly", "lby"}, + {"li", "lie"}, + {"lt", "ltu"}, + {"lu", "lux"}, + {"mo", "mac"}, + {"mk", "mkd"}, + {"mg", "mdg"}, + {"mw", "mwi"}, + {"my", "mys"}, + {"mv", "mdv"}, + {"ml", "mli"}, + {"mt", "mlt"}, + {"mh", "mhl"}, + {"mq", "mtq"}, + {"mr", "mrt"}, + {"mu", "mus"}, + {"yt", "myt"}, + {"mx", "mex"}, + {"fm", "fsm"}, + {"md", "mda"}, + {"mc", "mco"}, + {"mn", "mng"}, + {"me", "mne"}, + {"ms", "msr"}, + {"ma", "mar"}, + {"mz", "moz"}, + {"mm", "mmr"}, + {"na", "nam"}, + {"nr", "nru"}, + {"np", "npl"}, + {"nl", "nld"}, + {"an", "ant"}, + {"nc", "ncl"}, + {"nz", "nzl"}, + {"ni", "nic"}, + {"ne", "ner"}, + {"ng", "nga"}, + {"nu", "niu"}, + {"nf", "nfk"}, + {"mp", "mnp"}, + {"no", "nor"}, + {"om", "omn"}, + {"pk", "pak"}, + {"pw", "plw"}, + {"ps", "pse"}, + {"pa", "pan"}, + {"pg", "png"}, + {"py", "pry"}, + {"pe", "per"}, + {"ph", "phl"}, + {"pn", "pcn"}, + {"pl", "pol"}, + {"pt", "prt"}, + {"pr", "pri"}, + {"qa", "qat"}, + {"re", "reu"}, + {"ro", "rou"}, + {"ru", "rus"}, + {"rw", "rwa"}, + {"bl", "blm"}, + {"sh", "shn"}, + {"kn", "kna"}, + {"lc", "lca"}, + {"mf", "maf"}, + {"pm", "spm"}, + {"vc", "vct"}, + {"ws", "wsm"}, + {"sm", "smr"}, + {"st", "stp"}, + {"sa", "sau"}, + {"sn", "sen"}, + {"rs", "srb"}, + {"sc", "syc"}, + {"sl", "sle"}, + {"sg", "sgp"}, + {"sk", "svk"}, + {"si", "svn"}, + {"sb", "slb"}, + {"so", "som"}, + {"za", "zaf"}, + {"gs", "sgs"}, + {"es", "esp"}, + {"lk", "lka"}, + {"sd", "sdn"}, + {"sr", "sur"}, + {"sj", "sjm"}, + {"sz", "swz"}, + {"se", "swe"}, + {"ch", "che"}, + {"sy", "syr"}, + {"tw", "twn"}, + {"tj", "tjk"}, + {"tz", "tza"}, + {"th", "tha"}, + {"tl", "tls"}, + {"tg", "tgo"}, + {"tk", "tkl"}, + {"to", "ton"}, + {"tt", "tto"}, + {"tn", "tun"}, + {"tr", "tur"}, + {"tm", "tkm"}, + {"tc", "tca"}, + {"tv", "tuv"}, + {"ug", "uga"}, + {"ua", "ukr"}, + {"ae", "are"}, + {"gb", "gbr"}, + {"us", "usa"}, + {"um", "umi"}, + {"uy", "ury"}, + {"uz", "uzb"}, + {"vu", "vut"}, + {"ve", "ven"}, + {"vn", "vnm"}, + {"vg", "vgb"}, + {"vi", "vir"}, + {"wf", "wlf"}, + {"eh", "esh"}, + {"ye", "yem"}, + {"zm", "zmb"}, + {"zw", "zwe"} +}}; +// clang-format on diff --git a/xbmc/utils/LangCodeExpander.h b/xbmc/utils/LangCodeExpander.h new file mode 100644 index 0000000..5e26a65 --- /dev/null +++ b/xbmc/utils/LangCodeExpander.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include + +class TiXmlElement; + +class CLangCodeExpander +{ +public: + CLangCodeExpander(); + ~CLangCodeExpander(); + + enum LANGFORMATS + { + ISO_639_1, + ISO_639_2, + ENGLISH_NAME + }; + + void LoadUserCodes(const TiXmlElement* pRootElement); + void Clear(); + + bool Lookup(const std::string& code, std::string& desc); + bool Lookup(const int code, std::string& desc); + + /** \brief Determines if two english language names represent the same language. + * \param[in] lang1 The first language string to compare given as english language name. + * \param[in] lang2 The second language string to compare given as english language name. + * \return true if the two language strings represent the same language, false otherwise. + * For example "Abkhaz" and "Abkhazian" represent the same language. + */ + bool CompareFullLanguageNames(const std::string& lang1, const std::string& lang2); + + /** \brief Determines if two languages given as ISO 639-1, ISO 639-2/T, or ISO 639-2/B codes represent the same language. + * \param[in] code1 The first language to compare given as ISO 639-1, ISO 639-2/T, or ISO 639-2/B code. + * \param[in] code2 The second language to compare given as ISO 639-1, ISO 639-2/T, or ISO 639-2/B code. + * \return true if the two language codes represent the same language, false otherwise. + * For example "ger", "deu" and "de" represent the same language. + */ + bool CompareISO639Codes(const std::string& code1, const std::string& code2); + + /** \brief Converts a language given as 2-Char (ISO 639-1), + * 3-Char (ISO 639-2/T or ISO 639-2/B), + * or full english name string to a 2-Char (ISO 639-1) code. + * \param[out] code The 2-Char language code of the given language lang. + * \param[in] lang The language that should be converted. + * \return true if the conversion succeeded, false otherwise. + */ + bool ConvertToISO6391(const std::string& lang, std::string& code); + + /** \brief Converts a language given as 2-Char (ISO 639-1), + * 3-Char (ISO 639-2/T or ISO 639-2/B), + * or full english name string to a 3-Char ISO 639-2/B code. + * \param[in] lang The language that should be converted. + * \return The 3-Char ISO 639-2/B code of lang if that code exists, lang otherwise. + */ + std::string ConvertToISO6392B(const std::string& lang); + + /** \brief Converts a language given as 2-Char (ISO 639-1) to a 3-Char (ISO 639-2/T) code. + * \param[in] strISO6391 The language that should be converted. + * \param[out] strISO6392B The 3-Char (ISO 639-2/B) language code of the given language strISO6391. + * \param[in] checkWin32Locales Whether to also check WIN32 specific language codes. + * \return true if the conversion succeeded, false otherwise. + */ + static bool ConvertISO6391ToISO6392B(const std::string& strISO6391, std::string& strISO6392B, bool checkWin32Locales = false); + + /** \brief Converts a language given as 2-Char (ISO 639-1), + * 3-Char (ISO 639-2/T or ISO 639-2/B), + * or full english name string to a 3-Char ISO 639-2/T code. + * \param[in] strCharCode The language that should be converted. + * \param[out] strISO6392B The 3-Char (ISO 639-2/B) language code of the given language strISO6391. + * \param[in] checkWin32Locales Whether to also check WIN32 specific language codes. + * \return true if the conversion succeeded, false otherwise. + */ + bool ConvertToISO6392B(const std::string& strCharCode, std::string& strISO6392B, bool checkWin32Locales = false); + + /** \brief Converts a language given as 2-Char (ISO 639-1), + * 3-Char (ISO 639-2/T or ISO 639-2/B), + * or full english name string to a 3-Char ISO 639-2/T code. + * \param[in] strCharCode The language that should be converted. + * \param[out] strISO6392T The 3-Char (ISO 639-2/T) language code of the given language strISO6391. + * \param[in] checkWin32Locales Whether to also check WIN32 specific language codes. + * \return true if the conversion succeeded, false otherwise. + */ + bool ConvertToISO6392T(const std::string& strCharCode, std::string& strISO6392T, bool checkWin32Locales = false); + + /** \brief Converts a language given as 2-Char (ISO 639-1), + * 3-Char (ISO 639-2/T or ISO 639-2/B), + * or full english name string to a 3-Char ISO 639-2/T code. + * \param[in] lang The language that should be converted. + * \return The 3-Char ISO 639-2/T code of lang if that code exists, lang otherwise. + */ + std::string ConvertToISO6392T(const std::string& lang); + +#ifdef TARGET_WINDOWS + static bool ConvertISO31661Alpha2ToISO31661Alpha3(const std::string& strISO31661Alpha2, std::string& strISO31661Alpha3); + static bool ConvertWindowsLanguageCodeToISO6392B(const std::string& strWindowsLanguageCode, std::string& strISO6392B); +#endif + + std::vector GetLanguageNames(LANGFORMATS format = ISO_639_1, bool customNames = false); +protected: + + /** \brief Converts a language code given as a long, see #MAKECODE(a, b, c, d) + * to its string representation. + * \param[in] code The language code given as a long, see #MAKECODE(a, b, c, d). + * \param[out] ret The string representation of the given language code code. + */ + static void CodeToString(long code, std::string& ret); + + static bool LookupInISO639Tables(const std::string& code, std::string& desc); + bool LookupInUserMap(const std::string& code, std::string& desc); + + /** \brief Looks up the ISO 639-1, ISO 639-2/T, or ISO 639-2/B, whichever it finds first, + * code of the given english language name. + * \param[in] desc The english language name for which a code is looked for. + * \param[out] code The ISO 639-1, ISO 639-2/T, or ISO 639-2/B code of the given language desc. + * \return true if the a code was found, false otherwise. + */ + bool ReverseLookup(const std::string& desc, std::string& code); + + + /** \brief Looks up the user defined code of the given code or language name. + * \param[in] desc The language code or name that should be converted. + * \param[out] userCode The user defined language code of the given language desc. + * \return true if desc was found, false otherwise. + */ + bool LookupUserCode(const std::string& desc, std::string &userCode); + + typedef std::map STRINGLOOKUPTABLE; + STRINGLOOKUPTABLE m_mapUser; +}; + +extern CLangCodeExpander g_LangCodeExpander; diff --git a/xbmc/utils/LegacyPathTranslation.cpp b/xbmc/utils/LegacyPathTranslation.cpp new file mode 100644 index 0000000..0069339 --- /dev/null +++ b/xbmc/utils/LegacyPathTranslation.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2013-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "LegacyPathTranslation.h" + +#include "URL.h" +#include "utils/StringUtils.h" + +typedef struct Translator { + const char *legacyPath; + const char *newPath; +} Translator; + +// ATTENTION: Make sure the longer match strings go first +// because the string match is performed with StringUtils::StartsWith() +static Translator s_videoDbTranslator[] = { + { "videodb://1/1", "videodb://movies/genres" }, + { "videodb://1/2", "videodb://movies/titles" }, + { "videodb://1/3", "videodb://movies/years" }, + { "videodb://1/4", "videodb://movies/actors" }, + { "videodb://1/5", "videodb://movies/directors" }, + { "videodb://1/6", "videodb://movies/studios" }, + { "videodb://1/7", "videodb://movies/sets" }, + { "videodb://1/8", "videodb://movies/countries" }, + { "videodb://1/9", "videodb://movies/tags" }, + { "videodb://1", "videodb://movies" }, + { "videodb://2/1", "videodb://tvshows/genres" }, + { "videodb://2/2", "videodb://tvshows/titles" }, + { "videodb://2/3", "videodb://tvshows/years" }, + { "videodb://2/4", "videodb://tvshows/actors" }, + { "videodb://2/5", "videodb://tvshows/studios" }, + { "videodb://2/9", "videodb://tvshows/tags" }, + { "videodb://2", "videodb://tvshows" }, + { "videodb://3/1", "videodb://musicvideos/genres" }, + { "videodb://3/2", "videodb://musicvideos/titles" }, + { "videodb://3/3", "videodb://musicvideos/years" }, + { "videodb://3/4", "videodb://musicvideos/artists" }, + { "videodb://3/5", "videodb://musicvideos/albums" }, + { "videodb://3/9", "videodb://musicvideos/tags" }, + { "videodb://3", "videodb://musicvideos" }, + { "videodb://4", "videodb://recentlyaddedmovies" }, + { "videodb://5", "videodb://recentlyaddedepisodes" }, + { "videodb://6", "videodb://recentlyaddedmusicvideos" } +}; + +#define VideoDbTranslatorSize sizeof(s_videoDbTranslator) / sizeof(Translator) + +// ATTENTION: Make sure the longer match strings go first +// because the string match is performed with StringUtils::StartsWith() +static Translator s_musicDbTranslator[] = { + { "musicdb://10", "musicdb://singles" }, + { "musicdb://1", "musicdb://genres" }, + { "musicdb://2", "musicdb://artists" }, + { "musicdb://3", "musicdb://albums" }, + { "musicdb://4", "musicdb://songs" }, + { "musicdb://5/1", "musicdb://top100/albums" }, + { "musicdb://5/2", "musicdb://top100/songs" }, + { "musicdb://5", "musicdb://top100" }, + { "musicdb://6", "musicdb://recentlyaddedalbums" }, + { "musicdb://7", "musicdb://recentlyplayedalbums" }, + { "musicdb://8", "musicdb://compilations" }, + { "musicdb://9", "musicdb://years" } +}; + +#define MusicDbTranslatorSize sizeof(s_musicDbTranslator) / sizeof(Translator) + +std::string CLegacyPathTranslation::TranslateVideoDbPath(const CURL &legacyPath) +{ + return TranslatePath(legacyPath.Get(), s_videoDbTranslator, VideoDbTranslatorSize); +} + +std::string CLegacyPathTranslation::TranslateMusicDbPath(const CURL &legacyPath) +{ + return TranslatePath(legacyPath.Get(), s_musicDbTranslator, MusicDbTranslatorSize); +} + +std::string CLegacyPathTranslation::TranslateVideoDbPath(const std::string &legacyPath) +{ + return TranslatePath(legacyPath, s_videoDbTranslator, VideoDbTranslatorSize); +} + +std::string CLegacyPathTranslation::TranslateMusicDbPath(const std::string &legacyPath) +{ + return TranslatePath(legacyPath, s_musicDbTranslator, MusicDbTranslatorSize); +} + +std::string CLegacyPathTranslation::TranslatePath(const std::string &legacyPath, Translator *translationMap, size_t translationMapSize) +{ + std::string newPath = legacyPath; + for (size_t index = 0; index < translationMapSize; index++) + { + if (StringUtils::StartsWithNoCase(newPath, translationMap[index].legacyPath)) + { + StringUtils::Replace(newPath, translationMap[index].legacyPath, translationMap[index].newPath); + break; + } + } + + return newPath; +} diff --git a/xbmc/utils/LegacyPathTranslation.h b/xbmc/utils/LegacyPathTranslation.h new file mode 100644 index 0000000..ba6450b --- /dev/null +++ b/xbmc/utils/LegacyPathTranslation.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2013-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +typedef struct Translator Translator; + +class CURL; + +/*! + \brief Translates old internal paths into new ones + + Translates old videodb:// and musicdb:// paths which used numbers + to indicate a specific category to new paths using more descriptive + strings to indicate categories. + */ +class CLegacyPathTranslation +{ +public: + /*! + \brief Translates old videodb:// paths to new ones + + \param legacyPath Path in the old videodb:// format using numbers + \return Path in the new videodb:// format using descriptive strings + */ + static std::string TranslateVideoDbPath(const CURL &legacyPath); + static std::string TranslateVideoDbPath(const std::string &legacyPath); + + /*! + \brief Translates old musicdb:// paths to new ones + + \param legacyPath Path in the old musicdb:// format using numbers + \return Path in the new musicdb:// format using descriptive strings + */ + static std::string TranslateMusicDbPath(const CURL &legacyPath); + static std::string TranslateMusicDbPath(const std::string &legacyPath); + +private: + static std::string TranslatePath(const std::string &legacyPath, Translator *translationMap, size_t translationMapSize); +}; diff --git a/xbmc/utils/Literals.h b/xbmc/utils/Literals.h new file mode 100644 index 0000000..ce567d5 --- /dev/null +++ b/xbmc/utils/Literals.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +constexpr unsigned long long int operator"" _kib (unsigned long long int val) +{ + return val * 1024ull; +} + +constexpr unsigned long long int operator"" _kb (unsigned long long int val) +{ + return val * 1000ull; +} + +constexpr unsigned long long int operator"" _mib (unsigned long long int val) +{ + return val * 1024ull * 1024ull; +} + +constexpr unsigned long long int operator"" _mb (unsigned long long int val) +{ + return val * 1000ull * 1000ull; +} diff --git a/xbmc/utils/Locale.cpp b/xbmc/utils/Locale.cpp new file mode 100644 index 0000000..0a2d692 --- /dev/null +++ b/xbmc/utils/Locale.cpp @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Locale.h" + +#include "utils/StringUtils.h" + +const CLocale CLocale::Empty; + +CLocale::CLocale() + : m_language(), + m_territory(), + m_codeset(), + m_modifier() +{ } + +CLocale::CLocale(const std::string& language) + : m_language(), + m_territory(), + m_codeset(), + m_modifier() +{ + m_valid = ParseLocale(language, m_language, m_territory, m_codeset, m_modifier); +} + +CLocale::CLocale(const std::string& language, const std::string& territory) + : m_language(language), + m_territory(territory), + m_codeset(), + m_modifier() +{ + Initialize(); +} + +CLocale::CLocale(const std::string& language, const std::string& territory, const std::string& codeset) + : m_language(language), + m_territory(territory), + m_codeset(codeset), + m_modifier() +{ + Initialize(); +} + +CLocale::CLocale(const std::string& language, const std::string& territory, const std::string& codeset, const std::string& modifier) + : m_language(language), + m_territory(territory), + m_codeset(codeset), + m_modifier(modifier) +{ + Initialize(); +} + +CLocale::~CLocale() = default; + +CLocale CLocale::FromString(const std::string& locale) +{ + return CLocale(locale); +} + +bool CLocale::operator==(const CLocale& other) const +{ + if (!m_valid && !other.m_valid) + return true; + + return m_valid == other.m_valid && + StringUtils::EqualsNoCase(m_language, other.m_language) && + StringUtils::EqualsNoCase(m_territory, other.m_territory) && + StringUtils::EqualsNoCase(m_codeset, other.m_codeset) && + StringUtils::EqualsNoCase(m_modifier, other.m_modifier); +} + +std::string CLocale::ToString() const +{ + if (!m_valid) + return ""; + + std::string locale = ToShortString(); + + if (!m_codeset.empty()) + locale += "." + m_codeset; + + if (!m_modifier.empty()) + locale += "@" + m_modifier; + + return locale; +} + +std::string CLocale::ToStringLC() const +{ + if (!m_valid) + return ""; + + std::string locale = ToString(); + StringUtils::ToLower(locale); + + return locale; +} + +std::string CLocale::ToShortString() const +{ + if (!m_valid) + return ""; + + std::string locale = m_language; + + if (!m_territory.empty()) + locale += "_" + m_territory; + + return locale; +} + +std::string CLocale::ToShortStringLC() const +{ + if (!m_valid) + return ""; + + std::string locale = ToShortString(); + StringUtils::ToLower(locale); + + return locale; +} + +bool CLocale::Equals(const std::string& locale) const +{ + CLocale other = FromString(locale); + + return *this == other; +} + +bool CLocale::Matches(const std::string& locale) const +{ + CLocale other = FromString(locale); + + if (!m_valid && !other.m_valid) + return true; + if (!m_valid || !other.m_valid) + return false; + + if (!StringUtils::EqualsNoCase(m_language, other.m_language)) + return false; + if (!m_territory.empty() && !other.m_territory.empty() && !StringUtils::EqualsNoCase(m_territory, other.m_territory)) + return false; + if (!m_codeset.empty() && !other.m_codeset.empty() && !StringUtils::EqualsNoCase(m_codeset, other.m_codeset)) + return false; + if (!m_modifier.empty() && !other.m_modifier.empty() && !StringUtils::EqualsNoCase(m_modifier, other.m_modifier)) + return false; + + return true; +} + +std::string CLocale::FindBestMatch(const std::set& locales) const +{ + std::string bestMatch = ""; + int bestMatchRank = -1; + + for (auto const& locale : locales) + { + // check if there is an exact match + if (Equals(locale)) + return locale; + + int matchRank = GetMatchRank(locale); + if (matchRank > bestMatchRank) + { + bestMatchRank = matchRank; + bestMatch = locale; + } + } + + return bestMatch; +} + +std::string CLocale::FindBestMatch(const std::unordered_map& locales) const +{ + std::string bestMatch = ""; + int bestMatchRank = -1; + + for (auto const& locale : locales) + { + // check if there is an exact match + if (Equals(locale.first)) + return locale.first; + + int matchRank = GetMatchRank(locale.first); + if (matchRank > bestMatchRank) + { + bestMatchRank = matchRank; + bestMatch = locale.first; + } + } + + return bestMatch; +} + +bool CLocale::CheckValidity(const std::string& language, const std::string& territory, const std::string& codeset, const std::string& modifier) +{ + static_cast(territory); + static_cast(codeset); + static_cast(modifier); + + return !language.empty(); +} + +bool CLocale::ParseLocale(const std::string &locale, std::string &language, std::string &territory, std::string &codeset, std::string &modifier) +{ + if (locale.empty()) + return false; + + language.clear(); + territory.clear(); + codeset.clear(); + modifier.clear(); + + // the format for a locale is [language[_territory][.codeset][@modifier]] + std::string tmp = locale; + + // look for the modifier after @ + size_t pos = tmp.find("@"); + if (pos != std::string::npos) + { + modifier = tmp.substr(pos + 1); + tmp = tmp.substr(0, pos); + } + + // look for the codeset after . + pos = tmp.find("."); + if (pos != std::string::npos) + { + codeset = tmp.substr(pos + 1); + tmp = tmp.substr(0, pos); + } + + // look for the codeset after _ + pos = tmp.find("_"); + if (pos != std::string::npos) + { + territory = tmp.substr(pos + 1); + StringUtils::ToUpper(territory); + tmp = tmp.substr(0, pos); + } + + // what remains is the language + language = tmp; + StringUtils::ToLower(language); + + return CheckValidity(language, territory, codeset, modifier); +} + +void CLocale::Initialize() +{ + m_valid = CheckValidity(m_language, m_territory, m_codeset, m_modifier); + if (m_valid) + { + StringUtils::ToLower(m_language); + StringUtils::ToUpper(m_territory); + } +} + +int CLocale::GetMatchRank(const std::string& locale) const +{ + CLocale other = FromString(locale); + + // both locales must be valid and match in language + if (!m_valid || !other.m_valid || + !StringUtils::EqualsNoCase(m_language, other.m_language)) + return -1; + + int rank = 0; + // matching in territory is considered more important than matching in + // codeset and/or modifier + if (!m_territory.empty() && !other.m_territory.empty() && StringUtils::EqualsNoCase(m_territory, other.m_territory)) + rank += 3; + if (!m_codeset.empty() && !other.m_codeset.empty() && StringUtils::EqualsNoCase(m_codeset, other.m_codeset)) + rank += 1; + if (!m_modifier.empty() && !other.m_modifier.empty() && StringUtils::EqualsNoCase(m_modifier, other.m_modifier)) + rank += 1; + + return rank; +} diff --git a/xbmc/utils/Locale.h b/xbmc/utils/Locale.h new file mode 100644 index 0000000..4f68af8 --- /dev/null +++ b/xbmc/utils/Locale.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include + +/*! + \brief Class representing a full locale of the form `[language[_territory][.codeset][@modifier]]`. + */ +class CLocale +{ +public: + CLocale(); + explicit CLocale(const std::string& language); + CLocale(const std::string& language, const std::string& territory); + CLocale(const std::string& language, const std::string& territory, const std::string& codeset); + CLocale(const std::string& language, const std::string& territory, const std::string& codeset, const std::string& modifier); + ~CLocale(); + + /*! + \brief Empty (and invalid) CLocale instance. + */ + static const CLocale Empty; + + /*! + \brief Parses the given string representation and turns it into a locale. + + \param locale String representation of a locale + */ + static CLocale FromString(const std::string& locale); + + bool operator==(const CLocale& other) const; + inline bool operator!=(const CLocale& other) const { return !(*this == other); } + + /*! + \brief Whether the locale is valid or not. + + \details A locale is considered valid if at least the language code is set. + */ + bool IsValid() const { return m_valid; } + + /*! + \brief Returns the (lower-case) ISO 639-1 language code of the locale. + */ + const std::string& GetLanguageCode() const { return m_language; } + /*! + \brief Returns the (upper-case) ISO 3166-1 Alpha-2 territory code of the locale. + */ + const std::string& GetTerritoryCode() const { return m_territory; } + /*! + \brief Returns the codeset of the locale. + */ + const std::string& GetCodeset() const { return m_codeset; } + /*! + \brief Returns the modifier of the locale. + */ + const std::string& GetModifier() const { return m_modifier; } + + /*! + \brief Returns the full string representation of the locale. + + \details The format of the string representation is + `[language[_territory][.codeset][@modifier]]` where the language is + represented as a (lower-case) two character ISO 639-1 code and the territory + is represented as a (upper-case) two character ISO 3166-1 Alpha-2 code. + */ + std::string ToString() const; + /*! + \brief Returns the full string representation of the locale in lowercase. + + \details The format of the string representation is + `language[_territory][.codeset][@modifier]]` where the language is + represented as a two character ISO 639-1 code and the territory is + represented as a two character ISO 3166-1 Alpha-2 code. + */ + std::string ToStringLC() const; + /*! + \brief Returns the short string representation of the locale. + + \details The format of the short string representation is + `[language[_territory]` where the language is represented as a (lower-case) + two character ISO 639-1 code and the territory is represented as a + (upper-case) two character ISO 3166-1 Alpha-2 code. + */ + std::string ToShortString() const; + /*! + \brief Returns the short string representation of the locale in lowercase. + + \details The format of the short string representation is + `[language[_territory]` where the language is represented as a two character + ISO 639-1 code and the territory is represented as a two character + ISO 3166-1 Alpha-2 code. + */ + std::string ToShortStringLC() const; + + /*! + \brief Checks if the given string representation of a locale exactly matches + the locale. + + \param locale String representation of a locale + \return True if the string representation matches the locale, false otherwise. + */ + bool Equals(const std::string& locale) const; + + /*! + \brief Checks if the given string representation of a locale partly matches + the locale. + + \details Partial matching means that every available locale part needs to + match the same locale part of the other locale if present. + + \param locale String representation of a locale + \return True if the string representation matches the locale, false otherwise. + */ + bool Matches(const std::string& locale) const; + + /*! + \brief Tries to find the locale in the given list that matches this locale + best. + + \param locales List of string representations of locales + \return Best matching locale from the given list or empty string. + */ + std::string FindBestMatch(const std::set& locales) const; + + /*! + \brief Tries to find the locale in the given list that matches this locale + best. + + \param locales Map list of string representations of locales with first as + locale identifier + \return Best matching locale from the given list or empty string. + + \remark Used from \ref CAddonInfo::GetTranslatedText to prevent copy from map + to set. + */ + std::string FindBestMatch(const std::unordered_map& locales) const; + +private: + static bool CheckValidity(const std::string& language, const std::string& territory, const std::string& codeset, const std::string& modifier); + static bool ParseLocale(const std::string &locale, std::string &language, std::string &territory, std::string &codeset, std::string &modifier); + + void Initialize(); + + int GetMatchRank(const std::string& locale) const; + + bool m_valid = false; + std::string m_language; + std::string m_territory; + std::string m_codeset; + std::string m_modifier; +}; + diff --git a/xbmc/utils/MathUtils.h b/xbmc/utils/MathUtils.h new file mode 100644 index 0000000..7a69db7 --- /dev/null +++ b/xbmc/utils/MathUtils.h @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include +#include + +#if defined(HAVE_SSE2) && defined(__SSE2__) +#include +#endif + +// use real compiler defines in here as we want to +// avoid including system.h or other magic includes. +// use 'gcc -dM -E - < /dev/null' or similar to find them. + +#if defined(__ppc__) || \ + defined(__powerpc__) || \ + defined(__mips__) || \ + defined(__arm__) || \ + defined(__aarch64__) || \ + defined(__SH4__) || \ + defined(__sparc__) || \ + defined(__arc__) || \ + defined(_M_ARM) || \ + defined(__or1k__) || \ + defined(__xtensa__) + #define DISABLE_MATHUTILS_ASM_ROUND_INT +#endif + +/*! \brief Math utility class. + Note that the test() routine should return true for all implementations + + See http://ldesoras.free.fr/doc/articles/rounding_en.pdf for an explanation + of the technique used on x86. + */ +namespace MathUtils +{ + // GCC does something stupid with optimization on release builds if we try + // to assert in these functions + + /*! \brief Round to nearest integer. + This routine does fast rounding to the nearest integer. + In the case (k + 0.5 for any integer k) we round up to k+1, and in all other + instances we should return the nearest integer. + Thus, { -1.5, -0.5, 0.5, 1.5 } is rounded to { -1, 0, 1, 2 }. + It preserves the property that round(k) - round(k-1) = 1 for all doubles k. + + Make sure MathUtils::test() returns true for each implementation. + \sa truncate_int, test + */ + inline int round_int(double x) + { + assert(x > static_cast((int) (INT_MIN / 2)) - 1.0); + assert(x < static_cast((int) (INT_MAX / 2)) + 1.0); + +#if defined(DISABLE_MATHUTILS_ASM_ROUND_INT) + /* This implementation warrants some further explanation. + * + * First, a couple of notes on rounding: + * 1) C casts from float/double to integer round towards zero. + * 2) Float/double additions are rounded according to the normal rules, + * in other words: on some architectures, it's fixed at compile-time, + * and on others it can be set using fesetround()). The following + * analysis assumes round-to-nearest with ties rounding to even. This + * is a fairly sensible choice, and is the default with ARM VFP. + * + * What this function wants is round-to-nearest with ties rounding to + * +infinity. This isn't an IEEE rounding mode, even if we could guarantee + * that all architectures supported fesetround(), which they don't. Instead, + * this adds an offset of 2147483648.5 (= 0x80000000.8p0), then casts to + * an unsigned int (crucially, all possible inputs are now in a range where + * round to zero acts the same as round to -infinity) and then subtracts + * 0x80000000 in the integer domain. The 0.5 component of the offset + * converts what is effectively a round down into a round to nearest, with + * ties rounding up, as desired. + * + * There is a catch, that because there is a double rounding, there is a + * small region where the input falls just *below* a tie, where the addition + * of the offset causes a round *up* to an exact integer, due to the finite + * level of precision available in floating point. You need to be aware of + * this when calling this function, although at present it is not believed + * that XBMC ever attempts to round numbers in this window. + * + * It is worth proving the size of the affected window. Recall that double + * precision employs a mantissa of 52 bits. + * 1) For all inputs -0.5 <= x <= INT_MAX + * Once the offset is applied, the most significant binary digit in the + * floating-point representation is +2^31. + * At this magnitude, the smallest step representable in double precision + * is 2^31 / 2^52 = 0.000000476837158203125 + * So the size of the range which is rounded up due to the addition is + * half the size of this step, or 0.0000002384185791015625 + * + * 2) For all inputs INT_MIN/2 < x < -0.5 + * Once the offset is applied, the most significant binary digit in the + * floating-point representation is +2^30. + * At this magnitude, the smallest step representable in double precision + * is 2^30 / 2^52 = 0.0000002384185791015625 + * So the size of the range which is rounded up due to the addition is + * half the size of this step, or 0.00000011920928955078125 + * + * 3) For all inputs INT_MIN <= x <= INT_MIN/2 + * The representation once the offset is applied has equal or greater + * precision than the input, so the addition does not cause rounding. + */ + return ((unsigned int) (x + 2147483648.5)) - 0x80000000; + +#else + const float round_to_nearest = 0.5f; + int i; +#if defined(HAVE_SSE2) && defined(__SSE2__) + const float round_dn_to_nearest = 0.4999999f; + i = (x > 0) ? _mm_cvttsd_si32(_mm_set_sd(x + round_to_nearest)) : _mm_cvttsd_si32(_mm_set_sd(x - round_dn_to_nearest)); + +#elif defined(TARGET_WINDOWS) + __asm + { + fld x + fadd st, st (0) + fadd round_to_nearest + fistp i + sar i, 1 + } + +#else + __asm__ __volatile__ ( + "fadd %%st\n\t" + "fadd %%st(1)\n\t" + "fistpl %0\n\t" + "sarl $1, %0\n" + : "=m"(i) : "u"(round_to_nearest), "t"(x) : "st" + ); + +#endif + return i; +#endif + } + + /*! \brief Truncate to nearest integer. + This routine does fast truncation to an integer. + It should simply drop the fractional portion of the floating point number. + + Make sure MathUtils::test() returns true for each implementation. + \sa round_int, test + */ + inline int truncate_int(double x) + { + assert(x > static_cast(INT_MIN / 2) - 1.0); + assert(x < static_cast(INT_MAX / 2) + 1.0); + return static_cast(x); + } + + inline int64_t abs(int64_t a) + { + return (a < 0) ? -a : a; + } + + inline unsigned bitcount(unsigned v) + { + unsigned c = 0; + for (c = 0; v; c++) + v &= v - 1; // clear the least significant bit set + return c; + } + + inline void hack() + { + // stupid hack to keep compiler from dropping these + // functions as unused + MathUtils::round_int(0.0); + MathUtils::truncate_int(0.0); + MathUtils::abs(0); + } + + /** + * Compare two floating-point numbers for equality and regard them + * as equal if their difference is below a given threshold. + * + * It is usually not useful to compare float numbers for equality with + * the standard operator== since very close numbers might have different + * representations. + */ + template + inline bool FloatEquals(FloatT f1, FloatT f2, FloatT maxDelta) + { + return (std::abs(f2 - f1) < maxDelta); + } + +#if 0 + /*! \brief test routine for round_int and truncate_int + Must return true on all platforms. + */ + inline bool test() + { + for (int i = -8; i < 8; ++i) + { + double d = 0.25*i; + int r = (i < 0) ? (i - 1) / 4 : (i + 2) / 4; + int t = i / 4; + if (round_int(d) != r || truncate_int(d) != t) + return false; + } + return true; + } +#endif +} // namespace MathUtils + diff --git a/xbmc/utils/MemUtils.h b/xbmc/utils/MemUtils.h new file mode 100644 index 0000000..0266908 --- /dev/null +++ b/xbmc/utils/MemUtils.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include + +namespace KODI +{ +namespace MEMORY +{ +struct MemoryStatus +{ + unsigned int memoryLoad; + + uint64_t totalPhys; + uint64_t availPhys; +}; + +void* AlignedMalloc(size_t s, size_t alignTo); +void AlignedFree(void* p); +void GetMemoryStatus(MemoryStatus* buffer); +} +} diff --git a/xbmc/utils/Mime.cpp b/xbmc/utils/Mime.cpp new file mode 100644 index 0000000..5aa4c3c --- /dev/null +++ b/xbmc/utils/Mime.cpp @@ -0,0 +1,699 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Mime.h" + +#include "FileItem.h" +#include "URIUtils.h" +#include "URL.h" +#include "filesystem/CurlFile.h" +#include "music/tags/MusicInfoTag.h" +#include "utils/StringUtils.h" +#include "video/VideoInfoTag.h" + +#include + +const std::map CMime::m_mimetypes = + {{{"3dm", "x-world/x-3dmf"}, + {"3dmf", "x-world/x-3dmf"}, + {"3fr", "image/3fr"}, + {"a", "application/octet-stream"}, + {"aab", "application/x-authorware-bin"}, + {"aam", "application/x-authorware-map"}, + {"aas", "application/x-authorware-seg"}, + {"abc", "text/vnd.abc"}, + {"acgi", "text/html"}, + {"afl", "video/animaflex"}, + {"ai", "application/postscript"}, + {"aif", "audio/aiff"}, + {"aifc", "audio/x-aiff"}, + {"aiff", "audio/aiff"}, + {"aim", "application/x-aim"}, + {"aip", "text/x-audiosoft-intra"}, + {"ani", "application/x-navi-animation"}, + {"aos", "application/x-nokia-9000-communicator-add-on-software"}, + {"apng", "image/apng"}, + {"aps", "application/mime"}, + {"arc", "application/octet-stream"}, + {"arj", "application/arj"}, + {"art", "image/x-jg"}, + {"arw", "image/arw"}, + {"asf", "video/x-ms-asf"}, + {"asm", "text/x-asm"}, + {"asp", "text/asp"}, + {"asx", "video/x-ms-asf"}, + {"au", "audio/basic"}, + {"avi", "video/avi"}, + {"avs", "video/avs-video"}, + {"bcpio", "application/x-bcpio"}, + {"bin", "application/octet-stream"}, + {"bm", "image/bmp"}, + {"bmp", "image/bmp"}, + {"boo", "application/book"}, + {"book", "application/book"}, + {"boz", "application/x-bzip2"}, + {"bsh", "application/x-bsh"}, + {"bz", "application/x-bzip"}, + {"bz2", "application/x-bzip2"}, + {"c", "text/plain"}, + {"c++", "text/plain"}, + {"cat", "application/vnd.ms-pki.seccat"}, + {"cc", "text/plain"}, + {"ccad", "application/clariscad"}, + {"cco", "application/x-cocoa"}, + {"cdf", "application/cdf"}, + {"cer", "application/pkix-cert"}, + {"cer", "application/x-x509-ca-cert"}, + {"cha", "application/x-chat"}, + {"chat", "application/x-chat"}, + {"class", "application/java"}, + {"com", "application/octet-stream"}, + {"conf", "text/plain"}, + {"cpio", "application/x-cpio"}, + {"cpp", "text/x-c"}, + {"cpt", "application/x-cpt"}, + {"crl", "application/pkcs-crl"}, + {"crt", "application/pkix-cert"}, + {"cr2", "image/cr2"}, + {"crw", "image/crw"}, + {"csh", "application/x-csh"}, + {"css", "text/css"}, + {"cxx", "text/plain"}, + {"dcr", "application/x-director"}, + {"deepv", "application/x-deepv"}, + {"def", "text/plain"}, + {"der", "application/x-x509-ca-cert"}, + {"dif", "video/x-dv"}, + {"dir", "application/x-director"}, + {"dl", "video/dl"}, + {"divx", "video/x-msvideo"}, + {"dng", "image/dng"}, + {"doc", "application/msword"}, + {"docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, + {"dot", "application/msword"}, + {"dp", "application/commonground"}, + {"drw", "application/drafting"}, + {"dump", "application/octet-stream"}, + {"dv", "video/x-dv"}, + {"dvi", "application/x-dvi"}, + {"dwf", "model/vnd.dwf"}, + {"dwg", "image/vnd.dwg"}, + {"dxf", "image/vnd.dwg"}, + {"dxr", "application/x-director"}, + {"el", "text/x-script.elisp"}, + {"elc", "application/x-elc"}, + {"env", "application/x-envoy"}, + {"eps", "application/postscript"}, + {"erf", "image/erf"}, + {"es", "application/x-esrehber"}, + {"etx", "text/x-setext"}, + {"evy", "application/envoy"}, + {"exe", "application/octet-stream"}, + {"f", "text/x-fortran"}, + {"f77", "text/x-fortran"}, + {"f90", "text/x-fortran"}, + {"fdf", "application/vnd.fdf"}, + {"fif", "image/fif"}, + {"flac", "audio/flac"}, + {"fli", "video/fli"}, + {"flo", "image/florian"}, + {"flv", "video/x-flv"}, + {"flx", "text/vnd.fmi.flexstor"}, + {"fmf", "video/x-atomic3d-feature"}, + {"for", "text/plain"}, + {"for", "text/x-fortran"}, + {"fpx", "image/vnd.fpx"}, + {"frl", "application/freeloader"}, + {"funk", "audio/make"}, + {"g", "text/plain"}, + {"g3", "image/g3fax"}, + {"gif", "image/gif"}, + {"gl", "video/x-gl"}, + {"gsd", "audio/x-gsm"}, + {"gsm", "audio/x-gsm"}, + {"gsp", "application/x-gsp"}, + {"gss", "application/x-gss"}, + {"gtar", "application/x-gtar"}, + {"gz", "application/x-compressed"}, + {"gzip", "application/x-gzip"}, + {"h", "text/plain"}, + {"hdf", "application/x-hdf"}, + {"heic", "image/heic"}, + {"heif", "image/heif"}, + {"help", "application/x-helpfile"}, + {"hgl", "application/vnd.hp-hpgl"}, + {"hh", "text/plain"}, + {"hlb", "text/x-script"}, + {"hlp", "application/hlp"}, + {"hpg", "application/vnd.hp-hpgl"}, + {"hpgl", "application/vnd.hp-hpgl"}, + {"hqx", "application/binhex"}, + {"hta", "application/hta"}, + {"htc", "text/x-component"}, + {"htm", "text/html"}, + {"html", "text/html"}, + {"htmls", "text/html"}, + {"htt", "text/webviewhtml"}, + {"htx", "text/html"}, + {"ice", "x-conference/x-cooltalk"}, + {"ico", "image/x-icon"}, + {"idc", "text/plain"}, + {"ief", "image/ief"}, + {"iefs", "image/ief"}, + {"iges", "application/iges"}, + {"igs", "application/iges"}, + {"ima", "application/x-ima"}, + {"imap", "application/x-httpd-imap"}, + {"inf", "application/inf"}, + {"ins", "application/x-internet-signup"}, + {"ip", "application/x-ip2"}, + {"isu", "video/x-isvideo"}, + {"it", "audio/it"}, + {"iv", "application/x-inventor"}, + {"ivr", "i-world/i-vrml"}, + {"ivy", "application/x-livescreen"}, + {"jam", "audio/x-jam"}, + {"jav", "text/x-java-source"}, + {"java", "text/x-java-source"}, + {"jcm", "application/x-java-commerce"}, + {"jfif", "image/jpeg"}, + {"jp2", "image/jp2"}, + {"jfif-tbnl", "image/jpeg"}, + {"jpe", "image/jpeg"}, + {"jpeg", "image/jpeg"}, + {"jpg", "image/jpeg"}, + {"jps", "image/x-jps"}, + {"js", "application/javascript"}, + {"json", "application/json"}, + {"jut", "image/jutvision"}, + {"kar", "music/x-karaoke"}, + {"kdc", "image/kdc"}, + {"ksh", "text/x-script.ksh"}, + {"la", "audio/nspaudio"}, + {"lam", "audio/x-liveaudio"}, + {"latex", "application/x-latex"}, + {"lha", "application/lha"}, + {"lhx", "application/octet-stream"}, + {"list", "text/plain"}, + {"lma", "audio/nspaudio"}, + {"log", "text/plain"}, + {"lsp", "application/x-lisp"}, + {"lst", "text/plain"}, + {"lsx", "text/x-la-asf"}, + {"ltx", "application/x-latex"}, + {"lzh", "application/x-lzh"}, + {"lzx", "application/lzx"}, + {"m", "text/x-m"}, + {"m1v", "video/mpeg"}, + {"m2a", "audio/mpeg"}, + {"m2v", "video/mpeg"}, + {"m3u", "audio/x-mpegurl"}, + {"man", "application/x-troff-man"}, + {"map", "application/x-navimap"}, + {"mar", "text/plain"}, + {"mbd", "application/mbedlet"}, + {"mc$", "application/x-magic-cap-package-1.0"}, + {"mcd", "application/x-mathcad"}, + {"mcf", "text/mcf"}, + {"mcp", "application/netmc"}, + {"mdc", "image/mdc"}, + {"me", "application/x-troff-me"}, + {"mef", "image/mef"}, + {"mht", "message/rfc822"}, + {"mhtml", "message/rfc822"}, + {"mid", "audio/midi"}, + {"midi", "audio/midi"}, + {"mif", "application/x-mif"}, + {"mime", "message/rfc822"}, + {"mjf", "audio/x-vnd.audioexplosion.mjuicemediafile"}, + {"mjpg", "video/x-motion-jpeg"}, + {"mka", "audio/x-matroska"}, + {"mkv", "video/x-matroska"}, + {"mk3d", "video/x-matroska-3d"}, + {"mm", "application/x-meme"}, + {"mme", "application/base64"}, + {"mod", "audio/mod"}, + {"moov", "video/quicktime"}, + {"mov", "video/quicktime"}, + {"movie", "video/x-sgi-movie"}, + {"mos", "image/mos"}, + {"mp2", "audio/mpeg"}, + {"mp3", "audio/mpeg3"}, + {"mp4", "video/mp4"}, + {"mpa", "audio/mpeg"}, + {"mpc", "application/x-project"}, + {"mpe", "video/mpeg"}, + {"mpeg", "video/mpeg"}, + {"mpg", "video/mpeg"}, + {"mpga", "audio/mpeg"}, + {"mpp", "application/vnd.ms-project"}, + {"mpt", "application/x-project"}, + {"mpv", "application/x-project"}, + {"mpx", "application/x-project"}, + {"mrc", "application/marc"}, + {"mrw", "image/mrw"}, + {"ms", "application/x-troff-ms"}, + {"mv", "video/x-sgi-movie"}, + {"my", "audio/make"}, + {"mzz", "application/x-vnd.audioexplosion.mzz"}, + {"nap", "image/naplps"}, + {"naplps", "image/naplps"}, + {"nc", "application/x-netcdf"}, + {"ncm", "application/vnd.nokia.configuration-message"}, + {"nef", "image/nef"}, + {"nfo", "text/xml"}, + {"nif", "image/x-niff"}, + {"niff", "image/x-niff"}, + {"nix", "application/x-mix-transfer"}, + {"nrw", "image/nrw"}, + {"nsc", "application/x-conference"}, + {"nvd", "application/x-navidoc"}, + {"o", "application/octet-stream"}, + {"oda", "application/oda"}, + {"ogg", "audio/ogg"}, + {"omc", "application/x-omc"}, + {"omcd", "application/x-omcdatamaker"}, + {"omcr", "application/x-omcregerator"}, + {"orf", "image/orf"}, + {"p", "text/x-pascal"}, + {"p10", "application/pkcs10"}, + {"p12", "application/pkcs-12"}, + {"p7a", "application/x-pkcs7-signature"}, + {"p7c", "application/pkcs7-mime"}, + {"p7m", "application/pkcs7-mime"}, + {"p7r", "application/x-pkcs7-certreqresp"}, + {"p7s", "application/pkcs7-signature"}, + {"part", "application/pro_eng"}, + {"pas", "text/pascal"}, + {"pbm", "image/x-portable-bitmap"}, + {"pcl", "application/vnd.hp-pcl"}, + {"pct", "image/x-pict"}, + {"pcx", "image/x-pcx"}, + {"pdb", "chemical/x-pdb"}, + {"pdf", "application/pdf"}, + {"pef", "image/pef"}, + {"pfunk", "audio/make.my.funk"}, + {"pgm", "image/x-portable-greymap"}, + {"pic", "image/pict"}, + {"pict", "image/pict"}, + {"pkg", "application/x-newton-compatible-pkg"}, + {"pko", "application/vnd.ms-pki.pko"}, + {"pl", "text/x-script.perl"}, + {"plx", "application/x-pixclscript"}, + {"pm", "text/x-script.perl-module"}, + {"pm4", "application/x-pagemaker"}, + {"pm5", "application/x-pagemaker"}, + {"png", "image/png"}, + {"pnm", "application/x-portable-anymap"}, + {"pot", "application/vnd.ms-powerpoint"}, + {"pov", "model/x-pov"}, + {"ppa", "application/vnd.ms-powerpoint"}, + {"ppm", "image/x-portable-pixmap"}, + {"pps", "application/mspowerpoint"}, + {"ppt", "application/mspowerpoint"}, + {"ppz", "application/mspowerpoint"}, + {"pre", "application/x-freelance"}, + {"prt", "application/pro_eng"}, + {"ps", "application/postscript"}, + {"psd", "application/octet-stream"}, + {"pvu", "paleovu/x-pv"}, + {"pwz", "application/vnd.ms-powerpoint"}, + {"py", "text/x-script.phyton"}, + {"pyc", "application/x-bytecode.python"}, + {"qcp", "audio/vnd.qcelp"}, + {"qd3", "x-world/x-3dmf"}, + {"qd3d", "x-world/x-3dmf"}, + {"qif", "image/x-quicktime"}, + {"qt", "video/quicktime"}, + {"qtc", "video/x-qtc"}, + {"qti", "image/x-quicktime"}, + {"qtif", "image/x-quicktime"}, + {"ra", "audio/x-realaudio"}, + {"raf", "image/raf"}, + {"ram", "audio/x-pn-realaudio"}, + {"ras", "image/cmu-raster"}, + {"rast", "image/cmu-raster"}, + {"raw", "image/raw"}, + {"rexx", "text/x-script.rexx"}, + {"rf", "image/vnd.rn-realflash"}, + {"rgb", "image/x-rgb"}, + {"rm", "audio/x-pn-realaudio"}, + {"rmi", "audio/mid"}, + {"rmm", "audio/x-pn-realaudio"}, + {"rmp", "audio/x-pn-realaudio"}, + {"rng", "application/ringing-tones"}, + {"rnx", "application/vnd.rn-realplayer"}, + {"roff", "application/x-troff"}, + {"rp", "image/vnd.rn-realpix"}, + {"rpm", "audio/x-pn-realaudio-plugin"}, + {"rt", "text/richtext"}, + {"rtf", "text/richtext"}, + {"rtx", "text/richtext"}, + {"rv", "video/vnd.rn-realvideo"}, + {"rw2", "image/rw2"}, + {"s", "text/x-asm"}, + {"s3m", "audio/s3m"}, + {"saveme", "application/octet-stream"}, + {"sbk", "application/x-tbook"}, + {"scm", "video/x-scm"}, + {"sdml", "text/plain"}, + {"sdp", "application/sdp"}, + {"sdr", "application/sounder"}, + {"sea", "application/sea"}, + {"set", "application/set"}, + {"sgm", "text/sgml"}, + {"sgml", "text/sgml"}, + {"sh", "text/x-script.sh"}, + {"shar", "application/x-bsh"}, + {"shtml", "text/x-server-parsed-html"}, + {"sid", "audio/x-psid"}, + {"sit", "application/x-stuffit"}, + {"skd", "application/x-koan"}, + {"skm", "application/x-koan"}, + {"skp", "application/x-koan"}, + {"skt", "application/x-koan"}, + {"sl", "application/x-seelogo"}, + {"smi", "application/smil"}, + {"smil", "application/smil"}, + {"snd", "audio/basic"}, + {"sol", "application/solids"}, + {"spc", "text/x-speech"}, + {"spl", "application/futuresplash"}, + {"spr", "application/x-sprite"}, + {"sprite", "application/x-sprite"}, + {"src", "application/x-wais-source"}, + {"srw", "image/srw"}, + {"ssi", "text/x-server-parsed-html"}, + {"ssm", "application/streamingmedia"}, + {"sst", "application/vnd.ms-pki.certstore"}, + {"step", "application/step"}, + {"stl", "application/sla"}, + {"stp", "application/step"}, + {"sup", "application/x-pgs"}, + {"sv4cpio", "application/x-sv4cpio"}, + {"sv4crc", "application/x-sv4crc"}, + {"svf", "image/vnd.dwg"}, + {"svg", "image/svg+xml"}, + {"svr", "application/x-world"}, + {"swf", "application/x-shockwave-flash"}, + {"t", "application/x-troff"}, + {"talk", "text/x-speech"}, + {"tar", "application/x-tar"}, + {"tbk", "application/toolbook"}, + {"tcl", "text/x-script.tcl"}, + {"tcsh", "text/x-script.tcsh"}, + {"tex", "application/x-tex"}, + {"texi", "application/x-texinfo"}, + {"texinfo", "application/x-texinfo"}, + {"text", "text/plain"}, + {"tgz", "application/x-compressed"}, + {"tif", "image/tiff"}, + {"tiff", "image/tiff"}, + {"tr", "application/x-troff"}, + {"ts", "video/mp2t"}, + {"tsi", "audio/tsp-audio"}, + {"tsp", "audio/tsplayer"}, + {"tsv", "text/tab-separated-values"}, + {"turbot", "image/florian"}, + {"txt", "text/plain"}, + {"uil", "text/x-uil"}, + {"uni", "text/uri-list"}, + {"unis", "text/uri-list"}, + {"unv", "application/i-deas"}, + {"uri", "text/uri-list"}, + {"uris", "text/uri-list"}, + {"ustar", "application/x-ustar"}, + {"uu", "text/x-uuencode"}, + {"uue", "text/x-uuencode"}, + {"vcd", "application/x-cdlink"}, + {"vcs", "text/x-vcalendar"}, + {"vda", "application/vda"}, + {"vdo", "video/vdo"}, + {"vew", "application/groupwise"}, + {"viv", "video/vivo"}, + {"vivo", "video/vivo"}, + {"vmd", "application/vocaltec-media-desc"}, + {"vmf", "application/vocaltec-media-file"}, + {"voc", "audio/voc"}, + {"vos", "video/vosaic"}, + {"vox", "audio/voxware"}, + {"vqe", "audio/x-twinvq-plugin"}, + {"vqf", "audio/x-twinvq"}, + {"vql", "audio/x-twinvq-plugin"}, + {"vrml", "application/x-vrml"}, + {"vrt", "x-world/x-vrt"}, + {"vsd", "application/x-visio"}, + {"vst", "application/x-visio"}, + {"vsw", "application/x-visio"}, + {"w60", "application/wordperfect6.0"}, + {"w61", "application/wordperfect6.1"}, + {"w6w", "application/msword"}, + {"wav", "audio/wav"}, + {"wb1", "application/x-qpro"}, + {"wbmp", "image/vnd.wap.wbmp"}, + {"web", "application/vnd.xara"}, + {"webp", "image/webp"}, + {"wiz", "application/msword"}, + {"wk1", "application/x-123"}, + {"wma", "audio/x-ms-wma"}, + {"wmf", "windows/metafile"}, + {"wml", "text/vnd.wap.wml"}, + {"wmlc", "application/vnd.wap.wmlc"}, + {"wmls", "text/vnd.wap.wmlscript"}, + {"wmlsc", "application/vnd.wap.wmlscriptc"}, + {"wmv", "video/x-ms-wmv"}, + {"word", "application/msword"}, + {"wp", "application/wordperfect"}, + {"wp5", "application/wordperfect"}, + {"wp6", "application/wordperfect"}, + {"wpd", "application/wordperfect"}, + {"wq1", "application/x-lotus"}, + {"wri", "application/mswrite"}, + {"wrl", "model/vrml"}, + {"wrz", "model/vrml"}, + {"wsc", "text/scriplet"}, + {"wsrc", "application/x-wais-source"}, + {"wtk", "application/x-wintalk"}, + {"x3f", "image/x3f"}, + {"xbm", "image/xbm"}, + {"xdr", "video/x-amt-demorun"}, + {"xgz", "xgl/drawing"}, + {"xif", "image/vnd.xiff"}, + {"xl", "application/excel"}, + {"xla", "application/excel"}, + {"xlb", "application/excel"}, + {"xlc", "application/excel"}, + {"xld", "application/excel"}, + {"xlk", "application/excel"}, + {"xll", "application/excel"}, + {"xlm", "application/excel"}, + {"xls", "application/excel"}, + {"xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, + {"xlt", "application/excel"}, + {"xlv", "application/excel"}, + {"xlw", "application/excel"}, + {"xm", "audio/xm"}, + {"xml", "text/xml"}, + {"xmz", "xgl/movie"}, + {"xpix", "application/x-vnd.ls-xpix"}, + {"xpm", "image/xpm"}, + {"x-png", "image/png"}, + {"xspf", "application/xspf+xml"}, + {"xsr", "video/x-amt-showrun"}, + {"xvid", "video/x-msvideo"}, + {"xwd", "image/x-xwd"}, + {"xyz", "chemical/x-pdb"}, + {"z", "application/x-compressed"}, + {"zip", "application/zip"}, + {"zoo", "application/octet-stream"}, + {"zsh", "text/x-script.zsh"}}}; + +std::string CMime::GetMimeType(const std::string &extension) +{ + if (extension.empty()) + return ""; + + std::string ext = extension; + size_t posNotPoint = ext.find_first_not_of('.'); + if (posNotPoint != std::string::npos && posNotPoint > 0) + ext = extension.substr(posNotPoint); + transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + + std::map::const_iterator it = m_mimetypes.find(ext); + if (it != m_mimetypes.end()) + return it->second; + + return ""; +} + +std::string CMime::GetMimeType(const CFileItem &item) +{ + std::string path = item.GetDynPath(); + if (item.HasVideoInfoTag() && !item.GetVideoInfoTag()->GetPath().empty()) + path = item.GetVideoInfoTag()->GetPath(); + else if (item.HasMusicInfoTag() && !item.GetMusicInfoTag()->GetURL().empty()) + path = item.GetMusicInfoTag()->GetURL(); + + return GetMimeType(URIUtils::GetExtension(path)); +} + +std::string CMime::GetMimeType(const CURL &url, bool lookup) +{ + + std::string strMimeType; + + if( url.IsProtocol("shout") || url.IsProtocol("http") || url.IsProtocol("https")) + { + // If lookup is false, bail out early to leave mime type empty + if (!lookup) + return strMimeType; + + std::string strmime; + XFILE::CCurlFile::GetMimeType(url, strmime); + + // try to get mime-type again but with an NSPlayer User-Agent + // in order for server to provide correct mime-type. Allows us + // to properly detect an MMS stream + if (StringUtils::StartsWithNoCase(strmime, "video/x-ms-")) + XFILE::CCurlFile::GetMimeType(url, strmime, "NSPlayer/11.00.6001.7000"); + + // make sure there are no options set in mime-type + // mime-type can look like "video/x-ms-asf ; charset=utf8" + size_t i = strmime.find(';'); + if(i != std::string::npos) + strmime.erase(i, strmime.length() - i); + StringUtils::Trim(strmime); + strMimeType = strmime; + } + else + strMimeType = GetMimeType(url.GetFileType()); + + // if it's still empty set to an unknown type + if (strMimeType.empty()) + strMimeType = "application/octet-stream"; + + return strMimeType; +} + +CMime::EFileType CMime::GetFileTypeFromMime(const std::string& mimeType) +{ + // based on http://mimesniff.spec.whatwg.org/ + + std::string type, subtype; + if (!parseMimeType(mimeType, type, subtype)) + return FileTypeUnknown; + + if (type == "application") + { + if (subtype == "zip") + return FileTypeZip; + if (subtype == "x-gzip") + return FileTypeGZip; + if (subtype == "x-rar-compressed") + return FileTypeRar; + + if (subtype == "xml") + return FileTypeXml; + } + else if (type == "text") + { + if (subtype == "xml") + return FileTypeXml; + if (subtype == "html") + return FileTypeHtml; + if (subtype == "plain") + return FileTypePlainText; + } + else if (type == "image") + { + if (subtype == "bmp") + return FileTypeBmp; + if (subtype == "gif") + return FileTypeGif; + if (subtype == "png") + return FileTypePng; + if (subtype == "jpeg" || subtype == "pjpeg") + return FileTypeJpeg; + } + + if (StringUtils::EndsWith(subtype, "+zip")) + return FileTypeZip; + if (StringUtils::EndsWith(subtype, "+xml")) + return FileTypeXml; + + return FileTypeUnknown; +} + +CMime::EFileType CMime::GetFileTypeFromContent(const std::string& fileContent) +{ + // based on http://mimesniff.spec.whatwg.org/#matching-a-mime-type-pattern + + const size_t len = fileContent.length(); + if (len < 2) + return FileTypeUnknown; + + const unsigned char* const b = (const unsigned char*)fileContent.c_str(); + + //! @todo add detection for text types + + // check image types + if (b[0] == 'B' && b[1] == 'M') + return FileTypeBmp; + if (len >= 6 && b[0] == 'G' && b[1] == 'I' && b[2] == 'F' && b[3] == '8' && (b[4] == '7' || b[4] == '9') && b[5] == 'a') + return FileTypeGif; + if (len >= 8 && b[0] == 0x89 && b[1] == 'P' && b[2] == 'N' && b[3] == 'G' && b[4] == 0x0D && b[5] == 0x0A && b[6] == 0x1A && b[7] == 0x0A) + return FileTypePng; + if (len >= 3 && b[0] == 0xFF && b[1] == 0xD8 && b[2] == 0xFF) + return FileTypeJpeg; + + // check archive types + if (len >= 3 && b[0] == 0x1F && b[1] == 0x8B && b[2] == 0x08) + return FileTypeGZip; + if (len >= 4 && b[0] == 'P' && b[1] == 'K' && b[2] == 0x03 && b[3] == 0x04) + return FileTypeZip; + if (len >= 7 && b[0] == 'R' && b[1] == 'a' && b[2] == 'r' && b[3] == ' ' && b[4] == 0x1A && b[5] == 0x07 && b[6] == 0x00) + return FileTypeRar; + + //! @todo add detection for other types if required + + return FileTypeUnknown; +} + +bool CMime::parseMimeType(const std::string& mimeType, std::string& type, std::string& subtype) +{ + static const char* const whitespaceChars = "\x09\x0A\x0C\x0D\x20"; // tab, LF, FF, CR and space + + type.clear(); + subtype.clear(); + + const size_t slashPos = mimeType.find('/'); + if (slashPos == std::string::npos) + return false; + + type.assign(mimeType, 0, slashPos); + subtype.assign(mimeType, slashPos + 1, std::string::npos); + + const size_t semicolonPos = subtype.find(';'); + if (semicolonPos != std::string::npos) + subtype.erase(semicolonPos); + + StringUtils::Trim(type, whitespaceChars); + StringUtils::Trim(subtype, whitespaceChars); + + if (type.empty() || subtype.empty()) + { + type.clear(); + subtype.clear(); + return false; + } + + StringUtils::ToLower(type); + StringUtils::ToLower(subtype); + + return true; +} diff --git a/xbmc/utils/Mime.h b/xbmc/utils/Mime.h new file mode 100644 index 0000000..d3554b9 --- /dev/null +++ b/xbmc/utils/Mime.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include + +class CURL; + +class CFileItem; + +class CMime +{ +public: + static std::string GetMimeType(const std::string &extension); + static std::string GetMimeType(const CFileItem &item); + static std::string GetMimeType(const CURL &url, bool lookup = true); + + enum EFileType + { + FileTypeUnknown = 0, + FileTypeHtml, + FileTypeXml, + FileTypePlainText, + FileTypeZip, + FileTypeGZip, + FileTypeRar, + FileTypeBmp, + FileTypeGif, + FileTypePng, + FileTypeJpeg, + }; + static EFileType GetFileTypeFromMime(const std::string& mimeType); + static EFileType GetFileTypeFromContent(const std::string& fileContent); + +private: + static bool parseMimeType(const std::string& mimeType, std::string& type, std::string& subtype); + + static const std::map m_mimetypes; +}; diff --git a/xbmc/utils/Observer.cpp b/xbmc/utils/Observer.cpp new file mode 100644 index 0000000..729f61d --- /dev/null +++ b/xbmc/utils/Observer.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + + +#include "Observer.h" + +#include "threads/SingleLock.h" + +#include + +Observable &Observable::operator=(const Observable &observable) +{ + CSingleLock lock(m_obsCritSection); + + m_bObservableChanged = static_cast(observable.m_bObservableChanged); + m_observers = observable.m_observers; + + return *this; +} + +bool Observable::IsObserving(const Observer &obs) const +{ + CSingleLock lock(m_obsCritSection); + return std::find(m_observers.begin(), m_observers.end(), &obs) != m_observers.end(); +} + +void Observable::RegisterObserver(Observer *obs) +{ + CSingleLock lock(m_obsCritSection); + if (!IsObserving(*obs)) + { + m_observers.push_back(obs); + } +} + +void Observable::UnregisterObserver(Observer *obs) +{ + CSingleLock lock(m_obsCritSection); + auto iter = std::remove(m_observers.begin(), m_observers.end(), obs); + if (iter != m_observers.end()) + m_observers.erase(iter); +} + +void Observable::NotifyObservers(const ObservableMessage message /* = ObservableMessageNone */) +{ + // Make sure the set/compare is atomic + // so we don't clobber the variable in a race condition + auto bNotify = m_bObservableChanged.exchange(false); + + if (bNotify) + SendMessage(message); +} + +void Observable::SetChanged(bool SetTo) +{ + m_bObservableChanged = SetTo; +} + +void Observable::SendMessage(const ObservableMessage message) +{ + CSingleLock lock(m_obsCritSection); + + for (auto& observer : m_observers) + { + observer->Notify(*this, message); + } +} diff --git a/xbmc/utils/Observer.h b/xbmc/utils/Observer.h new file mode 100644 index 0000000..feb201a --- /dev/null +++ b/xbmc/utils/Observer.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "threads/CriticalSection.h" + +#include +#include + +class Observable; +class ObservableMessageJob; + +typedef enum +{ + ObservableMessageNone, + ObservableMessagePeripheralsChanged, + ObservableMessageSettingsChanged, + ObservableMessageButtonMapsChanged, +} ObservableMessage; + +class Observer +{ +public: + Observer() = default; + virtual ~Observer() = default; + /*! + * @brief Process a message from an observable. + * @param obs The observable that sends the message. + * @param msg The message. + */ + virtual void Notify(const Observable &obs, const ObservableMessage msg) = 0; +}; + +class Observable +{ + friend class ObservableMessageJob; + +public: + Observable() = default; + virtual ~Observable() = default; + virtual Observable &operator=(const Observable &observable); + + /*! + * @brief Register an observer. + * @param obs The observer to register. + */ + virtual void RegisterObserver(Observer *obs); + + /*! + * @brief Unregister an observer. + * @param obs The observer to unregister. + */ + virtual void UnregisterObserver(Observer *obs); + + /*! + * @brief Send a message to all observers when m_bObservableChanged is true. + * @param message The message to send. + */ + virtual void NotifyObservers(const ObservableMessage message = ObservableMessageNone); + + /*! + * @brief Mark an observable changed. + * @param bSetTo True to mark the observable changed, false to mark it as unchanged. + */ + virtual void SetChanged(bool bSetTo = true); + + /*! + * @brief Check whether this observable is being observed by an observer. + * @param obs The observer to check. + * @return True if this observable is being observed by the given observer, false otherwise. + */ + virtual bool IsObserving(const Observer &obs) const; + +protected: + /*! + * @brief Send a message to all observer when m_bObservableChanged is true. + * @param obs The observer that sends the message. + * @param message The message to send. + */ + void SendMessage(const ObservableMessage message); + + std::atomic m_bObservableChanged{false}; /*!< true when the observable is marked as changed, false otherwise */ + std::vector m_observers; /*!< all observers */ + mutable CCriticalSection m_obsCritSection; /*!< mutex */ +}; diff --git a/xbmc/utils/POUtils.cpp b/xbmc/utils/POUtils.cpp new file mode 100644 index 0000000..7d8afd3 --- /dev/null +++ b/xbmc/utils/POUtils.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/POUtils.h" + +#include "URL.h" +#include "filesystem/File.h" +#include "utils/log.h" + +#include + +CPODocument::CPODocument() +{ + m_CursorPos = 0; + m_nextEntryPos = 0; + m_POfilelength = 0; + m_Entry.msgStrPlural.clear(); + m_Entry.msgStrPlural.resize(1); +} + +CPODocument::~CPODocument() = default; + +bool CPODocument::LoadFile(const std::string &pofilename) +{ + CURL poFileUrl(pofilename); + if (!XFILE::CFile::Exists(poFileUrl)) + return false; + + XFILE::CFile file; + XFILE::auto_buffer buf; + if (file.LoadFile(poFileUrl, buf) < 18) // at least a size of a minimalistic header + { + CLog::Log(LOGERROR, "%s: can't load file \"%s\" or file is too small", __FUNCTION__, pofilename.c_str()); + return false; + } + + m_strBuffer = '\n'; + m_strBuffer.append(buf.get(), buf.size()); + buf.clear(); + + ConvertLineEnds(pofilename); + + // we make sure, to have an LF at the end of buffer + if (*m_strBuffer.rbegin() != '\n') + { + m_strBuffer += "\n"; + } + + m_POfilelength = m_strBuffer.size(); + + if (GetNextEntry() && m_Entry.Type == MSGID_FOUND) + return true; + + CLog::Log(LOGERROR, "POParser: unable to read PO file header from file: %s", pofilename.c_str()); + return false; +} + +bool CPODocument::GetNextEntry() +{ + do + { + // if we don't find LFLF, we reached the end of the buffer and the last entry to check + // we indicate this with setting m_nextEntryPos to the end of the buffer + if ((m_nextEntryPos = m_strBuffer.find("\n\n", m_CursorPos)) == std::string::npos) + m_nextEntryPos = m_POfilelength-1; + + // now we read the actual entry into a temp string for further processing + m_Entry.Content.assign(m_strBuffer, m_CursorPos, m_nextEntryPos - m_CursorPos +1); + m_CursorPos = m_nextEntryPos+1; // jump cursor to the second LF character + + if (FindLineStart ("\nmsgid ", m_Entry.msgID.Pos)) + { + if (FindLineStart ("\nmsgctxt \"#", m_Entry.xIDPos) && ParseNumID()) + { + m_Entry.Type = ID_FOUND; // we found an entry with a valid numeric id + return true; + } + + size_t plurPos; + if (FindLineStart ("\nmsgid_plural ", plurPos)) + { + m_Entry.Type = MSGID_PLURAL_FOUND; // we found a pluralized entry + return true; + } + + m_Entry.Type = MSGID_FOUND; // we found a normal entry, with no numeric id + return true; + } + } + while (m_nextEntryPos != m_POfilelength-1); + // we reached the end of buffer AND we have not found a valid entry + + return false; +} + +void CPODocument::ParseEntry(bool bisSourceLang) +{ + if (bisSourceLang) + { + if (m_Entry.Type == ID_FOUND) + GetString(m_Entry.msgID); + else + m_Entry.msgID.Str.clear(); + return; + } + + if (m_Entry.Type != ID_FOUND) + { + GetString(m_Entry.msgID); + if (FindLineStart ("\nmsgctxt ", m_Entry.msgCtxt.Pos)) + GetString(m_Entry.msgCtxt); + else + m_Entry.msgCtxt.Str.clear(); + } + + if (m_Entry.Type != MSGID_PLURAL_FOUND) + { + if (FindLineStart ("\nmsgstr ", m_Entry.msgStr.Pos)) + { + GetString(m_Entry.msgStr); + GetString(m_Entry.msgID); + } + else + { + CLog::Log(LOGERROR, "POParser: missing msgstr line in entry. Failed entry: %s", + m_Entry.Content.c_str()); + m_Entry.msgStr.Str.clear(); + } + return; + } + + // We found a plural form entry. We read it into a vector of CStrEntry types + m_Entry.msgStrPlural.clear(); + std::string strPattern = "\nmsgstr[0] "; + CStrEntry strEntry; + + for (int n=0; n<7 ; n++) + { + strPattern[8] = static_cast(n+'0'); + if (FindLineStart (strPattern, strEntry.Pos)) + { + GetString(strEntry); + if (strEntry.Str.empty()) + break; + m_Entry.msgStrPlural.push_back(strEntry); + } + else + break; + } + + if (m_Entry.msgStrPlural.empty()) + { + CLog::Log(LOGERROR, "POParser: msgstr[] plural lines have zero valid strings. " + "Failed entry: %s", m_Entry.Content.c_str()); + m_Entry.msgStrPlural.resize(1); // Put 1 element with an empty string into the vector + } +} + +const std::string& CPODocument::GetPlurMsgstr(size_t plural) const +{ + if (m_Entry.msgStrPlural.size() < plural+1) + { + CLog::Log(LOGERROR, "POParser: msgstr[%i] plural field requested, but not found in PO file. " + "Failed entry: %s", static_cast(plural), m_Entry.Content.c_str()); + plural = m_Entry.msgStrPlural.size()-1; + } + return m_Entry.msgStrPlural[plural].Str; +} + +std::string CPODocument::UnescapeString(const std::string &strInput) +{ + std::string strOutput; + if (strInput.empty()) + return strOutput; + + char oescchar; + strOutput.reserve(strInput.size()); + std::string::const_iterator it = strInput.begin(); + while (it < strInput.end()) + { + oescchar = *it++; + if (oescchar == '\\') + { + if (it == strInput.end()) + { + CLog::Log(LOGERROR, + "POParser: warning, unhandled escape character " + "at line-end. Problematic entry: %s", + m_Entry.Content.c_str()); + break; + } + switch (*it++) + { + case 'a': oescchar = '\a'; break; + case 'b': oescchar = '\b'; break; + case 'v': oescchar = '\v'; break; + case 'n': oescchar = '\n'; break; + case 't': oescchar = '\t'; break; + case 'r': oescchar = '\r'; break; + case '"': oescchar = '"' ; break; + case '0': oescchar = '\0'; break; + case 'f': oescchar = '\f'; break; + case '?': oescchar = '\?'; break; + case '\'': oescchar = '\''; break; + case '\\': oescchar = '\\'; break; + + default: + { + CLog::Log(LOGERROR, + "POParser: warning, unhandled escape character. Problematic entry: %s", + m_Entry.Content.c_str()); + continue; + } + } + } + strOutput.push_back(oescchar); + } + return strOutput; +} + +bool CPODocument::FindLineStart(const std::string &strToFind, size_t &FoundPos) +{ + + FoundPos = m_Entry.Content.find(strToFind); + + if (FoundPos == std::string::npos || FoundPos + strToFind.size() + 2 > m_Entry.Content.size()) + return false; // if we don't find the string or if we don't have at least one char after it + + FoundPos += strToFind.size(); // to set the pos marker to the exact start of the real data + return true; +} + +bool CPODocument::ParseNumID() +{ + if (isdigit(m_Entry.Content.at(m_Entry.xIDPos))) // verify if the first char is digit + { + // we check for the numeric id for the fist 10 chars (uint32) + m_Entry.xID = strtol(&m_Entry.Content[m_Entry.xIDPos], NULL, 10); + return true; + } + + CLog::Log(LOGERROR, "POParser: found numeric id descriptor, but no valid id can be read, " + "entry was handled as normal msgid entry"); + CLog::Log(LOGERROR, "POParser: The problematic entry: %s", + m_Entry.Content.c_str()); + return false; +} + +void CPODocument::GetString(CStrEntry &strEntry) +{ + size_t nextLFPos; + size_t startPos = strEntry.Pos; + strEntry.Str.clear(); + + while (startPos < m_Entry.Content.size()) + { + nextLFPos = m_Entry.Content.find("\n", startPos); + if (nextLFPos == std::string::npos) + nextLFPos = m_Entry.Content.size(); + + // check syntax, if it really is a valid quoted string line + if (nextLFPos-startPos < 2 || m_Entry.Content[startPos] != '\"' || + m_Entry.Content[nextLFPos-1] != '\"') + break; + + strEntry.Str.append(m_Entry.Content, startPos+1, nextLFPos-2-startPos); + startPos = nextLFPos+1; + } + + strEntry.Str = UnescapeString(strEntry.Str); +} + +void CPODocument::ConvertLineEnds(const std::string &filename) +{ + size_t foundPos = m_strBuffer.find_first_of("\r"); + if (foundPos == std::string::npos) + return; // We have only Linux style line endings in the file, nothing to do + + if (foundPos+1 >= m_strBuffer.size() || m_strBuffer[foundPos+1] != '\n') + CLog::Log(LOGDEBUG, "POParser: PO file has Mac Style Line Endings. " + "Converted in memory to Linux LF for file: %s", filename.c_str()); + else + CLog::Log(LOGDEBUG, "POParser: PO file has Win Style Line Endings. " + "Converted in memory to Linux LF for file: %s", filename.c_str()); + + std::string strTemp; + strTemp.reserve(m_strBuffer.size()); + for (std::string::const_iterator it = m_strBuffer.begin(); it < m_strBuffer.end(); ++it) + { + if (*it == '\r') + { + if (it+1 == m_strBuffer.end() || *(it+1) != '\n') + strTemp.push_back('\n'); // convert Mac style line ending and continue + continue; // we have Win style line ending so we exclude this CR now + } + strTemp.push_back(*it); + } + m_strBuffer.swap(strTemp); + m_POfilelength = m_strBuffer.size(); +} diff --git a/xbmc/utils/POUtils.h b/xbmc/utils/POUtils.h new file mode 100644 index 0000000..1752b79 --- /dev/null +++ b/xbmc/utils/POUtils.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include + +typedef enum +{ + ID_FOUND = 0, // We have an entry with a numeric (previously XML) identification number. + MSGID_FOUND = 1, // We have a classic gettext entry with textual msgid. No numeric ID. + MSGID_PLURAL_FOUND = 2 // We have a classic gettext entry with textual msgid in plural form. +} POIdType; + +enum +{ + ISSOURCELANG=true +}; + +// Struct to hold current position and text of the string field in the main PO entry. +struct CStrEntry +{ + size_t Pos; + std::string Str; +}; + +// Struct to collect all important data of the current processed entry. +struct CPOEntry +{ + int Type; + uint32_t xID; + size_t xIDPos; + std::string Content; + CStrEntry msgCtxt; + CStrEntry msgID; + CStrEntry msgStr; + std::vector msgStrPlural; +}; + +class CPODocument +{ +public: + CPODocument(); + ~CPODocument(); + + /*! \brief Tries to load a PO file into a temporary memory buffer. + * It also tries to parse the header of the PO file. + \param pofilename filename of the PO file to load. + \return true if the load was successful, unless return false + */ + bool LoadFile(const std::string &pofilename); + + /*! \brief Fast jumps to the next entry in PO buffer. + * Finds next entry started with "#: id:" or msgctx or msgid. + * to be as fast as possible this does not even get the id number + * just the type of the entry found. GetEntryID() has to be called + * for getting the id. After that ParseEntry() needs a call for + * actually getting the msg strings. The reason for this is to + * have calls and checks as fast as possible generally and specially + * for parsing weather tokens and to parse only the needed strings from + * the fallback language (missing from the gui language translation) + \return true if there was an entry found, false if reached the end of buffer + */ + bool GetNextEntry(); + + /*! \brief Gets the type of entry found with GetNextEntry. + \return the type of entry: ID_FOUND || MSGID_FOUND || MSGID_PLURAL_FOUND + */ + int GetEntryType() const {return m_Entry.Type;} + + /*! \brief Parses the numeric ID from current entry. + * This function can only be called right after GetNextEntry() + * to make sure that we have a valid entry detected. + \return parsed ID number + */ + uint32_t GetEntryID() const {return m_Entry.xID;} + + /*! \brief Parses current entry. + * Reads msgid, msgstr, msgstr[x], msgctxt strings. + * Note that this function also back-converts the c++ style escape sequences. + * The function only parses the needed strings, considering if it is a source language file. + \param bisSourceLang if we parse a source English file. + */ + void ParseEntry(bool bisSourceLang); + + /*! \brief Gets the msgctxt string previously parsed by ParseEntry(). + \return string* containing the msgctxt string, unescaped and linked together. + */ + const std::string& GetMsgctxt() const {return m_Entry.msgCtxt.Str;} + + /*! \brief Gets the msgid string previously parsed by ParseEntry(). + \return string* containing the msgid string, unescaped and linked together. + */ + const std::string& GetMsgid() const {return m_Entry.msgID.Str;} + + /*! \brief Gets the msgstr string previously parsed by ParseEntry(). + \return string* containing the msgstr string, unescaped and linked together. + */ + const std::string& GetMsgstr() const {return m_Entry.msgStr.Str;} + + /*! \brief Gets the msgstr[x] string previously parsed by ParseEntry(). + \param plural the number of plural-form expected to get (0-6). + \return string* containing the msgstr string, unescaped and linked together. + */ + const std::string& GetPlurMsgstr (size_t plural) const; + +protected: + + /*! \brief Converts c++ style char escape sequences back to char. + * Supports: \a \v \n \t \r \" \0 \f \? \' \\ + \param strInput string contains the string to be unescaped. + \return unescaped string. + */ + std::string UnescapeString(const std::string &strInput); + + /*! \brief Finds the position of line, starting with a given string in current entry. + * This function can only be called after GetNextEntry() + \param strToFind a string what we look for, at beginning of the lines. + \param FoundPos will get the position where we found the line starting with the string. + \return false if no line like that can be found in the entry (m_Entry) + */ + bool FindLineStart(const std::string &strToFind, size_t &FoundPos); + + /*! \brief Reads, and links together the quoted strings found with ParseEntry(). + * This function can only be called after GetNextEntry() called. + \param strEntry.Str a string where we get the appended string lines. + \param strEntry.Pos the position in m_Entry.Content to start reading the string. + */ + void GetString(CStrEntry &strEntry); + + /*! \brief Parses the numeric id and checks if it is valid. + * This function can only be called after GetNextEntry() + * It checks m_Entry.Content at position m_Entry.xIDPos for the numeric id. + * The converted ID number goes into m_Entry.xID for public read out. + \return false, if parse and convert of the id number was unsuccessful. + */ + bool ParseNumID(); + + /*! \brief If we have Windows or Mac line-end chars in PO file, convert them to Unix LFs + */ + void ConvertLineEnds(const std::string &filename); + + // Temporary string buffer to read file in. + std::string m_strBuffer; + // Size of the string buffer. + size_t m_POfilelength; + + // Current cursor position in m_strBuffer. + size_t m_CursorPos; + // The next PO entry position in m_strBuffer. + size_t m_nextEntryPos; + + // Variable to hold all data of currently processed entry. + CPOEntry m_Entry; +}; diff --git a/xbmc/utils/ProgressJob.cpp b/xbmc/utils/ProgressJob.cpp new file mode 100644 index 0000000..6ef1f24 --- /dev/null +++ b/xbmc/utils/ProgressJob.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ProgressJob.h" + +#include "ServiceBroker.h" +#include "dialogs/GUIDialogExtendedProgressBar.h" +#include "dialogs/GUIDialogProgress.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "utils/Variant.h" + +#include + +CProgressJob::CProgressJob() + : m_progress(NULL), + m_progressDialog(NULL) +{ } + +CProgressJob::CProgressJob(CGUIDialogProgressBarHandle* progressBar) + : m_progress(progressBar), + m_progressDialog(NULL) +{ } + +CProgressJob::~CProgressJob() +{ + MarkFinished(); + + m_progress = NULL; + m_progressDialog = NULL; +} + +bool CProgressJob::ShouldCancel(unsigned int progress, unsigned int total) const +{ + if (IsCancelled()) + return true; + + SetProgress(progress, total); + + return CJob::ShouldCancel(progress, total); +} + +bool CProgressJob::DoModal() +{ + m_progress = NULL; + + // get a progress dialog if we don't already have one + if (m_progressDialog == NULL) + { + m_progressDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow(WINDOW_DIALOG_PROGRESS); + + if (m_progressDialog == NULL) + return false; + } + + m_modal = true; + + // do the work + bool result = DoWork(); + + // mark the progress dialog as finished (will close it) + MarkFinished(); + m_modal = false; + + return result; +} + +void CProgressJob::SetProgressIndicators(CGUIDialogProgressBarHandle* progressBar, CGUIDialogProgress* progressDialog, bool updateProgress /* = true */, bool updateInformation /* = true */) +{ + SetProgressBar(progressBar); + SetProgressDialog(progressDialog); + SetUpdateProgress(updateProgress); + SetUpdateInformation(updateInformation); + + // disable auto-closing + SetAutoClose(false); +} + +void CProgressJob::ShowProgressDialog() const +{ + if (!IsModal() || m_progressDialog == NULL || + m_progressDialog->IsDialogRunning()) + return; + + // show the progress dialog as a modal dialog with a progress bar + m_progressDialog->Open(); + m_progressDialog->ShowProgressBar(true); +} + +void CProgressJob::SetTitle(const std::string &title) +{ + if (!m_updateInformation) + return; + + if (m_progress != NULL) + m_progress->SetTitle(title); + else if (m_progressDialog != NULL) + { + m_progressDialog->SetHeading(CVariant{title}); + + ShowProgressDialog(); + } +} + +void CProgressJob::SetText(const std::string &text) +{ + if (!m_updateInformation) + return; + + if (m_progress != NULL) + m_progress->SetText(text); + else if (m_progressDialog != NULL) + { + m_progressDialog->SetText(CVariant{text}); + + ShowProgressDialog(); + } +} + +void CProgressJob::SetProgress(float percentage) const +{ + if (!m_updateProgress) + return; + + if (m_progress != NULL) + m_progress->SetPercentage(percentage); + else if (m_progressDialog != NULL) + { + ShowProgressDialog(); + + int iPercentage = static_cast(ceil(percentage)); + // only change and update the progress bar if its percentage value changed + // (this can have a huge impact on performance if it's called a lot) + if (iPercentage != m_progressDialog->GetPercentage()) + { + m_progressDialog->SetPercentage(iPercentage); + m_progressDialog->Progress(); + } + } +} + +void CProgressJob::SetProgress(int currentStep, int totalSteps) const +{ + if (!m_updateProgress) + return; + + if (m_progress != NULL) + m_progress->SetProgress(currentStep, totalSteps); + else if (m_progressDialog != NULL) + SetProgress((static_cast(currentStep) * 100.0f) / totalSteps); +} + +void CProgressJob::MarkFinished() +{ + if (m_progress != NULL) + { + if (m_updateProgress) + { + m_progress->MarkFinished(); + // We don't own this pointer and it will be deleted after it's marked finished + // just set it to nullptr so we don't try to use it again + m_progress = nullptr; + } + } + else if (m_progressDialog != NULL && m_autoClose) + m_progressDialog->Close(); +} + +bool CProgressJob::IsCancelled() const +{ + if (m_progressDialog != NULL) + return m_progressDialog->IsCanceled(); + + return false; +} + +bool CProgressJob::HasProgressIndicator() const +{ + return m_progress != nullptr || m_progressDialog != nullptr; +} diff --git a/xbmc/utils/ProgressJob.h b/xbmc/utils/ProgressJob.h new file mode 100644 index 0000000..f1117aa --- /dev/null +++ b/xbmc/utils/ProgressJob.h @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/Job.h" + +#include + +class CGUIDialogProgress; +class CGUIDialogProgressBarHandle; + +/*! + \brief Basic implementation of a CJob with a progress bar to indicate the + progress of the job being processed. + */ +class CProgressJob : public CJob +{ +public: + ~CProgressJob() override; + + // implementation of CJob + const char *GetType() const override { return "ProgressJob"; } + bool operator==(const CJob* job) const override { return false; } + bool ShouldCancel(unsigned int progress, unsigned int total) const override; + + /*! + \brief Executes the job showing a modal progress dialog. + */ + bool DoModal(); + + /*! + \brief Sets the given progress indicators to be used during execution of + the job. + + \details This automatically disables auto-closing the given progress + indicators once the job has been finished. + + \param progressBar Progress bar handle to be used. + \param progressDialog Progress dialog to be used. + \param updateProgress (optional) Whether to show progress updates. + \param updateInformation (optional) Whether to show progress information. + */ + void SetProgressIndicators(CGUIDialogProgressBarHandle* progressBar, CGUIDialogProgress* progressDialog, bool updateProgress = true, bool updateInformation = true); + + bool HasProgressIndicator() const; + +protected: + CProgressJob(); + explicit CProgressJob(CGUIDialogProgressBarHandle* progressBar); + + /*! + \brief Whether the job is being run modally or in the background. + */ + bool IsModal() const { return m_modal; } + + /*! + \brief Returns the progress bar indicating the progress of the job. + */ + CGUIDialogProgressBarHandle* GetProgressBar() const { return m_progress; } + + /*! + \brief Sets the progress bar indicating the progress of the job. + */ + void SetProgressBar(CGUIDialogProgressBarHandle* progress) { m_progress = progress; } + + /*! + \brief Returns the progress dialog indicating the progress of the job. + */ + CGUIDialogProgress* GetProgressDialog() const { return m_progressDialog; } + + /*! + \brief Sets the progress bar indicating the progress of the job. + */ + void SetProgressDialog(CGUIDialogProgress* progressDialog) { m_progressDialog = progressDialog; } + + /*! + \brief Whether to automatically close the progress indicator in MarkFinished(). + */ + bool GetAutoClose() { return m_autoClose; } + + /*! + \brief Set whether to automatically close the progress indicator in MarkFinished(). + */ + void SetAutoClose(bool autoClose) { m_autoClose = autoClose; } + + /*! + \brief Whether to update the progress bar or not. + */ + bool GetUpdateProgress() { return m_updateProgress; } + + /*! + \brief Set whether to update the progress bar or not. + */ + void SetUpdateProgress(bool updateProgress) { m_updateProgress = updateProgress; } + + /*! + \brief Whether to update the progress information or not. + */ + bool GetUpdateInformation() { return m_updateInformation; } + + /*! + \brief Set whether to update the progress information or not. + */ + void SetUpdateInformation(bool updateInformation) { m_updateInformation = updateInformation; } + + /*! + \brief Makes sure that the modal dialog is being shown. + */ + void ShowProgressDialog() const; + + /*! + \brief Sets the given title as the title of the progress bar. + + \param[in] title Title to be set + */ + void SetTitle(const std::string &title); + + /*! + \brief Sets the given text as the description of the progress bar. + + \param[in] text Text to be set + */ + void SetText(const std::string &text); + + /*! + \brief Sets the progress of the progress bar to the given value in percentage. + + \param[in] percentage Percentage to be set as the current progress + */ + void SetProgress(float percentage) const; + + /*! + \brief Sets the progress of the progress bar to the given value. + + \param[in] currentStep Current step being processed + \param[in] totalSteps Total steps to be processed + */ + void SetProgress(int currentStep, int totalSteps) const; + + /*! + \brief Marks the progress as finished by setting it to 100%. + */ + void MarkFinished(); + + /*! + \brief Checks if the progress dialog has been cancelled. + */ + bool IsCancelled() const; + +private: + bool m_modal = false; + bool m_autoClose = true; + bool m_updateProgress = true; + bool m_updateInformation = true; + mutable CGUIDialogProgressBarHandle* m_progress; + mutable CGUIDialogProgress* m_progressDialog; +}; diff --git a/xbmc/utils/Random.h b/xbmc/utils/Random.h new file mode 100644 index 0000000..ac2a073 --- /dev/null +++ b/xbmc/utils/Random.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include + +namespace KODI +{ +namespace UTILS +{ +template +void RandomShuffle(TIterator begin, TIterator end) +{ + std::random_device rd; + std::mt19937 mt(rd()); + std::shuffle(begin, end, mt); +} +} +} diff --git a/xbmc/utils/RecentlyAddedJob.cpp b/xbmc/utils/RecentlyAddedJob.cpp new file mode 100644 index 0000000..b45fade --- /dev/null +++ b/xbmc/utils/RecentlyAddedJob.cpp @@ -0,0 +1,390 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "RecentlyAddedJob.h" + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindow.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/WindowIDs.h" +#include "music/MusicDatabase.h" +#include "music/MusicThumbLoader.h" +#include "music/tags/MusicInfoTag.h" +#include "settings/AdvancedSettings.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/StringUtils.h" +#include "utils/log.h" +#include "video/VideoDatabase.h" +#include "video/VideoInfoTag.h" +#include "video/VideoThumbLoader.h" + +#if defined(TARGET_DARWIN_TVOS) +#include "platform/darwin/tvos/TVOSTopShelf.h" +#endif + +#define NUM_ITEMS 10 + +CRecentlyAddedJob::CRecentlyAddedJob(int flag) +{ + m_flag = flag; +} + +bool CRecentlyAddedJob::UpdateVideo() +{ + auto home = CServiceBroker::GetGUI()->GetWindowManager().GetWindow(WINDOW_HOME); + + if ( home == nullptr ) + return false; + + CLog::Log(LOGDEBUG, "CRecentlyAddedJob::UpdateVideos() - Running RecentlyAdded home screen update"); + + int i = 0; + CFileItemList items; + CVideoDatabase videodatabase; + CVideoThumbLoader loader; + loader.OnLoaderStart(); + + videodatabase.Open(); + + if (videodatabase.GetRecentlyAddedMoviesNav("videodb://recentlyaddedmovies/", items, NUM_ITEMS)) + { + for (; i < items.Size(); ++i) + { + auto item = items.Get(i); + std::string value = StringUtils::Format("%i", i + 1); + std::string strRating = StringUtils::Format("%.1f", item->GetVideoInfoTag()->GetRating().rating); + + home->SetProperty("LatestMovie." + value + ".Title" , item->GetLabel()); + home->SetProperty("LatestMovie." + value + ".Rating" , strRating); + home->SetProperty("LatestMovie." + value + ".Year" , item->GetVideoInfoTag()->GetYear()); + home->SetProperty("LatestMovie." + value + ".Plot" , item->GetVideoInfoTag()->m_strPlot); + home->SetProperty("LatestMovie." + value + ".RunningTime" , item->GetVideoInfoTag()->GetDuration() / 60); + home->SetProperty("LatestMovie." + value + ".Path" , item->GetVideoInfoTag()->m_strFileNameAndPath); + home->SetProperty("LatestMovie." + value + ".Trailer" , item->GetVideoInfoTag()->m_strTrailer); + + if (!item->HasArt("thumb")) + loader.LoadItem(item.get()); + + home->SetProperty("LatestMovie." + value + ".Thumb" , item->GetArt("thumb")); + home->SetProperty("LatestMovie." + value + ".Fanart" , item->GetArt("fanart")); + } + } + for (; i < NUM_ITEMS; ++i) + { + std::string value = StringUtils::Format("%i", i + 1); + home->SetProperty("LatestMovie." + value + ".Title" , ""); + home->SetProperty("LatestMovie." + value + ".Thumb" , ""); + home->SetProperty("LatestMovie." + value + ".Rating" , ""); + home->SetProperty("LatestMovie." + value + ".Year" , ""); + home->SetProperty("LatestMovie." + value + ".Plot" , ""); + home->SetProperty("LatestMovie." + value + ".RunningTime" , ""); + home->SetProperty("LatestMovie." + value + ".Path" , ""); + home->SetProperty("LatestMovie." + value + ".Trailer" , ""); + home->SetProperty("LatestMovie." + value + ".Fanart" , ""); + } + + i = 0; + CFileItemList TVShowItems; + + if (videodatabase.GetRecentlyAddedEpisodesNav("videodb://recentlyaddedepisodes/", TVShowItems, NUM_ITEMS)) + { + for (; i < TVShowItems.Size(); ++i) + { + auto item = TVShowItems.Get(i); + int EpisodeSeason = item->GetVideoInfoTag()->m_iSeason; + int EpisodeNumber = item->GetVideoInfoTag()->m_iEpisode; + std::string EpisodeNo = StringUtils::Format("s%02de%02d", EpisodeSeason, EpisodeNumber); + std::string value = StringUtils::Format("%i", i + 1); + std::string strRating = StringUtils::Format("%.1f", item->GetVideoInfoTag()->GetRating().rating); + + home->SetProperty("LatestEpisode." + value + ".ShowTitle" , item->GetVideoInfoTag()->m_strShowTitle); + home->SetProperty("LatestEpisode." + value + ".EpisodeTitle" , item->GetVideoInfoTag()->m_strTitle); + home->SetProperty("LatestEpisode." + value + ".Rating" , strRating); + home->SetProperty("LatestEpisode." + value + ".Plot" , item->GetVideoInfoTag()->m_strPlot); + home->SetProperty("LatestEpisode." + value + ".EpisodeNo" , EpisodeNo); + home->SetProperty("LatestEpisode." + value + ".EpisodeSeason" , EpisodeSeason); + home->SetProperty("LatestEpisode." + value + ".EpisodeNumber" , EpisodeNumber); + home->SetProperty("LatestEpisode." + value + ".Path" , item->GetVideoInfoTag()->m_strFileNameAndPath); + + if (!item->HasArt("thumb")) + loader.LoadItem(item.get()); + + std::string seasonThumb; + if (item->GetVideoInfoTag()->m_iIdSeason > 0) + seasonThumb = videodatabase.GetArtForItem(item->GetVideoInfoTag()->m_iIdSeason, MediaTypeSeason, "thumb"); + + home->SetProperty("LatestEpisode." + value + ".Thumb" , item->GetArt("thumb")); + home->SetProperty("LatestEpisode." + value + ".ShowThumb" , item->GetArt("tvshow.thumb")); + home->SetProperty("LatestEpisode." + value + ".SeasonThumb" , seasonThumb); + home->SetProperty("LatestEpisode." + value + ".Fanart" , item->GetArt("fanart")); + } + } + for (; i < NUM_ITEMS; ++i) + { + std::string value = StringUtils::Format("%i", i + 1); + home->SetProperty("LatestEpisode." + value + ".ShowTitle" , ""); + home->SetProperty("LatestEpisode." + value + ".EpisodeTitle" , ""); + home->SetProperty("LatestEpisode." + value + ".Rating" , ""); + home->SetProperty("LatestEpisode." + value + ".Plot" , ""); + home->SetProperty("LatestEpisode." + value + ".EpisodeNo" , ""); + home->SetProperty("LatestEpisode." + value + ".EpisodeSeason" , ""); + home->SetProperty("LatestEpisode." + value + ".EpisodeNumber" , ""); + home->SetProperty("LatestEpisode." + value + ".Path" , ""); + home->SetProperty("LatestEpisode." + value + ".Thumb" , ""); + home->SetProperty("LatestEpisode." + value + ".ShowThumb" , ""); + home->SetProperty("LatestEpisode." + value + ".SeasonThumb" , ""); + home->SetProperty("LatestEpisode." + value + ".Fanart" , ""); + } + +#if defined(TARGET_DARWIN_TVOS) + // send recently added Movies and TvShows to TopShelf + CTVOSTopShelf::GetInstance().SetTopShelfItems(items, TVShowItems); +#endif + + i = 0; + CFileItemList MusicVideoItems; + + if (videodatabase.GetRecentlyAddedMusicVideosNav("videodb://recentlyaddedmusicvideos/", MusicVideoItems, NUM_ITEMS)) + { + for (; i < MusicVideoItems.Size(); ++i) + { + auto item = MusicVideoItems.Get(i); + std::string value = StringUtils::Format("%i", i + 1); + + home->SetProperty("LatestMusicVideo." + value + ".Title" , item->GetLabel()); + home->SetProperty("LatestMusicVideo." + value + ".Year" , item->GetVideoInfoTag()->GetYear()); + home->SetProperty("LatestMusicVideo." + value + ".Plot" , item->GetVideoInfoTag()->m_strPlot); + home->SetProperty("LatestMusicVideo." + value + ".RunningTime" , item->GetVideoInfoTag()->GetDuration() / 60); + home->SetProperty("LatestMusicVideo." + value + ".Path" , item->GetVideoInfoTag()->m_strFileNameAndPath); + home->SetProperty("LatestMusicVideo." + value + ".Artist" , StringUtils::Join(item->GetVideoInfoTag()->m_artist, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator)); + + if (!item->HasArt("thumb")) + loader.LoadItem(item.get()); + + home->SetProperty("LatestMusicVideo." + value + ".Thumb" , item->GetArt("thumb")); + home->SetProperty("LatestMusicVideo." + value + ".Fanart" , item->GetArt("fanart")); + } + } + for (; i < NUM_ITEMS; ++i) + { + std::string value = StringUtils::Format("%i", i + 1); + home->SetProperty("LatestMusicVideo." + value + ".Title" , ""); + home->SetProperty("LatestMusicVideo." + value + ".Thumb" , ""); + home->SetProperty("LatestMusicVideo." + value + ".Year" , ""); + home->SetProperty("LatestMusicVideo." + value + ".Plot" , ""); + home->SetProperty("LatestMusicVideo." + value + ".RunningTime" , ""); + home->SetProperty("LatestMusicVideo." + value + ".Path" , ""); + home->SetProperty("LatestMusicVideo." + value + ".Artist" , ""); + home->SetProperty("LatestMusicVideo." + value + ".Fanart" , ""); + } + + videodatabase.Close(); + return true; +} + +bool CRecentlyAddedJob::UpdateMusic() +{ + auto home = CServiceBroker::GetGUI()->GetWindowManager().GetWindow(WINDOW_HOME); + + if ( home == nullptr ) + return false; + + CLog::Log(LOGDEBUG, "CRecentlyAddedJob::UpdateMusic() - Running RecentlyAdded home screen update"); + + int i = 0; + CFileItemList musicItems; + CMusicDatabase musicdatabase; + CMusicThumbLoader loader; + loader.OnLoaderStart(); + + musicdatabase.Open(); + + if (musicdatabase.GetRecentlyAddedAlbumSongs("musicdb://songs/", musicItems, NUM_ITEMS)) + { + long idAlbum = -1; + std::string strAlbumThumb; + std::string strAlbumFanart; + for (; i < musicItems.Size(); ++i) + { + auto item = musicItems.Get(i); + std::string value = StringUtils::Format("%d", i + 1); + + std::string strRating; + std::string strAlbum = item->GetMusicInfoTag()->GetAlbum(); + std::string strArtist = item->GetMusicInfoTag()->GetArtistString(); + + if (idAlbum != item->GetMusicInfoTag()->GetAlbumId()) + { + strAlbumThumb.clear(); + strAlbumFanart.clear(); + idAlbum = item->GetMusicInfoTag()->GetAlbumId(); + + if (loader.LoadItem(item.get())) + { + strAlbumThumb = item->GetArt("thumb"); + strAlbumFanart = item->GetArt("fanart"); + } + } + + strRating = StringUtils::Format("%c", item->GetMusicInfoTag()->GetUserrating()); + + home->SetProperty("LatestSong." + value + ".Title" , item->GetMusicInfoTag()->GetTitle()); + home->SetProperty("LatestSong." + value + ".Year" , item->GetMusicInfoTag()->GetYear()); + home->SetProperty("LatestSong." + value + ".Artist" , strArtist); + home->SetProperty("LatestSong." + value + ".Album" , strAlbum); + home->SetProperty("LatestSong." + value + ".Rating" , strRating); + home->SetProperty("LatestSong." + value + ".Path" , item->GetMusicInfoTag()->GetURL()); + home->SetProperty("LatestSong." + value + ".Thumb" , strAlbumThumb); + home->SetProperty("LatestSong." + value + ".Fanart" , strAlbumFanart); + } + } + for (; i < NUM_ITEMS; ++i) + { + std::string value = StringUtils::Format("%i", i + 1); + home->SetProperty("LatestSong." + value + ".Title" , ""); + home->SetProperty("LatestSong." + value + ".Year" , ""); + home->SetProperty("LatestSong." + value + ".Artist" , ""); + home->SetProperty("LatestSong." + value + ".Album" , ""); + home->SetProperty("LatestSong." + value + ".Rating" , ""); + home->SetProperty("LatestSong." + value + ".Path" , ""); + home->SetProperty("LatestSong." + value + ".Thumb" , ""); + home->SetProperty("LatestSong." + value + ".Fanart" , ""); + } + + i = 0; + VECALBUMS albums; + + if (musicdatabase.GetRecentlyAddedAlbums(albums, NUM_ITEMS)) + { + size_t j = 0; + for (; j < albums.size(); ++j) + { + auto& album=albums[j]; + std::string value = StringUtils::Format("%lu", j + 1); + std::string strThumb; + std::string strFanart; + bool artfound = false; + std::vector art; + // Get album thumb and fanart for first album artist + artfound = musicdatabase.GetArtForItem(-1, album.idAlbum, -1, true, art); + if (artfound) + { + for (auto artitem : art) + { + if (artitem.mediaType == MediaTypeAlbum && artitem.artType == "thumb") + strThumb = artitem.url; + else if (artitem.mediaType == MediaTypeArtist && artitem.artType == "fanart") + strFanart = artitem.url; + } + } + + std::string strDBpath = StringUtils::Format("musicdb://albums/%li/", album.idAlbum); + + home->SetProperty("LatestAlbum." + value + ".Title" , album.strAlbum); + home->SetProperty("LatestAlbum." + value + ".Year" , album.strReleaseDate); + home->SetProperty("LatestAlbum." + value + ".Artist" , album.GetAlbumArtistString()); + home->SetProperty("LatestAlbum." + value + ".Rating" , album.fRating); + home->SetProperty("LatestAlbum." + value + ".Path" , strDBpath); + home->SetProperty("LatestAlbum." + value + ".Thumb" , strThumb); + home->SetProperty("LatestAlbum." + value + ".Fanart" , strFanart); + } + i = j; + } + for (; i < NUM_ITEMS; ++i) + { + std::string value = StringUtils::Format("%i", i + 1); + home->SetProperty("LatestAlbum." + value + ".Title" , ""); + home->SetProperty("LatestAlbum." + value + ".Year" , ""); + home->SetProperty("LatestAlbum." + value + ".Artist" , ""); + home->SetProperty("LatestAlbum." + value + ".Rating" , ""); + home->SetProperty("LatestAlbum." + value + ".Path" , ""); + home->SetProperty("LatestAlbum." + value + ".Thumb" , ""); + home->SetProperty("LatestAlbum." + value + ".Fanart" , ""); + } + + musicdatabase.Close(); + return true; +} + +bool CRecentlyAddedJob::UpdateTotal() +{ + auto home = CServiceBroker::GetGUI()->GetWindowManager().GetWindow(WINDOW_HOME); + + if ( home == nullptr ) + return false; + + CLog::Log(LOGDEBUG, "CRecentlyAddedJob::UpdateTotal() - Running RecentlyAdded home screen update"); + + CVideoDatabase videodatabase; + CMusicDatabase musicdatabase; + + musicdatabase.Open(); + + CMusicDbUrl musicUrl; + musicUrl.FromString("musicdb://artists/"); + musicUrl.AddOption("albumartistsonly", !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_MUSICLIBRARY_SHOWCOMPILATIONARTISTS)); + + CFileItemList items; + CDatabase::Filter filter; + musicdatabase.GetArtistsByWhere(musicUrl.ToString(), filter, items, SortDescription(), true); + int MusArtistTotals = 0; + if (items.Size() == 1 && items.Get(0)->HasProperty("total")) + MusArtistTotals = items.Get(0)->GetProperty("total").asInteger(); + + int MusSongTotals = atoi(musicdatabase.GetSingleValue("songview" , "count(1)").c_str()); + int MusAlbumTotals = atoi(musicdatabase.GetSingleValue("songview" , "count(distinct strAlbum)").c_str()); + musicdatabase.Close(); + + videodatabase.Open(); + int tvShowCount = atoi(videodatabase.GetSingleValue("tvshow_view" , "count(1)").c_str()); + int movieTotals = atoi(videodatabase.GetSingleValue("movie_view" , "count(1)").c_str()); + int movieWatched = atoi(videodatabase.GetSingleValue("movie_view" , "count(playCount)").c_str()); + int MusVidTotals = atoi(videodatabase.GetSingleValue("musicvideo_view" , "count(1)").c_str()); + int MusVidWatched = atoi(videodatabase.GetSingleValue("musicvideo_view" , "count(playCount)").c_str()); + int EpWatched = atoi(videodatabase.GetSingleValue("tvshow_view" , "sum(watchedcount)").c_str()); + int EpCount = atoi(videodatabase.GetSingleValue("tvshow_view" , "sum(totalcount)").c_str()); + int TvShowsWatched = atoi(videodatabase.GetSingleValue("tvshow_view" , "sum(watchedcount = totalcount)").c_str()); + videodatabase.Close(); + + home->SetProperty("TVShows.Count" , tvShowCount); + home->SetProperty("TVShows.Watched" , TvShowsWatched); + home->SetProperty("TVShows.UnWatched" , tvShowCount - TvShowsWatched); + home->SetProperty("Episodes.Count" , EpCount); + home->SetProperty("Episodes.Watched" , EpWatched); + home->SetProperty("Episodes.UnWatched" , EpCount-EpWatched); + home->SetProperty("Movies.Count" , movieTotals); + home->SetProperty("Movies.Watched" , movieWatched); + home->SetProperty("Movies.UnWatched" , movieTotals - movieWatched); + home->SetProperty("MusicVideos.Count" , MusVidTotals); + home->SetProperty("MusicVideos.Watched" , MusVidWatched); + home->SetProperty("MusicVideos.UnWatched" , MusVidTotals - MusVidWatched); + home->SetProperty("Music.SongsCount" , MusSongTotals); + home->SetProperty("Music.AlbumsCount" , MusAlbumTotals); + home->SetProperty("Music.ArtistsCount" , MusArtistTotals); + + return true; +} + + +bool CRecentlyAddedJob::DoWork() +{ + bool ret = true; + if (m_flag & Audio) + ret &= UpdateMusic(); + + if (m_flag & Video) + ret &= UpdateVideo(); + + if (m_flag & Totals) + ret &= UpdateTotal(); + + return ret; +} diff --git a/xbmc/utils/RecentlyAddedJob.h b/xbmc/utils/RecentlyAddedJob.h new file mode 100644 index 0000000..f61b60b --- /dev/null +++ b/xbmc/utils/RecentlyAddedJob.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "Job.h" + +enum ERecentlyAddedFlag +{ + Audio = 0x1, + Video = 0x2, + Totals = 0x4 +}; + +class CRecentlyAddedJob : public CJob +{ +public: + explicit CRecentlyAddedJob(int flag); + static bool UpdateVideo(); + static bool UpdateMusic(); + static bool UpdateTotal(); + bool DoWork() override; +private: + int m_flag; +}; diff --git a/xbmc/utils/RegExp.cpp b/xbmc/utils/RegExp.cpp new file mode 100644 index 0000000..b6fe9d5 --- /dev/null +++ b/xbmc/utils/RegExp.cpp @@ -0,0 +1,642 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "RegExp.h" + +#include "log.h" +#include "utils/StringUtils.h" +#include "utils/Utf8Utils.h" + +#include +#include +#include + +using namespace PCRE; + +#ifndef PCRE_UCP +#define PCRE_UCP 0 +#endif // PCRE_UCP + +#ifdef PCRE_CONFIG_JIT +#define PCRE_HAS_JIT_CODE 1 +#endif + +#ifndef PCRE_STUDY_JIT_COMPILE +#define PCRE_STUDY_JIT_COMPILE 0 +#endif +#ifndef PCRE_INFO_JIT +// some unused number +#define PCRE_INFO_JIT 2048 +#endif +#ifndef PCRE_HAS_JIT_CODE +#define pcre_free_study(x) pcre_free((x)) +#endif + +int CRegExp::m_Utf8Supported = -1; +int CRegExp::m_UcpSupported = -1; +int CRegExp::m_JitSupported = -1; + + +CRegExp::CRegExp(bool caseless /*= false*/, CRegExp::utf8Mode utf8 /*= asciiOnly*/) +{ + InitValues(caseless, utf8); +} + +void CRegExp::InitValues(bool caseless /*= false*/, CRegExp::utf8Mode utf8 /*= asciiOnly*/) +{ + m_utf8Mode = utf8; + m_re = NULL; + m_sd = NULL; + m_iOptions = PCRE_DOTALL | PCRE_NEWLINE_ANY; + if(caseless) + m_iOptions |= PCRE_CASELESS; + if (m_utf8Mode == forceUtf8) + { + if (IsUtf8Supported()) + m_iOptions |= PCRE_UTF8; + if (AreUnicodePropertiesSupported()) + m_iOptions |= PCRE_UCP; + } + + m_offset = 0; + m_jitCompiled = false; + m_bMatched = false; + m_iMatchCount = 0; + m_jitStack = NULL; + + memset(m_iOvector, 0, sizeof(m_iOvector)); +} + +CRegExp::CRegExp(bool caseless, CRegExp::utf8Mode utf8, const char *re, studyMode study /*= NoStudy*/) +{ + if (utf8 == autoUtf8) + utf8 = requireUtf8(re) ? forceUtf8 : asciiOnly; + + InitValues(caseless, utf8); + RegComp(re, study); +} + +bool CRegExp::requireUtf8(const std::string& regexp) +{ + // enable UTF-8 mode if regexp string has UTF-8 multibyte sequences + if (CUtf8Utils::checkStrForUtf8(regexp) == CUtf8Utils::utf8string) + return true; + + // check for explicit Unicode Properties (\p, \P, \X) and for Unicode character codes (greater than 0xFF) in form \x{hhh..} + // note: PCRE change meaning of \w, \s, \d (and \W, \S, \D) when Unicode Properties are enabled, + // but in auto mode we enable UNP for US-ASCII regexp only if regexp contains explicit \p, \P, \X or Unicode character code + const char* const regexpC = regexp.c_str(); + const size_t len = regexp.length(); + size_t pos = 0; + + while (pos < len) + { + const char chr = regexpC[pos]; + if (chr == '\\') + { + const char nextChr = regexpC[pos + 1]; + + if (nextChr == 'p' || nextChr == 'P' || nextChr == 'X') + return true; // found Unicode Properties + else if (nextChr == 'Q') + pos = regexp.find("\\E", pos + 2); // skip all literals in "\Q...\E" + else if (nextChr == 'x' && regexpC[pos + 2] == '{') + { // Unicode character with hex code + if (readCharXCode(regexp, pos) >= 0x100) + return true; // found Unicode character code + } + else if (nextChr == '\\' || nextChr == '(' || nextChr == ')' + || nextChr == '[' || nextChr == ']') + pos++; // exclude next character from analyze + + } // chr != '\\' + else if (chr == '(' && regexpC[pos + 1] == '?' && regexpC[pos + 2] == '#') // comment in regexp + pos = regexp.find(')', pos); // skip comment + else if (chr == '[') + { + if (isCharClassWithUnicode(regexp, pos)) + return true; + } + + if (pos == std::string::npos) // check results of regexp.find() and isCharClassWithUnicode + return false; + + pos++; + } + + // no Unicode Properties was found + return false; +} + +inline int CRegExp::readCharXCode(const std::string& regexp, size_t& pos) +{ + // read hex character code in form "\x{hh..}" + // 'pos' must point to '\' + if (pos >= regexp.length()) + return -1; + const char* const regexpC = regexp.c_str(); + if (regexpC[pos] != '\\' || regexpC[pos + 1] != 'x' || regexpC[pos + 2] != '{') + return -1; + + pos++; + const size_t startPos = pos; // 'startPos' points to 'x' + const size_t closingBracketPos = regexp.find('}', startPos + 2); + if (closingBracketPos == std::string::npos) + return 0; // return character zero code, leave 'pos' at 'x' + + pos++; // 'pos' points to '{' + int chCode = 0; + while (++pos < closingBracketPos) + { + const int xdigitVal = StringUtils::asciixdigitvalue(regexpC[pos]); + if (xdigitVal >= 0) + chCode = chCode * 16 + xdigitVal; + else + { // found non-hexdigit + pos = startPos; // reset 'pos' to 'startPos', process "{hh..}" as non-code + return 0; // return character zero code + } + } + + return chCode; +} + +bool CRegExp::isCharClassWithUnicode(const std::string& regexp, size_t& pos) +{ + const char* const regexpC = regexp.c_str(); + const size_t len = regexp.length(); + if (pos > len || regexpC[pos] != '[') + return false; + + // look for Unicode character code "\x{hhh..}" and Unicode properties "\P", "\p" and "\X" + // find end (terminating ']') of character class (like "[a-h45]") + // detect nested POSIX classes like "[[:lower:]]" and escaped brackets like "[\]]" + bool needUnicode = false; + while (++pos < len) + { + if (regexpC[pos] == '[' && regexpC[pos + 1] == ':') + { // possible POSIX character class, like "[:alpha:]" + const size_t nextClosingBracketPos = regexp.find(']', pos + 2); // don't care about "\]", as it produce error if used inside POSIX char class + + if (nextClosingBracketPos == std::string::npos) + { // error in regexp: no closing ']' for character class + pos = std::string::npos; + return needUnicode; + } + else if (regexpC[nextClosingBracketPos - 1] == ':') + pos = nextClosingBracketPos; // skip POSIX character class + // if ":]" is not found, process "[:..." as part of normal character class + } + else if (regexpC[pos] == ']') + return needUnicode; // end of character class + else if (regexpC[pos] == '\\') + { + const char nextChar = regexpC[pos + 1]; + if (nextChar == ']' || nextChar == '[') + pos++; // skip next character + else if (nextChar == 'Q') + { + pos = regexp.find("\\E", pos + 2); + if (pos == std::string::npos) + return needUnicode; // error in regexp: no closing "\E" after "\Q" in character class + else + pos++; // skip "\E" + } + else if (nextChar == 'p' || nextChar == 'P' || nextChar == 'X') + needUnicode = true; // don't care about property name as it can contain only ASCII chars + else if (nextChar == 'x') + { + if (readCharXCode(regexp, pos) >= 0x100) + needUnicode = true; + } + } + } + pos = std::string::npos; // closing square bracket was not found + + return needUnicode; +} + + +CRegExp::CRegExp(const CRegExp& re) +{ + m_re = NULL; + m_sd = NULL; + m_jitStack = NULL; + m_utf8Mode = re.m_utf8Mode; + m_iOptions = re.m_iOptions; + *this = re; +} + +CRegExp& CRegExp::operator=(const CRegExp& re) +{ + size_t size; + Cleanup(); + m_jitCompiled = false; + m_pattern = re.m_pattern; + if (re.m_re) + { + if (pcre_fullinfo(re.m_re, NULL, PCRE_INFO_SIZE, &size) >= 0) + { + if ((m_re = (pcre*)malloc(size))) + { + memcpy(m_re, re.m_re, size); + memcpy(m_iOvector, re.m_iOvector, OVECCOUNT*sizeof(int)); + m_offset = re.m_offset; + m_iMatchCount = re.m_iMatchCount; + m_bMatched = re.m_bMatched; + m_subject = re.m_subject; + m_iOptions = re.m_iOptions; + } + else + CLog::Log(LOGFATAL, "%s: Failed to allocate memory", __FUNCTION__); + } + } + return *this; +} + +CRegExp::~CRegExp() +{ + Cleanup(); +} + +bool CRegExp::RegComp(const char *re, studyMode study /*= NoStudy*/) +{ + if (!re) + return false; + + m_offset = 0; + m_jitCompiled = false; + m_bMatched = false; + m_iMatchCount = 0; + const char *errMsg = NULL; + int errOffset = 0; + int options = m_iOptions; + if (m_utf8Mode == autoUtf8 && requireUtf8(re)) + options |= (IsUtf8Supported() ? PCRE_UTF8 : 0) | (AreUnicodePropertiesSupported() ? PCRE_UCP : 0); + + Cleanup(); + + m_re = pcre_compile(re, options, &errMsg, &errOffset, NULL); + if (!m_re) + { + m_pattern.clear(); + CLog::Log(LOGERROR, "PCRE: %s. Compilation failed at offset %d in expression '%s'", + errMsg, errOffset, re); + return false; + } + + m_pattern = re; + + if (study) + { + const bool jitCompile = (study == StudyWithJitComp) && IsJitSupported(); + const int studyOptions = jitCompile ? PCRE_STUDY_JIT_COMPILE : 0; + + m_sd = pcre_study(m_re, studyOptions, &errMsg); + if (errMsg != NULL) + { + CLog::Log(LOGWARNING, "%s: PCRE error \"%s\" while studying expression", __FUNCTION__, errMsg); + if (m_sd != NULL) + { + pcre_free_study(m_sd); + m_sd = NULL; + } + } + else if (jitCompile) + { + int jitPresent = 0; + m_jitCompiled = (pcre_fullinfo(m_re, m_sd, PCRE_INFO_JIT, &jitPresent) == 0 && jitPresent == 1); + } + } + + return true; +} + +int CRegExp::RegFind(const char *str, unsigned int startoffset /*= 0*/, int maxNumberOfCharsToTest /*= -1*/) +{ + return PrivateRegFind(strlen(str), str, startoffset, maxNumberOfCharsToTest); +} + +int CRegExp::PrivateRegFind(size_t bufferLen, const char *str, unsigned int startoffset /* = 0*/, int maxNumberOfCharsToTest /*= -1*/) +{ + m_offset = 0; + m_bMatched = false; + m_iMatchCount = 0; + + if (!m_re) + { + CLog::Log(LOGERROR, "PCRE: Called before compilation"); + return -1; + } + + if (!str) + { + CLog::Log(LOGERROR, "PCRE: Called without a string to match"); + return -1; + } + + if (startoffset > bufferLen) + { + CLog::Log(LOGERROR, "%s: startoffset is beyond end of string to match", __FUNCTION__); + return -1; + } + +#ifdef PCRE_HAS_JIT_CODE + if (m_jitCompiled && !m_jitStack) + { + m_jitStack = pcre_jit_stack_alloc(32*1024, 512*1024); + if (m_jitStack == NULL) + CLog::Log(LOGWARNING, "%s: can't allocate address space for JIT stack", __FUNCTION__); + + pcre_assign_jit_stack(m_sd, NULL, m_jitStack); + } +#endif + + if (maxNumberOfCharsToTest >= 0) + bufferLen = std::min(bufferLen, startoffset + maxNumberOfCharsToTest); + + m_subject.assign(str + startoffset, bufferLen - startoffset); + int rc = pcre_exec(m_re, NULL, m_subject.c_str(), m_subject.length(), 0, 0, m_iOvector, OVECCOUNT); + + if (rc<1) + { + static const int fragmentLen = 80; // length of excerpt before erroneous char for log + switch(rc) + { + case PCRE_ERROR_NOMATCH: + return -1; + + case PCRE_ERROR_MATCHLIMIT: + CLog::Log(LOGERROR, "PCRE: Match limit reached"); + return -1; + +#ifdef PCRE_ERROR_SHORTUTF8 + case PCRE_ERROR_SHORTUTF8: + { + const size_t startPos = (m_subject.length() > fragmentLen) ? CUtf8Utils::RFindValidUtf8Char(m_subject, m_subject.length() - fragmentLen) : 0; + if (startPos != std::string::npos) + CLog::Log(LOGERROR, "PCRE: Bad UTF-8 character at the end of string. Text before bad character: \"%s\"", m_subject.substr(startPos).c_str()); + else + CLog::Log(LOGERROR, "PCRE: Bad UTF-8 character at the end of string"); + return -1; + } +#endif + case PCRE_ERROR_BADUTF8: + { + const size_t startPos = (m_iOvector[0] > fragmentLen) ? CUtf8Utils::RFindValidUtf8Char(m_subject, m_iOvector[0] - fragmentLen) : 0; + if (m_iOvector[0] >= 0 && startPos != std::string::npos) + CLog::Log(LOGERROR, "PCRE: Bad UTF-8 character, error code: %d, position: %d. Text before bad char: \"%s\"", m_iOvector[1], m_iOvector[0], m_subject.substr(startPos, m_iOvector[0] - startPos + 1).c_str()); + else + CLog::Log(LOGERROR, "PCRE: Bad UTF-8 character, error code: %d, position: %d", m_iOvector[1], m_iOvector[0]); + return -1; + } + case PCRE_ERROR_BADUTF8_OFFSET: + CLog::Log(LOGERROR, "PCRE: Offset is pointing to the middle of UTF-8 character"); + return -1; + + default: + CLog::Log(LOGERROR, "PCRE: Unknown error: %d", rc); + return -1; + } + } + m_offset = startoffset; + m_bMatched = true; + m_iMatchCount = rc; + return m_iOvector[0] + m_offset; +} + +int CRegExp::GetCaptureTotal() const +{ + int c = -1; + if (m_re) + pcre_fullinfo(m_re, NULL, PCRE_INFO_CAPTURECOUNT, &c); + return c; +} + +std::string CRegExp::GetReplaceString(const std::string& sReplaceExp) const +{ + if (!m_bMatched || sReplaceExp.empty()) + return ""; + + const char* const expr = sReplaceExp.c_str(); + + size_t pos = sReplaceExp.find_first_of("\\&"); + std::string result(sReplaceExp, 0, pos); + result.reserve(sReplaceExp.size()); // very rough estimate + + while(pos != std::string::npos) + { + if (expr[pos] == '\\') + { + // string is null-terminated and current char isn't null, so it's safe to advance to next char + pos++; // advance to next char + const char nextChar = expr[pos]; + if (nextChar == '&' || nextChar == '\\') + { // this is "\&" or "\\" combination + result.push_back(nextChar); // add '&' or '\' to result + pos++; + } + else if (isdigit(nextChar)) + { // this is "\0" - "\9" combination + int subNum = nextChar - '0'; + pos++; // advance to second next char + const char secondNextChar = expr[pos]; + if (isdigit(secondNextChar)) + { // this is "\00" - "\99" combination + subNum = subNum * 10 + (secondNextChar - '0'); + pos++; + } + result.append(GetMatch(subNum)); + } + } + else + { // '&' char + result.append(GetMatch(0)); + pos++; + } + + const size_t nextPos = sReplaceExp.find_first_of("\\&", pos); + result.append(sReplaceExp, pos, nextPos - pos); + pos = nextPos; + } + + return result; +} + +int CRegExp::GetSubStart(int iSub) const +{ + if (!IsValidSubNumber(iSub)) + return -1; + + return m_iOvector[iSub*2] + m_offset; +} + +int CRegExp::GetSubStart(const std::string& subName) const +{ + return GetSubStart(GetNamedSubPatternNumber(subName.c_str())); +} + +int CRegExp::GetSubLength(int iSub) const +{ + if (!IsValidSubNumber(iSub)) + return -1; + + return m_iOvector[(iSub*2)+1] - m_iOvector[(iSub*2)]; +} + +int CRegExp::GetSubLength(const std::string& subName) const +{ + return GetSubLength(GetNamedSubPatternNumber(subName.c_str())); +} + +std::string CRegExp::GetMatch(int iSub /* = 0 */) const +{ + if (!IsValidSubNumber(iSub)) + return ""; + + int pos = m_iOvector[(iSub*2)]; + int len = m_iOvector[(iSub*2)+1] - pos; + if (pos < 0 || len <= 0) + return ""; + + return m_subject.substr(pos, len); +} + +std::string CRegExp::GetMatch(const std::string& subName) const +{ + return GetMatch(GetNamedSubPatternNumber(subName.c_str())); +} + +bool CRegExp::GetNamedSubPattern(const char* strName, std::string& strMatch) const +{ + strMatch.clear(); + int iSub = pcre_get_stringnumber(m_re, strName); + if (!IsValidSubNumber(iSub)) + return false; + strMatch = GetMatch(iSub); + return true; +} + +int CRegExp::GetNamedSubPatternNumber(const char* strName) const +{ + return pcre_get_stringnumber(m_re, strName); +} + +void CRegExp::DumpOvector(int iLog /* = LOGDEBUG */) +{ + if (iLog < LOGDEBUG || iLog > LOGNONE) + return; + + std::string str = "{"; + int size = GetSubCount(); // past the subpatterns is junk + for (int i = 0; i <= size; i++) + { + std::string t = StringUtils::Format("[%i,%i]", m_iOvector[(i*2)], m_iOvector[(i*2)+1]); + if (i != size) + t += ","; + str += t; + } + str += "}"; + CLog::Log(iLog, "regexp ovector=%s", str.c_str()); +} + +void CRegExp::Cleanup() +{ + if (m_re) + { + pcre_free(m_re); + m_re = NULL; + } + + if (m_sd) + { + pcre_free_study(m_sd); + m_sd = NULL; + } + +#ifdef PCRE_HAS_JIT_CODE + if (m_jitStack) + { + pcre_jit_stack_free(m_jitStack); + m_jitStack = NULL; + } +#endif +} + +inline bool CRegExp::IsValidSubNumber(int iSub) const +{ + return iSub >= 0 && iSub <= m_iMatchCount && iSub <= m_MaxNumOfBackrefrences; +} + + +bool CRegExp::IsUtf8Supported(void) +{ + if (m_Utf8Supported == -1) + { + if (pcre_config(PCRE_CONFIG_UTF8, &m_Utf8Supported) != 0) + m_Utf8Supported = 0; + } + + return m_Utf8Supported == 1; +} + +bool CRegExp::AreUnicodePropertiesSupported(void) +{ +#if defined(PCRE_CONFIG_UNICODE_PROPERTIES) && PCRE_UCP != 0 + if (m_UcpSupported == -1) + { + if (pcre_config(PCRE_CONFIG_UNICODE_PROPERTIES, &m_UcpSupported) != 0) + m_UcpSupported = 0; + } +#endif + + return m_UcpSupported == 1; +} + +bool CRegExp::LogCheckUtf8Support(void) +{ + bool utf8FullSupport = true; + + if (!CRegExp::IsUtf8Supported()) + { + utf8FullSupport = false; + CLog::Log(LOGWARNING, "UTF-8 is not supported in PCRE lib, support for national symbols is limited!"); + } + + if (!CRegExp::AreUnicodePropertiesSupported()) + { + utf8FullSupport = false; + CLog::Log(LOGWARNING, "Unicode properties are not enabled in PCRE lib, support for national symbols may be limited!"); + } + + if (!utf8FullSupport) + { + CLog::Log(LOGINFO, + "Consider installing PCRE lib version 8.10 or later with enabled Unicode properties " + "and UTF-8 support. Your PCRE lib version: %s", + PCRE::pcre_version()); +#if PCRE_UCP == 0 + CLog::Log(LOGINFO, "You will need to rebuild XBMC after PCRE lib update."); +#endif + } + + return utf8FullSupport; +} + +bool CRegExp::IsJitSupported(void) +{ + if (m_JitSupported == -1) + { +#ifdef PCRE_HAS_JIT_CODE + if (pcre_config(PCRE_CONFIG_JIT, &m_JitSupported) != 0) +#endif + m_JitSupported = 0; + } + + return m_JitSupported == 1; +} diff --git a/xbmc/utils/RegExp.h b/xbmc/utils/RegExp.h new file mode 100644 index 0000000..53f6019 --- /dev/null +++ b/xbmc/utils/RegExp.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +//! @todo - move to std::regex (after switching to gcc 4.9 or higher) and get rid of CRegExp + +#include +#include + +/* make sure stdlib.h is included before including pcre.h inside the + namespace; this works around stdlib.h definitions also living in + the PCRE namespace */ +#include + +namespace PCRE { +struct real_pcre_jit_stack; // forward declaration for PCRE without JIT +typedef struct real_pcre_jit_stack pcre_jit_stack; +#include +} + +class CRegExp +{ +public: + enum studyMode + { + NoStudy = 0, // do not study expression + StudyRegExp = 1, // study expression (slower compilation, faster find) + StudyWithJitComp // study expression and JIT-compile it, if possible (heavyweight optimization) + }; + enum utf8Mode + { + autoUtf8 = -1, // analyze regexp for UTF-8 multi-byte chars, for Unicode codes > 0xFF + // or explicit Unicode properties (\p, \P and \X), enable UTF-8 mode if any of them are found + asciiOnly = 0, // process regexp and strings as single-byte encoded strings + forceUtf8 = 1 // enable UTF-8 mode (with Unicode properties) + }; + + static const int m_MaxNumOfBackrefrences = 20; + /** + * @param caseless (optional) Matching will be case insensitive if set to true + * or case sensitive if set to false + * @param utf8 (optional) Control UTF-8 processing + */ + CRegExp(bool caseless = false, utf8Mode utf8 = asciiOnly); + /** + * Create new CRegExp object and compile regexp expression in one step + * @warning Use only with hardcoded regexp when you're sure that regexp is compiled without errors + * @param caseless Matching will be case insensitive if set to true + * or case sensitive if set to false + * @param utf8 Control UTF-8 processing + * @param re The regular expression + * @param study (optional) Controls study of expression, useful if expression will be used + * several times + */ + CRegExp(bool caseless, utf8Mode utf8, const char *re, studyMode study = NoStudy); + + CRegExp(const CRegExp& re); + ~CRegExp(); + + /** + * Compile (prepare) regular expression + * @param re The regular expression + * @param study (optional) Controls study of expression, useful if expression will be used + * several times + * @return true on success, false on any error + */ + bool RegComp(const char *re, studyMode study = NoStudy); + + /** + * Compile (prepare) regular expression + * @param re The regular expression + * @param study (optional) Controls study of expression, useful if expression will be used + * several times + * @return true on success, false on any error + */ + bool RegComp(const std::string& re, studyMode study = NoStudy) + { return RegComp(re.c_str(), study); } + + /** + * Find first match of regular expression in given string + * @param str The string to match against regular expression + * @param startoffset (optional) The string offset to start matching + * @param maxNumberOfCharsToTest (optional) The maximum number of characters to test (match) in + * string. If set to -1 string checked up to the end. + * @return staring position of match in string, negative value in case of error or no match + */ + int RegFind(const char* str, unsigned int startoffset = 0, int maxNumberOfCharsToTest = -1); + /** + * Find first match of regular expression in given string + * @param str The string to match against regular expression + * @param startoffset (optional) The string offset to start matching + * @param maxNumberOfCharsToTest (optional) The maximum number of characters to test (match) in + * string. If set to -1 string checked up to the end. + * @return staring position of match in string, negative value in case of error or no match + */ + int RegFind(const std::string& str, unsigned int startoffset = 0, int maxNumberOfCharsToTest = -1) + { return PrivateRegFind(str.length(), str.c_str(), startoffset, maxNumberOfCharsToTest); } + std::string GetReplaceString(const std::string& sReplaceExp) const; + int GetFindLen() const + { + if (!m_re || !m_bMatched) + return 0; + + return (m_iOvector[1] - m_iOvector[0]); + }; + int GetSubCount() const { return m_iMatchCount - 1; } // PCRE returns the number of sub-patterns + 1 + int GetSubStart(int iSub) const; + int GetSubStart(const std::string& subName) const; + int GetSubLength(int iSub) const; + int GetSubLength(const std::string& subName) const; + int GetCaptureTotal() const; + std::string GetMatch(int iSub = 0) const; + std::string GetMatch(const std::string& subName) const; + const std::string& GetPattern() const { return m_pattern; } + bool GetNamedSubPattern(const char* strName, std::string& strMatch) const; + int GetNamedSubPatternNumber(const char* strName) const; + void DumpOvector(int iLog); + /** + * Check is RegExp object is ready for matching + * @return true if RegExp object is ready for matching, false otherwise + */ + inline bool IsCompiled(void) const + { return !m_pattern.empty(); } + CRegExp& operator= (const CRegExp& re); + static bool IsUtf8Supported(void); + static bool AreUnicodePropertiesSupported(void); + static bool LogCheckUtf8Support(void); + static bool IsJitSupported(void); + +private: + int PrivateRegFind(size_t bufferLen, const char *str, unsigned int startoffset = 0, int maxNumberOfCharsToTest = -1); + void InitValues(bool caseless = false, CRegExp::utf8Mode utf8 = asciiOnly); + static bool requireUtf8(const std::string& regexp); + static int readCharXCode(const std::string& regexp, size_t& pos); + static bool isCharClassWithUnicode(const std::string& regexp, size_t& pos); + + void Cleanup(); + inline bool IsValidSubNumber(int iSub) const; + + PCRE::pcre* m_re; + PCRE::pcre_extra* m_sd; + static const int OVECCOUNT=(m_MaxNumOfBackrefrences + 1) * 3; + unsigned int m_offset; + int m_iOvector[OVECCOUNT]; + utf8Mode m_utf8Mode; + int m_iMatchCount; + int m_iOptions; + bool m_jitCompiled; + bool m_bMatched; + PCRE::pcre_jit_stack* m_jitStack; + std::string m_subject; + std::string m_pattern; + static int m_Utf8Supported; + static int m_UcpSupported; + static int m_JitSupported; +}; + +typedef std::vector VECCREGEXP; + diff --git a/xbmc/utils/RingBuffer.cpp b/xbmc/utils/RingBuffer.cpp new file mode 100644 index 0000000..f44ab57 --- /dev/null +++ b/xbmc/utils/RingBuffer.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2010-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "RingBuffer.h" + +#include "threads/SingleLock.h" + +#include +#include +#include + +/* Constructor */ +CRingBuffer::CRingBuffer() +{ + m_buffer = NULL; + m_size = 0; + m_readPtr = 0; + m_writePtr = 0; + m_fillCount = 0; +} + +/* Destructor */ +CRingBuffer::~CRingBuffer() +{ + Destroy(); +} + +/* Create a ring buffer with the specified 'size' */ +bool CRingBuffer::Create(unsigned int size) +{ + CSingleLock lock(m_critSection); + m_buffer = (char*)malloc(size); + if (m_buffer != NULL) + { + m_size = size; + return true; + } + return false; +} + +/* Free the ring buffer and set all values to NULL or 0 */ +void CRingBuffer::Destroy() +{ + CSingleLock lock(m_critSection); + if (m_buffer != NULL) + { + free(m_buffer); + m_buffer = NULL; + } + m_size = 0; + m_readPtr = 0; + m_writePtr = 0; + m_fillCount = 0; +} + +/* Clear the ring buffer */ +void CRingBuffer::Clear() +{ + CSingleLock lock(m_critSection); + m_readPtr = 0; + m_writePtr = 0; + m_fillCount = 0; +} + +/* Read in data from the ring buffer to the supplied buffer 'buf'. The amount + * read in is specified by 'size'. + */ +bool CRingBuffer::ReadData(char *buf, unsigned int size) +{ + CSingleLock lock(m_critSection); + if (size > m_fillCount) + { + return false; + } + if (size + m_readPtr > m_size) + { + unsigned int chunk = m_size - m_readPtr; + memcpy(buf, m_buffer + m_readPtr, chunk); + memcpy(buf + chunk, m_buffer, size - chunk); + m_readPtr = size - chunk; + } + else + { + memcpy(buf, m_buffer + m_readPtr, size); + m_readPtr += size; + } + if (m_readPtr == m_size) + m_readPtr = 0; + m_fillCount -= size; + return true; +} + +/* Read in data from the ring buffer to another ring buffer object specified by + * 'rBuf'. + */ +bool CRingBuffer::ReadData(CRingBuffer &rBuf, unsigned int size) +{ + CSingleLock lock(m_critSection); + if (rBuf.getBuffer() == NULL) + rBuf.Create(size); + + bool bOk = size <= rBuf.getMaxWriteSize() && size <= getMaxReadSize(); + if (bOk) + { + unsigned int chunksize = std::min(size, m_size - m_readPtr); + bOk = rBuf.WriteData(&getBuffer()[m_readPtr], chunksize); + if (bOk && chunksize < size) + bOk = rBuf.WriteData(&getBuffer()[0], size - chunksize); + if (bOk) + SkipBytes(size); + } + + return bOk; +} + +/* Write data to ring buffer from buffer specified in 'buf'. Amount read in is + * specified by 'size'. + */ +bool CRingBuffer::WriteData(const char *buf, unsigned int size) +{ + CSingleLock lock(m_critSection); + if (size > m_size - m_fillCount) + { + return false; + } + if (size + m_writePtr > m_size) + { + unsigned int chunk = m_size - m_writePtr; + memcpy(m_buffer + m_writePtr, buf, chunk); + memcpy(m_buffer, buf + chunk, size - chunk); + m_writePtr = size - chunk; + } + else + { + memcpy(m_buffer + m_writePtr, buf, size); + m_writePtr += size; + } + if (m_writePtr == m_size) + m_writePtr = 0; + m_fillCount += size; + return true; +} + +/* Write data to ring buffer from another ring buffer object specified by + * 'rBuf'. + */ +bool CRingBuffer::WriteData(CRingBuffer &rBuf, unsigned int size) +{ + CSingleLock lock(m_critSection); + if (m_buffer == NULL) + Create(size); + + bool bOk = size <= rBuf.getMaxReadSize() && size <= getMaxWriteSize(); + if (bOk) + { + unsigned int readpos = rBuf.getReadPtr(); + unsigned int chunksize = std::min(size, rBuf.getSize() - readpos); + bOk = WriteData(&rBuf.getBuffer()[readpos], chunksize); + if (bOk && chunksize < size) + bOk = WriteData(&rBuf.getBuffer()[0], size - chunksize); + } + + return bOk; +} + +/* Skip bytes in buffer to be read */ +bool CRingBuffer::SkipBytes(int skipSize) +{ + CSingleLock lock(m_critSection); + if (skipSize < 0) + { + return false; // skipping backwards is not supported + } + + unsigned int size = skipSize; + if (size > m_fillCount) + { + return false; + } + if (size + m_readPtr > m_size) + { + unsigned int chunk = m_size - m_readPtr; + m_readPtr = size - chunk; + } + else + { + m_readPtr += size; + } + if (m_readPtr == m_size) + m_readPtr = 0; + m_fillCount -= size; + return true; +} + +/* Append all content from ring buffer 'rBuf' to this ring buffer */ +bool CRingBuffer::Append(CRingBuffer &rBuf) +{ + return WriteData(rBuf, rBuf.getMaxReadSize()); +} + +/* Copy all content from ring buffer 'rBuf' to this ring buffer overwriting any existing data */ +bool CRingBuffer::Copy(CRingBuffer &rBuf) +{ + Clear(); + return Append(rBuf); +} + +/* Our various 'get' methods */ +char *CRingBuffer::getBuffer() +{ + return m_buffer; +} + +unsigned int CRingBuffer::getSize() +{ + CSingleLock lock(m_critSection); + return m_size; +} + +unsigned int CRingBuffer::getReadPtr() const +{ + return m_readPtr; +} + +unsigned int CRingBuffer::getWritePtr() +{ + CSingleLock lock(m_critSection); + return m_writePtr; +} + +unsigned int CRingBuffer::getMaxReadSize() +{ + CSingleLock lock(m_critSection); + return m_fillCount; +} + +unsigned int CRingBuffer::getMaxWriteSize() +{ + CSingleLock lock(m_critSection); + return m_size - m_fillCount; +} diff --git a/xbmc/utils/RingBuffer.h b/xbmc/utils/RingBuffer.h new file mode 100644 index 0000000..8cdb971 --- /dev/null +++ b/xbmc/utils/RingBuffer.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "threads/CriticalSection.h" + +class CRingBuffer +{ + CCriticalSection m_critSection; + char *m_buffer; + unsigned int m_size; + unsigned int m_readPtr; + unsigned int m_writePtr; + unsigned int m_fillCount; +public: + CRingBuffer(); + ~CRingBuffer(); + bool Create(unsigned int size); + void Destroy(); + void Clear(); + bool ReadData(char *buf, unsigned int size); + bool ReadData(CRingBuffer &rBuf, unsigned int size); + bool WriteData(const char *buf, unsigned int size); + bool WriteData(CRingBuffer &rBuf, unsigned int size); + bool SkipBytes(int skipSize); + bool Append(CRingBuffer &rBuf); + bool Copy(CRingBuffer &rBuf); + char *getBuffer(); + unsigned int getSize(); + unsigned int getReadPtr() const; + unsigned int getWritePtr(); + unsigned int getMaxReadSize(); + unsigned int getMaxWriteSize(); +}; diff --git a/xbmc/utils/RssManager.cpp b/xbmc/utils/RssManager.cpp new file mode 100644 index 0000000..2e26b4e --- /dev/null +++ b/xbmc/utils/RssManager.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "RssManager.h" + +#include "ServiceBroker.h" +#include "addons/AddonInstaller.h" +#include "addons/AddonManager.h" +#include "filesystem/File.h" +#include "interfaces/builtins/Builtins.h" +#include "messaging/helpers/DialogHelper.h" +#include "profiles/ProfileManager.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "settings/lib/Setting.h" +#include "threads/SingleLock.h" +#include "utils/RssReader.h" +#include "utils/StringUtils.h" +#include "utils/Variant.h" +#include "utils/log.h" + +#include + +using namespace XFILE; +using namespace KODI::MESSAGING; + + +CRssManager::CRssManager() +{ + m_bActive = false; +} + +CRssManager::~CRssManager() +{ + Stop(); +} + +CRssManager& CRssManager::GetInstance() +{ + static CRssManager sRssManager; + return sRssManager; +} + +void CRssManager::OnSettingsLoaded() +{ + Load(); +} + +void CRssManager::OnSettingsUnloaded() +{ + Clear(); +} + +void CRssManager::OnSettingAction(std::shared_ptr setting) +{ + if (setting == NULL) + return; + + const std::string &settingId = setting->GetId(); + if (settingId == CSettings::SETTING_LOOKANDFEEL_RSSEDIT) + { + ADDON::AddonPtr addon; + if (!CServiceBroker::GetAddonMgr().GetAddon("script.rss.editor", addon)) + { + if (!CAddonInstaller::GetInstance().InstallModal("script.rss.editor", addon)) + return; + } + CBuiltins::GetInstance().Execute("RunScript(script.rss.editor)"); + } +} + +void CRssManager::Start() + { + m_bActive = true; +} + +void CRssManager::Stop() +{ + CSingleLock lock(m_critical); + m_bActive = false; + for (unsigned int i = 0; i < m_readers.size(); i++) + { + if (m_readers[i].reader) + delete m_readers[i].reader; + } + m_readers.clear(); +} + +bool CRssManager::Load() +{ + const std::shared_ptr profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager(); + + CSingleLock lock(m_critical); + + std::string rssXML = profileManager->GetUserDataItem("RssFeeds.xml"); + if (!CFile::Exists(rssXML)) + return false; + + CXBMCTinyXML rssDoc; + if (!rssDoc.LoadFile(rssXML)) + { + CLog::Log(LOGERROR, "CRssManager: error loading %s, Line %d\n%s", rssXML.c_str(), rssDoc.ErrorRow(), rssDoc.ErrorDesc()); + return false; + } + + const TiXmlElement *pRootElement = rssDoc.RootElement(); + if (pRootElement == NULL || !StringUtils::EqualsNoCase(pRootElement->ValueStr(), "rssfeeds")) + { + CLog::Log(LOGERROR, "CRssManager: error loading %s, no node", rssXML.c_str()); + return false; + } + + m_mapRssUrls.clear(); + const TiXmlElement* pSet = pRootElement->FirstChildElement("set"); + while (pSet != NULL) + { + int iId; + if (pSet->QueryIntAttribute("id", &iId) == TIXML_SUCCESS) + { + RssSet set; + set.rtl = pSet->Attribute("rtl") != NULL && + StringUtils::CompareNoCase(pSet->Attribute("rtl"), "true") == 0; + const TiXmlElement* pFeed = pSet->FirstChildElement("feed"); + while (pFeed != NULL) + { + int iInterval; + if (pFeed->QueryIntAttribute("updateinterval", &iInterval) != TIXML_SUCCESS) + { + iInterval = 30; // default to 30 min + CLog::Log(LOGDEBUG, "CRssManager: no interval set, default to 30!"); + } + + if (pFeed->FirstChild() != NULL) + { + //! @todo UTF-8: Do these URLs need to be converted to UTF-8? + //! What about the xml encoding? + std::string strUrl = pFeed->FirstChild()->ValueStr(); + set.url.push_back(strUrl); + set.interval.push_back(iInterval); + } + pFeed = pFeed->NextSiblingElement("feed"); + } + + m_mapRssUrls.insert(std::make_pair(iId,set)); + } + else + CLog::Log(LOGERROR, "CRssManager: found rss url set with no id in RssFeeds.xml, ignored"); + + pSet = pSet->NextSiblingElement("set"); + } + + return true; +} + +bool CRssManager::Reload() +{ + Stop(); + if (!Load()) + return false; + Start(); + + return true; +} + +void CRssManager::Clear() +{ + CSingleLock lock(m_critical); + m_mapRssUrls.clear(); +} + +// returns true if the reader doesn't need creating, false otherwise +bool CRssManager::GetReader(int controlID, int windowID, IRssObserver* observer, CRssReader *&reader) +{ + CSingleLock lock(m_critical); + // check to see if we've already created this reader + for (unsigned int i = 0; i < m_readers.size(); i++) + { + if (m_readers[i].controlID == controlID && m_readers[i].windowID == windowID) + { + reader = m_readers[i].reader; + reader->SetObserver(observer); + reader->UpdateObserver(); + return true; + } + } + // need to create a new one + READERCONTROL readerControl; + readerControl.controlID = controlID; + readerControl.windowID = windowID; + reader = readerControl.reader = new CRssReader; + m_readers.push_back(readerControl); + return false; +} diff --git a/xbmc/utils/RssManager.h b/xbmc/utils/RssManager.h new file mode 100644 index 0000000..399cfa4 --- /dev/null +++ b/xbmc/utils/RssManager.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "settings/lib/ISettingCallback.h" +#include "settings/lib/ISettingsHandler.h" +#include "threads/CriticalSection.h" + +#include +#include +#include + +class CRssReader; +class IRssObserver; + +typedef struct +{ + bool rtl; + std::vector interval; + std::vector url; +} RssSet; +typedef std::map RssUrls; + +class CRssManager : public ISettingCallback, public ISettingsHandler +{ +public: + static CRssManager& GetInstance(); + + void OnSettingsLoaded() override; + void OnSettingsUnloaded() override; + + void OnSettingAction(std::shared_ptr setting) override; + + void Start(); + void Stop(); + bool Load(); + bool Reload(); + void Clear(); + bool IsActive() const { return m_bActive; } + + bool GetReader(int controlID, int windowID, IRssObserver* observer, CRssReader *&reader); + const RssUrls& GetUrls() const { return m_mapRssUrls; } + +protected: + CRssManager(); + ~CRssManager() override; + +private: + CRssManager(const CRssManager&) = delete; + CRssManager& operator=(const CRssManager&) = delete; + struct READERCONTROL + { + int controlID; + int windowID; + CRssReader *reader; + }; + + std::vector m_readers; + RssUrls m_mapRssUrls; + bool m_bActive; + CCriticalSection m_critical; +}; diff --git a/xbmc/utils/RssReader.cpp b/xbmc/utils/RssReader.cpp new file mode 100644 index 0000000..ecebc93 --- /dev/null +++ b/xbmc/utils/RssReader.cpp @@ -0,0 +1,413 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "RssReader.h" + +#include "CharsetConverter.h" +#include "ServiceBroker.h" +#include "URL.h" +#include "filesystem/CurlFile.h" +#include "filesystem/File.h" +#include "guilib/GUIRSSControl.h" +#include "guilib/LocalizeStrings.h" +#include "log.h" +#include "network/Network.h" +#include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" +#include "threads/SingleLock.h" +#include "threads/SystemClock.h" +#include "utils/HTMLUtil.h" +#include "utils/XTimeUtils.h" + +#define RSS_COLOR_BODY 0 +#define RSS_COLOR_HEADLINE 1 +#define RSS_COLOR_CHANNEL 2 + +using namespace XFILE; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CRssReader::CRssReader() : CThread("RSSReader") +{ + m_pObserver = NULL; + m_spacesBetweenFeeds = 0; + m_bIsRunning = false; + m_savedScrollPixelPos = 0; + m_rtlText = false; + m_requestRefresh = false; +} + +CRssReader::~CRssReader() +{ + if (m_pObserver) + m_pObserver->OnFeedRelease(); + StopThread(); + for (unsigned int i = 0; i < m_vecTimeStamps.size(); i++) + delete m_vecTimeStamps[i]; +} + +void CRssReader::Create(IRssObserver* aObserver, const std::vector& aUrls, const std::vector ×, int spacesBetweenFeeds, bool rtl) +{ + CSingleLock lock(m_critical); + + m_pObserver = aObserver; + m_spacesBetweenFeeds = spacesBetweenFeeds; + m_vecUrls = aUrls; + m_strFeed.resize(aUrls.size()); + m_strColors.resize(aUrls.size()); + // set update times + m_vecUpdateTimes = times; + m_rtlText = rtl; + m_requestRefresh = false; + + // update each feed on creation + for (unsigned int i = 0; i < m_vecUpdateTimes.size(); ++i) + { + AddToQueue(i); + KODI::TIME::SystemTime* time = new KODI::TIME::SystemTime; + KODI::TIME::GetLocalTime(time); + m_vecTimeStamps.push_back(time); + } +} + +void CRssReader::requestRefresh() +{ + m_requestRefresh = true; +} + +void CRssReader::AddToQueue(int iAdd) +{ + CSingleLock lock(m_critical); + if (iAdd < (int)m_vecUrls.size()) + m_vecQueue.push_back(iAdd); + if (!m_bIsRunning) + { + StopThread(); + m_bIsRunning = true; + CThread::Create(false); + } +} + +void CRssReader::OnExit() +{ + m_bIsRunning = false; +} + +int CRssReader::GetQueueSize() +{ + CSingleLock lock(m_critical); + return m_vecQueue.size(); +} + +void CRssReader::Process() +{ + while (GetQueueSize()) + { + CSingleLock lock(m_critical); + + int iFeed = m_vecQueue.front(); + m_vecQueue.erase(m_vecQueue.begin()); + + m_strFeed[iFeed].clear(); + m_strColors[iFeed].clear(); + + CCurlFile http; + http.SetUserAgent(CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_userAgent); + http.SetTimeout(2); + std::string strXML; + std::string strUrl = m_vecUrls[iFeed]; + lock.Leave(); + + int nRetries = 3; + CURL url(strUrl); + std::string fileCharset; + + // we wait for the network to come up + if ((url.IsProtocol("http") || url.IsProtocol("https")) && + !CServiceBroker::GetNetwork().IsAvailable()) + { + CLog::Log(LOGWARNING, "RSS: No network connection"); + strXML = ""+g_localizeStrings.Get(15301)+""; + } + else + { + XbmcThreads::EndTime timeout(15000); + while (!m_bStop && nRetries > 0) + { + if (timeout.IsTimePast()) + { + CLog::Log(LOGERROR, "Timeout while retrieving rss feed: %s", strUrl.c_str()); + break; + } + nRetries--; + + if (!url.IsProtocol("http") && !url.IsProtocol("https")) + { + CFile file; + auto_buffer buffer; + if (file.LoadFile(strUrl, buffer) > 0) + { + strXML.assign(buffer.get(), buffer.length()); + break; + } + } + else + { + if (http.Get(strUrl, strXML)) + { + fileCharset = http.GetProperty(XFILE::FILE_PROPERTY_CONTENT_CHARSET); + CLog::Log(LOGDEBUG, "Got rss feed: %s", strUrl.c_str()); + break; + } + else if (nRetries > 0) + CThread::Sleep(5000); // Network problems? Retry, but not immediately. + else + CLog::Log(LOGERROR, "Unable to obtain rss feed: %s", strUrl.c_str()); + } + } + http.Cancel(); + } + if (!strXML.empty() && m_pObserver) + { + // erase any tags (also unsupported by tinyxml) + size_t iStart = strXML.find(""); + size_t iEnd = 0; + while (iStart != std::string::npos) + { + // get end position + iEnd = strXML.find("", iStart) + 18; + + // erase the section + strXML = strXML.erase(iStart, iEnd - iStart); + + iStart = strXML.find(""); + } + + if (Parse(strXML, iFeed, fileCharset)) + CLog::Log(LOGDEBUG, "Parsed rss feed: %s", strUrl.c_str()); + } + } + UpdateObserver(); +} + +void CRssReader::getFeed(vecText &text) +{ + text.clear(); + // double the spaces at the start of the set + for (int j = 0; j < m_spacesBetweenFeeds; j++) + text.push_back(L' '); + for (unsigned int i = 0; i < m_strFeed.size(); i++) + { + for (int j = 0; j < m_spacesBetweenFeeds; j++) + text.push_back(L' '); + + for (unsigned int j = 0; j < m_strFeed[i].size(); j++) + { + character_t letter = m_strFeed[i][j] | ((m_strColors[i][j] - 48) << 16); + text.push_back(letter); + } + } +} + +void CRssReader::AddTag(const std::string &aString) +{ + m_tagSet.push_back(aString); +} + +void CRssReader::AddString(std::wstring aString, int aColour, int iFeed) +{ + if (m_rtlText) + m_strFeed[iFeed] = aString + m_strFeed[iFeed]; + else + m_strFeed[iFeed] += aString; + + size_t nStringLength = aString.size(); + + for (size_t i = 0;i < nStringLength;i++) + aString[i] = static_cast(48 + aColour); + + if (m_rtlText) + m_strColors[iFeed] = aString + m_strColors[iFeed]; + else + m_strColors[iFeed] += aString; +} + +void CRssReader::GetNewsItems(TiXmlElement* channelXmlNode, int iFeed) +{ + HTML::CHTMLUtil html; + + TiXmlElement * itemNode = channelXmlNode->FirstChildElement("item"); + std::map mTagElements; + typedef std::pair StrPair; + std::list::iterator i; + + // Add the title tag in if we didn't pass any tags in at all + // Represents default behaviour before configurability + + if (m_tagSet.empty()) + AddTag("title"); + + while (itemNode != nullptr) + { + TiXmlNode* childNode = itemNode->FirstChild(); + mTagElements.clear(); + while (childNode != nullptr) + { + std::string strName = childNode->ValueStr(); + + for (i = m_tagSet.begin(); i != m_tagSet.end(); ++i) + { + if (!childNode->NoChildren() && *i == strName) + { + std::string htmlText = childNode->FirstChild()->ValueStr(); + + // This usually happens in right-to-left languages where they want to + // specify in the RSS body that the text should be RTL. + // + // <div dir="RTL">��� ����: ���� �� �����</div> + // + if (htmlText == "div" || htmlText == "span") + htmlText = childNode->FirstChild()->FirstChild()->ValueStr(); + + std::wstring unicodeText, unicodeText2; + + g_charsetConverter.utf8ToW(htmlText, unicodeText2, m_rtlText); + html.ConvertHTMLToW(unicodeText2, unicodeText); + + mTagElements.insert(StrPair(*i, unicodeText)); + } + } + childNode = childNode->NextSibling(); + } + + int rsscolour = RSS_COLOR_HEADLINE; + for (i = m_tagSet.begin(); i != m_tagSet.end(); ++i) + { + std::map::iterator j = mTagElements.find(*i); + + if (j == mTagElements.end()) + continue; + + std::wstring& text = j->second; + AddString(text, rsscolour, iFeed); + rsscolour = RSS_COLOR_BODY; + text = L" - "; + AddString(text, rsscolour, iFeed); + } + itemNode = itemNode->NextSiblingElement("item"); + } +} + +bool CRssReader::Parse(const std::string& data, int iFeed, const std::string& charset) +{ + m_xml.Clear(); + m_xml.Parse(data, charset); + + CLog::Log(LOGDEBUG, "RSS feed encoding: %s", m_xml.GetUsedCharset().c_str()); + + return Parse(iFeed); +} + +bool CRssReader::Parse(int iFeed) +{ + TiXmlElement* rootXmlNode = m_xml.RootElement(); + + if (!rootXmlNode) + return false; + + TiXmlElement* rssXmlNode = NULL; + + std::string strValue = rootXmlNode->ValueStr(); + if (strValue.find("rss") != std::string::npos || + strValue.find("rdf") != std::string::npos) + rssXmlNode = rootXmlNode; + else + { + // Unable to find root or node + return false; + } + + TiXmlElement* channelXmlNode = rssXmlNode->FirstChildElement("channel"); + if (channelXmlNode) + { + TiXmlElement* titleNode = channelXmlNode->FirstChildElement("title"); + if (titleNode && !titleNode->NoChildren()) + { + std::string strChannel = titleNode->FirstChild()->Value(); + std::wstring strChannelUnicode; + g_charsetConverter.utf8ToW(strChannel, strChannelUnicode, m_rtlText); + AddString(strChannelUnicode, RSS_COLOR_CHANNEL, iFeed); + + AddString(L":", RSS_COLOR_CHANNEL, iFeed); + AddString(L" ", RSS_COLOR_CHANNEL, iFeed); + } + + GetNewsItems(channelXmlNode,iFeed); + } + + GetNewsItems(rssXmlNode,iFeed); + + // avoid trailing ' - ' + if (m_strFeed[iFeed].size() > 3 && m_strFeed[iFeed].substr(m_strFeed[iFeed].size() - 3) == L" - ") + { + if (m_rtlText) + { + m_strFeed[iFeed].erase(0, 3); + m_strColors[iFeed].erase(0, 3); + } + else + { + m_strFeed[iFeed].erase(m_strFeed[iFeed].length() - 3); + m_strColors[iFeed].erase(m_strColors[iFeed].length() - 3); + } + } + return true; +} + +void CRssReader::SetObserver(IRssObserver *observer) +{ + m_pObserver = observer; +} + +void CRssReader::UpdateObserver() +{ + if (!m_pObserver) + return; + + vecText feed; + getFeed(feed); + if (!feed.empty()) + { + CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext()); + if (m_pObserver) // need to check again when locked to make sure observer wasnt removed + m_pObserver->OnFeedUpdate(feed); + } +} + +void CRssReader::CheckForUpdates() +{ + KODI::TIME::SystemTime time; + KODI::TIME::GetLocalTime(&time); + + for (unsigned int i = 0;i < m_vecUpdateTimes.size(); ++i ) + { + if (m_requestRefresh || ((time.day * 24 * 60) + (time.hour * 60) + time.minute) - + ((m_vecTimeStamps[i]->day * 24 * 60) + + (m_vecTimeStamps[i]->hour * 60) + m_vecTimeStamps[i]->minute) > + m_vecUpdateTimes[i]) + { + CLog::Log(LOGDEBUG, "Updating RSS"); + KODI::TIME::GetLocalTime(m_vecTimeStamps[i]); + AddToQueue(i); + } + } + + m_requestRefresh = false; +} diff --git a/xbmc/utils/RssReader.h b/xbmc/utils/RssReader.h new file mode 100644 index 0000000..6e259ff --- /dev/null +++ b/xbmc/utils/RssReader.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "XBDateTime.h" +#include "threads/CriticalSection.h" +#include "threads/Thread.h" +#include "utils/IRssObserver.h" +#include "utils/XBMCTinyXML.h" + +#include +#include +#include + +class CRssReader : public CThread +{ +public: + CRssReader(); + ~CRssReader() override; + + void Create(IRssObserver* aObserver, const std::vector& aUrl, const std::vector& times, int spacesBetweenFeeds, bool rtl); + bool Parse(const std::string& data, int iFeed, const std::string& charset); + void getFeed(vecText &text); + void AddTag(const std::string &addTag); + void AddToQueue(int iAdd); + void UpdateObserver(); + void SetObserver(IRssObserver* observer); + void CheckForUpdates(); + void requestRefresh(); + float m_savedScrollPixelPos; + +private: + void Process() override; + bool Parse(int iFeed); + void GetNewsItems(TiXmlElement* channelXmlNode, int iFeed); + void AddString(std::wstring aString, int aColour, int iFeed); + void UpdateFeed(); + void OnExit() override; + int GetQueueSize(); + + IRssObserver* m_pObserver; + + std::vector m_strFeed; + std::vector m_strColors; + std::vector m_vecTimeStamps; + std::vector m_vecUpdateTimes; + int m_spacesBetweenFeeds; + CXBMCTinyXML m_xml; + std::list m_tagSet; + std::vector m_vecUrls; + std::vector m_vecQueue; + bool m_bIsRunning; + bool m_rtlText; + bool m_requestRefresh; + + CCriticalSection m_critical; +}; diff --git a/xbmc/utils/SaveFileStateJob.cpp b/xbmc/utils/SaveFileStateJob.cpp new file mode 100644 index 0000000..26b7b5c --- /dev/null +++ b/xbmc/utils/SaveFileStateJob.cpp @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2010-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "SaveFileStateJob.h" + +#include "Application.h" +#include "FileItem.h" +#include "GUIUserMessages.h" +#include "ServiceBroker.h" +#include "StringUtils.h" +#include "URIUtils.h" +#include "URL.h" +#include "Util.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIMessage.h" +#include "guilib/GUIWindowManager.h" +#include "interfaces/AnnouncementManager.h" +#include "log.h" +#include "music/MusicDatabase.h" +#include "music/tags/MusicInfoTag.h" +#include "network/upnp/UPnP.h" +#include "utils/Variant.h" +#include "video/Bookmark.h" +#include "video/VideoDatabase.h" + +void CSaveFileState::DoWork(CFileItem& item, + CBookmark& bookmark, + bool updatePlayCount) +{ + std::string progressTrackingFile = item.GetPath(); + + if (item.HasVideoInfoTag() && StringUtils::StartsWith(item.GetVideoInfoTag()->m_strFileNameAndPath, "removable://")) + progressTrackingFile = item.GetVideoInfoTag()->m_strFileNameAndPath; // this variable contains removable:// suffixed by disc label+uniqueid or is empty if label not uniquely identified + else if (item.HasVideoInfoTag() && item.IsVideoDb()) + progressTrackingFile = item.GetVideoInfoTag()->m_strFileNameAndPath; // we need the file url of the video db item to create the bookmark + else if (item.HasProperty("original_listitem_url")) + { + // only use original_listitem_url for Python, UPnP and Bluray sources + std::string original = item.GetProperty("original_listitem_url").asString(); + if (URIUtils::IsPlugin(original) || URIUtils::IsUPnP(original) || URIUtils::IsBluray(item.GetPath())) + progressTrackingFile = original; + } + + if (!progressTrackingFile.empty()) + { +#ifdef HAS_UPNP + // checks if UPnP server of this file is available and supports updating + if (URIUtils::IsUPnP(progressTrackingFile) + && UPNP::CUPnP::SaveFileState(item, bookmark, updatePlayCount)) + { + return; + } +#endif + if (item.IsVideo()) + { + std::string redactPath = CURL::GetRedacted(progressTrackingFile); + CLog::Log(LOGDEBUG, "%s - Saving file state for video item %s", __FUNCTION__, redactPath.c_str()); + + CVideoDatabase videodatabase; + if (!videodatabase.Open()) + { + CLog::Log(LOGWARNING, "%s - Unable to open video database. Can not save file state!", __FUNCTION__); + } + else + { + if (URIUtils::IsPlugin(progressTrackingFile) && !(item.HasVideoInfoTag() && item.GetVideoInfoTag()->m_iDbId >= 0)) + { + // FileItem from plugin can lack information, make sure all needed fields are set + CVideoInfoTag *tag = item.GetVideoInfoTag(); + CStreamDetails streams = tag->m_streamDetails; + if (videodatabase.LoadVideoInfo(progressTrackingFile, *tag)) + { + item.SetPath(progressTrackingFile); + item.ClearProperty("original_listitem_url"); + tag->m_streamDetails = streams; + } + } + + bool updateListing = false; + // No resume & watched status for livetv + if (!item.IsLiveTV()) + { + if (updatePlayCount) + { + // no watched for not yet finished pvr recordings + if (!item.IsInProgressPVRRecording()) + { + CLog::Log(LOGDEBUG, "%s - Marking video item %s as watched", __FUNCTION__, redactPath.c_str()); + + // consider this item as played + videodatabase.IncrementPlayCount(item); + item.GetVideoInfoTag()->IncrementPlayCount(); + + item.SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, true); + updateListing = true; + + if (item.HasVideoInfoTag()) + { + CVariant data; + data["id"] = item.GetVideoInfoTag()->m_iDbId; + data["type"] = item.GetVideoInfoTag()->m_type; + CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::VideoLibrary, "xbmc", "OnUpdate", data); + } + } + } + else + videodatabase.UpdateLastPlayed(item); + + if (!item.HasVideoInfoTag() || + item.GetVideoInfoTag()->GetResumePoint().timeInSeconds != bookmark.timeInSeconds) + { + if (bookmark.timeInSeconds <= 0.0f) + videodatabase.ClearBookMarksOfFile(progressTrackingFile, CBookmark::RESUME); + else + videodatabase.AddBookMarkToFile(progressTrackingFile, bookmark, CBookmark::RESUME); + if (item.HasVideoInfoTag()) + item.GetVideoInfoTag()->SetResumePoint(bookmark); + + // UPnP announce resume point changes to clients + // however not if playcount is modified as that already announces + if (item.HasVideoInfoTag() && !updatePlayCount) + { + CVariant data; + data["id"] = item.GetVideoInfoTag()->m_iDbId; + data["type"] = item.GetVideoInfoTag()->m_type; + CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::VideoLibrary, "xbmc", "OnUpdate", data); + } + + updateListing = true; + } + } + + if (item.HasVideoInfoTag() && item.GetVideoInfoTag()->HasStreamDetails()) + { + CFileItem dbItem(item); + + // Check whether the item's db streamdetails need updating + if (!videodatabase.GetStreamDetails(dbItem) || + dbItem.GetVideoInfoTag()->m_streamDetails != item.GetVideoInfoTag()->m_streamDetails) + { + videodatabase.SetStreamDetailsForFile(item.GetVideoInfoTag()->m_streamDetails, progressTrackingFile); + updateListing = true; + } + } + + // Could be part of an ISO stack. In this case the bookmark is saved onto the part. + // In order to properly update the list, we need to refresh the stack's resume point + CApplicationStackHelper& stackHelper = g_application.GetAppStackHelper(); + if (stackHelper.HasRegisteredStack(item) && stackHelper.GetRegisteredStackTotalTimeMs(item) == 0) + videodatabase.GetResumePoint(*(stackHelper.GetRegisteredStack(item)->GetVideoInfoTag())); + + videodatabase.Close(); + + if (updateListing) + { + CUtil::DeleteVideoDatabaseDirectoryCache(); + CFileItemPtr msgItem(new CFileItem(item)); + if (item.HasProperty("original_listitem_url")) + msgItem->SetPath(item.GetProperty("original_listitem_url").asString()); + CGUIMessage message(GUI_MSG_NOTIFY_ALL, CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow(), 0, GUI_MSG_UPDATE_ITEM, 0, msgItem); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message); + } + } + } + + if (item.IsAudio()) + { + std::string redactPath = CURL::GetRedacted(progressTrackingFile); + CLog::Log(LOGDEBUG, "%s - Saving file state for audio item %s", __FUNCTION__, redactPath.c_str()); + + CMusicDatabase musicdatabase; + if (updatePlayCount) + { + if (!musicdatabase.Open()) + { + CLog::Log(LOGWARNING, "%s - Unable to open music database. Can not save file state!", __FUNCTION__); + } + else + { + // consider this item as played + CLog::Log(LOGDEBUG, "%s - Marking audio item %s as listened", __FUNCTION__, redactPath.c_str()); + + musicdatabase.IncrementPlayCount(item); + musicdatabase.Close(); + + // UPnP announce resume point changes to clients + // however not if playcount is modified as that already announces + if (item.IsMusicDb()) + { + CVariant data; + data["id"] = item.GetMusicInfoTag()->GetDatabaseId(); + data["type"] = item.GetMusicInfoTag()->GetType(); + CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::AudioLibrary, "xbmc", "OnUpdate", data); + } + } + } + + if (item.IsAudioBook()) + { + musicdatabase.Open(); + musicdatabase.SetResumeBookmarkForAudioBook(item, item.m_lStartOffset + CUtil::ConvertSecsToMilliSecs(bookmark.timeInSeconds)); + musicdatabase.Close(); + } + } + } +} diff --git a/xbmc/utils/SaveFileStateJob.h b/xbmc/utils/SaveFileStateJob.h new file mode 100644 index 0000000..b7bb0cc --- /dev/null +++ b/xbmc/utils/SaveFileStateJob.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2010-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +class CBookmark; +class CFileItem; + +class CSaveFileState +{ +public: + static void DoWork(CFileItem& item, + CBookmark& bookmark, + bool updatePlayCount); +}; + diff --git a/xbmc/utils/ScopeGuard.h b/xbmc/utils/ScopeGuard.h new file mode 100644 index 0000000..a1aa0a6 --- /dev/null +++ b/xbmc/utils/ScopeGuard.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +namespace KODI +{ +namespace UTILS +{ + +/*! \class CScopeGuard + \brief Generic scopeguard designed to handle any type of handle + + This is not necessary but recommended to cut down on some typing + using CSocketHandle = CScopeGuard; + + CSocketHandle sh(closesocket, open(thingy)); + */ +template +class CScopeGuard +{ + +public: + + CScopeGuard(std::function del, Handle handle = invalid) + : m_handle{handle} + , m_deleter{del} + { }; + + ~CScopeGuard() noexcept + { + reset(); + } + + operator Handle() const + { + return m_handle; + } + + operator bool() const + { + return m_handle != invalid; + } + + /*! \brief attach a new handle to this instance, if there's + already a handle it will be closed. + + \param[in] handle The handle to manage + */ + void attach(Handle handle) + { + reset(); + + m_handle = handle; + } + + /*! \brief release the managed handle so that it won't be auto closed + + \return The handle being managed by the guard + */ + Handle release() + { + Handle h = m_handle; + m_handle = invalid; + return h; + } + + /*! \brief reset the instance, closing any managed handle and setting it to invalid + */ + void reset() + { + if (m_handle != invalid) + { + m_deleter(m_handle); + m_handle = invalid; + } + } + + //Disallow default construction and copying + CScopeGuard() = delete; + CScopeGuard(const CScopeGuard& rhs) = delete; + CScopeGuard& operator= (const CScopeGuard& rhs) = delete; + + //Allow moving + CScopeGuard(CScopeGuard&& rhs) + : m_handle{std::move(rhs.m_handle)}, m_deleter{std::move(rhs.m_deleter)} + { + // Bring moved-from object into released state so destructor will not do anything + rhs.release(); + } + CScopeGuard& operator=(CScopeGuard&& rhs) + { + attach(rhs.release()); + m_deleter = std::move(rhs.m_deleter); + return *this; + } + +private: + Handle m_handle; + std::function m_deleter; +}; + +} +} diff --git a/xbmc/utils/ScraperParser.cpp b/xbmc/utils/ScraperParser.cpp new file mode 100644 index 0000000..81fcf37 --- /dev/null +++ b/xbmc/utils/ScraperParser.cpp @@ -0,0 +1,616 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ScraperParser.h" + +#include "addons/AddonManager.h" +#include "guilib/LocalizeStrings.h" +#include "RegExp.h" +#include "HTMLUtil.h" +#include "addons/Scraper.h" +#include "URL.h" +#include "utils/StringUtils.h" +#include "log.h" +#include "CharsetConverter.h" +#ifdef HAVE_LIBXSLT +#include "utils/XSLTUtils.h" +#endif +#include "utils/XMLUtils.h" +#include +#include + +using namespace ADDON; +using namespace XFILE; + +CScraperParser::CScraperParser() +{ + m_pRootElement = NULL; + m_document = NULL; + m_SearchStringEncoding = "UTF-8"; + m_scraper = NULL; + m_isNoop = true; +} + +CScraperParser::CScraperParser(const CScraperParser& parser) +{ + m_pRootElement = NULL; + m_document = NULL; + m_SearchStringEncoding = "UTF-8"; + m_scraper = NULL; + m_isNoop = true; + *this = parser; +} + +CScraperParser &CScraperParser::operator=(const CScraperParser &parser) +{ + if (this != &parser) + { + Clear(); + if (parser.m_document) + { + m_scraper = parser.m_scraper; + m_document = new CXBMCTinyXML(*parser.m_document); + LoadFromXML(); + } + else + m_scraper = NULL; + } + return *this; +} + +CScraperParser::~CScraperParser() +{ + Clear(); +} + +void CScraperParser::Clear() +{ + m_pRootElement = NULL; + delete m_document; + + m_document = NULL; + m_strFile.clear(); +} + +bool CScraperParser::Load(const std::string& strXMLFile) +{ + Clear(); + + m_document = new CXBMCTinyXML(); + + if (!m_document) + return false; + + m_strFile = strXMLFile; + + if (m_document->LoadFile(strXMLFile)) + return LoadFromXML(); + + delete m_document; + m_document = NULL; + return false; +} + +bool CScraperParser::LoadFromXML() +{ + if (!m_document) + return false; + + m_pRootElement = m_document->RootElement(); + std::string strValue = m_pRootElement->ValueStr(); + if (strValue == "scraper") + { + TiXmlElement* pChildElement = m_pRootElement->FirstChildElement("CreateSearchUrl"); + if (pChildElement) + { + m_isNoop = false; + if (!(m_SearchStringEncoding = pChildElement->Attribute("SearchStringEncoding"))) + m_SearchStringEncoding = "UTF-8"; + } + + pChildElement = m_pRootElement->FirstChildElement("CreateArtistSearchUrl"); + if (pChildElement) + { + m_isNoop = false; + if (!(m_SearchStringEncoding = pChildElement->Attribute("SearchStringEncoding"))) + m_SearchStringEncoding = "UTF-8"; + } + pChildElement = m_pRootElement->FirstChildElement("CreateAlbumSearchUrl"); + if (pChildElement) + { + m_isNoop = false; + if (!(m_SearchStringEncoding = pChildElement->Attribute("SearchStringEncoding"))) + m_SearchStringEncoding = "UTF-8"; + } + + return true; + } + + delete m_document; + m_document = NULL; + m_pRootElement = NULL; + return false; +} + +void CScraperParser::ReplaceBuffers(std::string& strDest) +{ + // insert buffers + size_t iIndex; + for (int i=MAX_SCRAPER_BUFFERS-1; i>=0; i--) + { + iIndex = 0; + std::string temp = StringUtils::Format("$$%i",i+1); + while ((iIndex = strDest.find(temp,iIndex)) != std::string::npos) + { + strDest.replace(strDest.begin()+iIndex,strDest.begin()+iIndex+temp.size(),m_param[i]); + iIndex += m_param[i].length(); + } + } + // insert settings + iIndex = 0; + while ((iIndex = strDest.find("$INFO[", iIndex)) != std::string::npos) + { + size_t iEnd = strDest.find("]", iIndex); + std::string strInfo = strDest.substr(iIndex+6, iEnd - iIndex - 6); + std::string strReplace; + if (m_scraper) + strReplace = m_scraper->GetSetting(strInfo); + strDest.replace(strDest.begin()+iIndex,strDest.begin()+iEnd+1,strReplace); + iIndex += strReplace.length(); + } + // insert localize strings + iIndex = 0; + while ((iIndex = strDest.find("$LOCALIZE[", iIndex)) != std::string::npos) + { + size_t iEnd = strDest.find("]", iIndex); + std::string strInfo = strDest.substr(iIndex+10, iEnd - iIndex - 10); + std::string strReplace; + if (m_scraper) + strReplace = g_localizeStrings.GetAddonString(m_scraper->ID(), strtol(strInfo.c_str(),NULL,10)); + strDest.replace(strDest.begin()+iIndex,strDest.begin()+iEnd+1,strReplace); + iIndex += strReplace.length(); + } + iIndex = 0; + while ((iIndex = strDest.find("\\n",iIndex)) != std::string::npos) + strDest.replace(strDest.begin()+iIndex,strDest.begin()+iIndex+2,"\n"); +} + +void CScraperParser::ParseExpression(const std::string& input, std::string& dest, TiXmlElement* element, bool bAppend) +{ + std::string strOutput = XMLUtils::GetAttribute(element, "output"); + + TiXmlElement* pExpression = element->FirstChildElement("expression"); + if (pExpression) + { + bool bInsensitive=true; + const char* sensitive = pExpression->Attribute("cs"); + if (sensitive) + if (StringUtils::CompareNoCase(sensitive, "yes") == 0) + bInsensitive=false; // match case sensitive + + CRegExp::utf8Mode eUtf8 = CRegExp::autoUtf8; + const char* const strUtf8 = pExpression->Attribute("utf8"); + if (strUtf8) + { + if (StringUtils::CompareNoCase(strUtf8, "yes") == 0) + eUtf8 = CRegExp::forceUtf8; + else if (StringUtils::CompareNoCase(strUtf8, "no") == 0) + eUtf8 = CRegExp::asciiOnly; + else if (StringUtils::CompareNoCase(strUtf8, "auto") == 0) + eUtf8 = CRegExp::autoUtf8; + } + + CRegExp reg(bInsensitive, eUtf8); + std::string strExpression; + if (pExpression->FirstChild()) + strExpression = pExpression->FirstChild()->Value(); + else + strExpression = "(.*)"; + ReplaceBuffers(strExpression); + ReplaceBuffers(strOutput); + + if (!reg.RegComp(strExpression.c_str())) + { + return; + } + + bool bRepeat = false; + const char* szRepeat = pExpression->Attribute("repeat"); + if (szRepeat) + if (StringUtils::CompareNoCase(szRepeat, "yes") == 0) + bRepeat = true; + + const char* szClear = pExpression->Attribute("clear"); + if (szClear) + if (StringUtils::CompareNoCase(szClear, "yes") == 0) + dest=""; // clear no matter if regexp fails + + bool bClean[MAX_SCRAPER_BUFFERS]; + GetBufferParams(bClean,pExpression->Attribute("noclean"),true); + + bool bTrim[MAX_SCRAPER_BUFFERS]; + GetBufferParams(bTrim,pExpression->Attribute("trim"),false); + + bool bFixChars[MAX_SCRAPER_BUFFERS]; + GetBufferParams(bFixChars,pExpression->Attribute("fixchars"),false); + + bool bEncode[MAX_SCRAPER_BUFFERS]; + GetBufferParams(bEncode,pExpression->Attribute("encode"),false); + + int iOptional = -1; + pExpression->QueryIntAttribute("optional",&iOptional); + + int iCompare = -1; + pExpression->QueryIntAttribute("compare",&iCompare); + if (iCompare > -1) + StringUtils::ToLower(m_param[iCompare-1]); + std::string curInput = input; + for (int iBuf=0;iBuf -1 && (i < (int)curInput.size() || curInput.empty())) + { + if (!bAppend) + { + dest = ""; + bAppend = true; + } + std::string strCurOutput=strOutput; + + if (iOptional > -1) // check that required param is there + { + char temp[12]; + sprintf(temp,"\\%i",iOptional); + std::string szParam = reg.GetReplaceString(temp); + CRegExp reg2; + reg2.RegComp("(.*)(\\\\\\(.*\\\\2.*)\\\\\\)(.*)"); + int i2=reg2.RegFind(strCurOutput.c_str()); + while (i2 > -1) + { + std::string szRemove(reg2.GetMatch(2)); + int iRemove = szRemove.size(); + int i3 = strCurOutput.find(szRemove); + if (!szParam.empty()) + { + strCurOutput.erase(i3+iRemove,2); + strCurOutput.erase(i3,2); + } + else + strCurOutput.replace(strCurOutput.begin()+i3,strCurOutput.begin()+i3+iRemove+2,""); + + i2 = reg2.RegFind(strCurOutput.c_str()); + } + } + + int iLen = reg.GetFindLen(); + // nasty hack #1 - & means \0 in a replace string + StringUtils::Replace(strCurOutput, "&","!!!AMPAMP!!!"); + std::string result = reg.GetReplaceString(strCurOutput.c_str()); + if (!result.empty()) + { + std::string strResult(result); + StringUtils::Replace(strResult, "!!!AMPAMP!!!","&"); + Clean(strResult); + ReplaceBuffers(strResult); + if (iCompare > -1) + { + std::string strResultNoCase = strResult; + StringUtils::ToLower(strResultNoCase); + if (strResultNoCase.find(m_param[iCompare-1]) != std::string::npos) + dest += strResult; + } + else + dest += strResult; + } + if (bRepeat && iLen > 0) + { + curInput.erase(0,i+iLen>(int)curInput.size()?curInput.size():i+iLen); + i = reg.RegFind(curInput.c_str()); + } + else + i = -1; + } + } +} + +void CScraperParser::ParseXSLT(const std::string& input, std::string& dest, TiXmlElement* element, bool bAppend) +{ +#ifdef HAVE_LIBXSLT + TiXmlElement* pSheet = element->FirstChildElement(); + if (pSheet) + { + XSLTUtils xsltUtils; + std::string strXslt; + strXslt << *pSheet; + ReplaceBuffers(strXslt); + + if (!xsltUtils.SetInput(input)) + CLog::Log(LOGDEBUG, "could not parse input XML"); + + if (!xsltUtils.SetStylesheet(strXslt)) + CLog::Log(LOGDEBUG, "could not parse stylesheet XML"); + + xsltUtils.XSLTTransform(dest); + } +#endif +} + +TiXmlElement *FirstChildScraperElement(TiXmlElement *element) +{ + for (TiXmlElement *child = element->FirstChildElement(); child; child = child->NextSiblingElement()) + { +#ifdef HAVE_LIBXSLT + if (child->ValueStr() == "XSLT") + return child; +#endif + if (child->ValueStr() == "RegExp") + return child; + } + return NULL; +} + +TiXmlElement *NextSiblingScraperElement(TiXmlElement *element) +{ + for (TiXmlElement *next = element->NextSiblingElement(); next; next = next->NextSiblingElement()) + { +#ifdef HAVE_LIBXSLT + if (next->ValueStr() == "XSLT") + return next; +#endif + if (next->ValueStr() == "RegExp") + return next; + } + return NULL; +} + +void CScraperParser::ParseNext(TiXmlElement* element) +{ + TiXmlElement* pReg = element; + while (pReg) + { + TiXmlElement* pChildReg = FirstChildScraperElement(pReg); + if (pChildReg) + ParseNext(pChildReg); + else + { + TiXmlElement* pChildReg = pReg->FirstChildElement("clear"); + if (pChildReg) + ParseNext(pChildReg); + } + + int iDest = 1; + bool bAppend = false; + const char* szDest = pReg->Attribute("dest"); + if (szDest && strlen(szDest)) + { + if (szDest[strlen(szDest)-1] == '+') + bAppend = true; + + iDest = atoi(szDest); + } + + const char *szInput = pReg->Attribute("input"); + std::string strInput; + if (szInput) + { + strInput = szInput; + ReplaceBuffers(strInput); + } + else + strInput = m_param[0]; + + const char* szConditional = pReg->Attribute("conditional"); + bool bExecute = true; + if (szConditional) + { + bool bInverse=false; + if (szConditional[0] == '!') + { + bInverse = true; + szConditional++; + } + std::string strSetting; + if (m_scraper && m_scraper->HasSettings()) + strSetting = m_scraper->GetSetting(szConditional); + bExecute = bInverse != (strSetting == "true"); + } + + if (bExecute) + { + if (iDest-1 < MAX_SCRAPER_BUFFERS && iDest-1 > -1) + { +#ifdef HAVE_LIBXSLT + if (pReg->ValueStr() == "XSLT") + ParseXSLT(strInput, m_param[iDest - 1], pReg, bAppend); + else +#endif + ParseExpression(strInput, m_param[iDest - 1],pReg,bAppend); + } + else + CLog::Log(LOGERROR,"CScraperParser::ParseNext: destination buffer " + "out of bounds, skipping expression"); + } + pReg = NextSiblingScraperElement(pReg); + } +} + +const std::string CScraperParser::Parse(const std::string& strTag, + CScraper* scraper) +{ + TiXmlElement* pChildElement = m_pRootElement->FirstChildElement(strTag.c_str()); + if(pChildElement == NULL) + { + CLog::Log(LOGERROR,"%s: Could not find scraper function %s",__FUNCTION__,strTag.c_str()); + return ""; + } + int iResult = 1; // default to param 1 + pChildElement->QueryIntAttribute("dest",&iResult); + TiXmlElement* pChildStart = FirstChildScraperElement(pChildElement); + m_scraper = scraper; + ParseNext(pChildStart); + std::string tmp = m_param[iResult-1]; + + const char* szClearBuffers = pChildElement->Attribute("clearbuffers"); + if (!szClearBuffers || StringUtils::CompareNoCase(szClearBuffers, "no") != 0) + ClearBuffers(); + + return tmp; +} + +void CScraperParser::Clean(std::string& strDirty) +{ + size_t i = 0; + std::string strBuffer; + while ((i = strDirty.find("!!!CLEAN!!!",i)) != std::string::npos) + { + size_t i2; + if ((i2 = strDirty.find("!!!CLEAN!!!",i+11)) != std::string::npos) + { + strBuffer = strDirty.substr(i+11,i2-i-11); + std::string strConverted(strBuffer); + HTML::CHTMLUtil::RemoveTags(strConverted); + StringUtils::Trim(strConverted); + strDirty.replace(i, i2-i+11, strConverted); + i += strConverted.size(); + } + else + break; + } + i=0; + while ((i = strDirty.find("!!!TRIM!!!",i)) != std::string::npos) + { + size_t i2; + if ((i2 = strDirty.find("!!!TRIM!!!",i+10)) != std::string::npos) + { + strBuffer = strDirty.substr(i+10,i2-i-10); + StringUtils::Trim(strBuffer); + strDirty.replace(i, i2-i+10, strBuffer); + i += strBuffer.size(); + } + else + break; + } + i=0; + while ((i = strDirty.find("!!!FIXCHARS!!!",i)) != std::string::npos) + { + size_t i2; + if ((i2 = strDirty.find("!!!FIXCHARS!!!",i+14)) != std::string::npos) + { + strBuffer = strDirty.substr(i+14,i2-i-14); + std::wstring wbuffer; + g_charsetConverter.utf8ToW(strBuffer, wbuffer, false, false, false); + std::wstring wConverted; + HTML::CHTMLUtil::ConvertHTMLToW(wbuffer,wConverted); + g_charsetConverter.wToUTF8(wConverted, strBuffer, false); + StringUtils::Trim(strBuffer); + ConvertJSON(strBuffer); + strDirty.replace(i, i2-i+14, strBuffer); + i += strBuffer.size(); + } + else + break; + } + i=0; + while ((i=strDirty.find("!!!ENCODE!!!",i)) != std::string::npos) + { + size_t i2; + if ((i2 = strDirty.find("!!!ENCODE!!!",i+12)) != std::string::npos) + { + strBuffer = CURL::Encode(strDirty.substr(i + 12, i2 - i - 12)); + strDirty.replace(i, i2-i+12, strBuffer); + i += strBuffer.size(); + } + else + break; + } +} + +void CScraperParser::ConvertJSON(std::string &string) +{ + CRegExp reg; + reg.RegComp("\\\\u([0-f]{4})"); + while (reg.RegFind(string.c_str()) > -1) + { + int pos = reg.GetSubStart(1); + std::string szReplace(reg.GetMatch(1)); + + std::string replace = StringUtils::Format("&#x%s;", szReplace.c_str()); + string.replace(string.begin()+pos-2, string.begin()+pos+4, replace); + } + + CRegExp reg2; + reg2.RegComp("\\\\x([0-9]{2})([^\\\\]+;)"); + while (reg2.RegFind(string.c_str()) > -1) + { + int pos1 = reg2.GetSubStart(1); + int pos2 = reg2.GetSubStart(2); + std::string szHexValue(reg2.GetMatch(1)); + + std::string replace = StringUtils::Format("%li", strtol(szHexValue.c_str(), NULL, 16)); + string.replace(string.begin()+pos1-2, string.begin()+pos2+reg2.GetSubLength(2), replace); + } + + StringUtils::Replace(string, "\\\"","\""); +} + +void CScraperParser::ClearBuffers() +{ + //clear all m_param strings + for (std::string& param : m_param) + param.clear(); +} + +void CScraperParser::GetBufferParams(bool* result, const char* attribute, bool defvalue) +{ + for (int iBuf=0;iBuf vecBufs; + StringUtils::Tokenize(attribute,vecBufs,","); + for (size_t nToken=0; nToken < vecBufs.size(); nToken++) + { + int index = atoi(vecBufs[nToken].c_str())-1; + if (index < MAX_SCRAPER_BUFFERS) + result[index] = !defvalue; + } + } +} + +void CScraperParser::InsertToken(std::string& strOutput, int buf, const char* token) +{ + char temp[4]; + sprintf(temp,"\\%i",buf); + size_t i2=0; + while ((i2 = strOutput.find(temp,i2)) != std::string::npos) + { + strOutput.insert(i2,token); + i2 += strlen(token) + strlen(temp); + strOutput.insert(i2,token); + } +} + +void CScraperParser::AddDocument(const CXBMCTinyXML* doc) +{ + const TiXmlNode* node = doc->RootElement()->FirstChild(); + while (node) + { + m_pRootElement->InsertEndChild(*node); + node = node->NextSibling(); + } +} + diff --git a/xbmc/utils/ScraperParser.h b/xbmc/utils/ScraperParser.h new file mode 100644 index 0000000..293dbcc --- /dev/null +++ b/xbmc/utils/ScraperParser.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include + +#define MAX_SCRAPER_BUFFERS 20 + +namespace ADDON +{ + class CScraper; +} + +class TiXmlElement; +class CXBMCTinyXML; + +class CScraperSettings; + +class CScraperParser +{ +public: + CScraperParser(); + CScraperParser(const CScraperParser& parser); + ~CScraperParser(); + CScraperParser& operator= (const CScraperParser& parser); + bool Load(const std::string& strXMLFile); + bool IsNoop() const { return m_isNoop; }; + + void Clear(); + const std::string& GetFilename() const { return m_strFile; } + std::string GetSearchStringEncoding() const + { return m_SearchStringEncoding; } + const std::string Parse(const std::string& strTag, + ADDON::CScraper* scraper); + + void AddDocument(const CXBMCTinyXML* doc); + + std::string m_param[MAX_SCRAPER_BUFFERS]; + +private: + bool LoadFromXML(); + void ReplaceBuffers(std::string& strDest); + void ParseExpression(const std::string& input, std::string& dest, TiXmlElement* element, bool bAppend); + + /*! \brief Parse an 'XSLT' declaration from the scraper + This allow us to transform an inbound XML document using XSLT + to a different type of XML document, ready to be output direct + to the album loaders or similar + \param input the input document + \param dest the output destination for the conversion + \param element the current XML element + \param bAppend append or clear the buffer + */ + void ParseXSLT(const std::string& input, std::string& dest, TiXmlElement* element, bool bAppend); + void ParseNext(TiXmlElement* element); + void Clean(std::string& strDirty); + void ConvertJSON(std::string &string); + void ClearBuffers(); + void GetBufferParams(bool* result, const char* attribute, bool defvalue); + void InsertToken(std::string& strOutput, int buf, const char* token); + + CXBMCTinyXML* m_document; + TiXmlElement* m_pRootElement; + + const char* m_SearchStringEncoding; + bool m_isNoop; + + std::string m_strFile; + ADDON::CScraper* m_scraper; +}; + diff --git a/xbmc/utils/ScraperUrl.cpp b/xbmc/utils/ScraperUrl.cpp new file mode 100644 index 0000000..f242a40 --- /dev/null +++ b/xbmc/utils/ScraperUrl.cpp @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ScraperUrl.h" + +#include "CharsetConverter.h" +#include "ServiceBroker.h" +#include "URIUtils.h" +#include "URL.h" +#include "XMLUtils.h" +#include "filesystem/CurlFile.h" +#include "filesystem/ZipFile.h" +#include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" +#include "utils/CharsetDetection.h" +#include "utils/Mime.h" +#include "utils/StringUtils.h" +#include "utils/XBMCTinyXML.h" +#include "utils/log.h" + +#include +#include +#include + +CScraperUrl::CScraperUrl() : m_relevance(0.0), m_parsed(false) +{ +} + +CScraperUrl::CScraperUrl(std::string strUrl) : CScraperUrl() +{ + ParseFromData(std::move(strUrl)); +} + +CScraperUrl::CScraperUrl(const TiXmlElement* element) : CScraperUrl() +{ + ParseAndAppendUrl(element); +} + +CScraperUrl::~CScraperUrl() = default; + +void CScraperUrl::Clear() +{ + m_urls.clear(); + m_data.clear(); + m_relevance = 0.0; + m_parsed = false; +} + +void CScraperUrl::SetData(std::string data) +{ + m_data = std::move(data); + m_parsed = false; +} + +const CScraperUrl::SUrlEntry CScraperUrl::GetFirstUrlByType(const std::string& type) const +{ + const auto url = std::find_if(m_urls.begin(), m_urls.end(), [type](const SUrlEntry& url) { + return url.m_type == UrlType::General && (type.empty() || url.m_aspect == type); + }); + if (url != m_urls.end()) + return *url; + + return SUrlEntry(); +} + +const CScraperUrl::SUrlEntry CScraperUrl::GetSeasonUrl(int season, const std::string& type) const +{ + const auto url = std::find_if(m_urls.begin(), m_urls.end(), [season, type](const SUrlEntry& url) { + return url.m_type == UrlType::Season && url.m_season == season && + (type.empty() || type == "thumb" || url.m_aspect == type); + }); + if (url != m_urls.end()) + return *url; + + return SUrlEntry(); +} + +unsigned int CScraperUrl::GetMaxSeasonUrl() const +{ + unsigned int maxSeason = 0; + for (const auto& url : m_urls) + { + if (url.m_type == UrlType::Season && url.m_season > 0 && + static_cast(url.m_season) > maxSeason) + maxSeason = url.m_season; + } + return maxSeason; +} + +std::string CScraperUrl::GetFirstThumbUrl() const +{ + if (m_urls.empty()) + return {}; + + return GetThumbUrl(m_urls.front()); +} + +void CScraperUrl::GetThumbUrls(std::vector& thumbs, + const std::string& type, + int season, + bool unique) const +{ + for (const auto& url : m_urls) + { + if (url.m_aspect == type || type.empty() || url.m_aspect.empty()) + { + if ((url.m_type == CScraperUrl::UrlType::General && season == -1) || + (url.m_type == CScraperUrl::UrlType::Season && url.m_season == season)) + { + std::string thumbUrl = GetThumbUrl(url); + if (!unique || std::find(thumbs.begin(), thumbs.end(), thumbUrl) == thumbs.end()) + thumbs.push_back(thumbUrl); + } + } + } +} + +bool CScraperUrl::Parse() +{ + if (m_parsed) + return true; + + auto dataToParse = m_data; + m_data.clear(); + return ParseFromData(std::move(dataToParse)); +} + +bool CScraperUrl::ParseFromData(std::string data) +{ + if (data.empty()) + return false; + + CXBMCTinyXML doc; + /* strUrl is coming from internal sources (usually generated by scraper or from database) + * so strUrl is always in UTF-8 */ + doc.Parse(data, TIXML_ENCODING_UTF8); + + auto pElement = doc.RootElement(); + if (pElement == nullptr) + { + m_urls.emplace_back(data); + m_data = data; + } + else + { + while (pElement != nullptr) + { + ParseAndAppendUrl(pElement); + pElement = pElement->NextSiblingElement(pElement->Value()); + } + } + + m_parsed = true; + return true; +} + +bool CScraperUrl::ParseAndAppendUrl(const TiXmlElement* element) +{ + if (element == nullptr || element->FirstChild() == nullptr || + element->FirstChild()->Value() == nullptr) + return false; + + bool wasEmpty = m_data.empty(); + + std::stringstream stream; + stream << *element; + m_data += stream.str(); + + SUrlEntry url(element->FirstChild()->ValueStr()); + url.m_spoof = XMLUtils::GetAttribute(element, "spoof"); + + const char* szPost = element->Attribute("post"); + if (szPost && StringUtils::CompareNoCase(szPost, "yes") == 0) + url.m_post = true; + else + url.m_post = false; + + const char* szIsGz = element->Attribute("gzip"); + if (szIsGz && StringUtils::CompareNoCase(szIsGz, "yes") == 0) + url.m_isgz = true; + else + url.m_isgz = false; + + url.m_cache = XMLUtils::GetAttribute(element, "cache"); + + const char* szType = element->Attribute("type"); + if (szType && StringUtils::CompareNoCase(szType, "season") == 0) + { + url.m_type = UrlType::Season; + const char* szSeason = element->Attribute("season"); + if (szSeason) + url.m_season = atoi(szSeason); + } + + url.m_aspect = XMLUtils::GetAttribute(element, "aspect"); + + m_urls.push_back(url); + + if (wasEmpty) + m_parsed = true; + + return true; +} + +// XML format is of strUrls is: +// ...... (parsed by ParseElement) or ... (ditto) +bool CScraperUrl::ParseAndAppendUrlsFromEpisodeGuide(std::string episodeGuide) +{ + if (episodeGuide.empty()) + return false; + + // ok, now parse the xml file + CXBMCTinyXML doc; + /* strUrls is coming from internal sources so strUrls is always in UTF-8 */ + doc.Parse(episodeGuide, TIXML_ENCODING_UTF8); + if (doc.RootElement() == nullptr) + return false; + + bool wasEmpty = m_data.empty(); + + TiXmlHandle docHandle(&doc); + auto link = docHandle.FirstChild("episodeguide").Element(); + if (link->FirstChildElement("url")) + { + for (link = link->FirstChildElement("url"); link; link = link->NextSiblingElement("url")) + ParseAndAppendUrl(link); + } + else if (link->FirstChild() && link->FirstChild()->Value()) + ParseAndAppendUrl(link); + + if (wasEmpty) + m_parsed = true; + + return true; +} + +void CScraperUrl::AddParsedUrl(std::string url, + std::string aspect, + std::string preview, + std::string referrer, + std::string cache, + bool post, + bool isgz, + int season) +{ + bool wasEmpty = m_data.empty(); + + TiXmlElement thumb("thumb"); + thumb.SetAttribute("spoof", referrer); + thumb.SetAttribute("cache", cache); + if (post) + thumb.SetAttribute("post", "yes"); + if (isgz) + thumb.SetAttribute("gzip", "yes"); + if (season >= 0) + { + thumb.SetAttribute("season", StringUtils::Format("%i", season)); + thumb.SetAttribute("type", "season"); + } + thumb.SetAttribute("aspect", aspect); + thumb.SetAttribute("preview", preview); + TiXmlText text(url); + thumb.InsertEndChild(text); + + m_data << thumb; + + SUrlEntry nUrl(url); + nUrl.m_spoof = referrer; + nUrl.m_post = post; + nUrl.m_isgz = isgz; + nUrl.m_cache = cache; + if (season >= 0) + { + nUrl.m_type = UrlType::Season; + nUrl.m_season = season; + } + nUrl.m_aspect = aspect; + + m_urls.push_back(nUrl); + + if (wasEmpty) + m_parsed = true; +} + +std::string CScraperUrl::GetThumbUrl(const CScraperUrl::SUrlEntry& entry) +{ + if (entry.m_spoof.empty()) + return entry.m_url; + + return entry.m_url + "|Referer=" + CURL::Encode(entry.m_spoof); +} + +bool CScraperUrl::Get(const SUrlEntry& scrURL, + std::string& strHTML, + XFILE::CCurlFile& http, + const std::string& cacheContext) +{ + CURL url(scrURL.m_url); + http.SetReferer(scrURL.m_spoof); + std::string strCachePath; + + if (!scrURL.m_cache.empty()) + { + strCachePath = URIUtils::AddFileToFolder( + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_cachePath, "scrapers", + cacheContext, scrURL.m_cache); + if (XFILE::CFile::Exists(strCachePath)) + { + XFILE::CFile file; + XFILE::auto_buffer buffer; + if (file.LoadFile(strCachePath, buffer) > 0) + { + strHTML.assign(buffer.get(), buffer.length()); + return true; + } + } + } + + auto strHTML1 = strHTML; + + if (scrURL.m_post) + { + std::string strOptions = url.GetOptions(); + strOptions = strOptions.substr(1); + url.SetOptions(""); + + if (!http.Post(url.Get(), strOptions, strHTML1)) + return false; + } + else if (!http.Get(url.Get(), strHTML1)) + return false; + + strHTML = strHTML1; + + const auto mimeType = http.GetProperty(XFILE::FILE_PROPERTY_MIME_TYPE); + CMime::EFileType ftype = CMime::GetFileTypeFromMime(mimeType); + if (ftype == CMime::FileTypeUnknown) + ftype = CMime::GetFileTypeFromContent(strHTML); + + if (ftype == CMime::FileTypeZip || ftype == CMime::FileTypeGZip) + { + XFILE::CZipFile file; + std::string strBuffer; + auto iSize = file.UnpackFromMemory( + strBuffer, strHTML, scrURL.m_isgz); // FIXME: use FileTypeGZip instead of scrURL.m_isgz? + if (iSize > 0) + { + strHTML = strBuffer; + CLog::Log(LOGDEBUG, "{}: Archive \"{}\" was unpacked in memory", __FUNCTION__, scrURL.m_url); + } + else + CLog::Log(LOGWARNING, "{}: \"{}\" looks like archive but cannot be unpacked", __FUNCTION__, + scrURL.m_url); + } + + const auto reportedCharset = http.GetProperty(XFILE::FILE_PROPERTY_CONTENT_CHARSET); + if (ftype == CMime::FileTypeHtml) + { + std::string realHtmlCharset, converted; + if (!CCharsetDetection::ConvertHtmlToUtf8(strHTML, converted, reportedCharset, realHtmlCharset)) + CLog::Log(LOGWARNING, + "{}: Can't find precise charset for HTML \"{}\", using \"{}\" as fallback", + __FUNCTION__, scrURL.m_url, realHtmlCharset); + else + CLog::Log(LOGDEBUG, "{}: Using \"{}\" charset for HTML \"{}\"", __FUNCTION__, realHtmlCharset, + scrURL.m_url); + + strHTML = converted; + } + else if (ftype == CMime::FileTypeXml) + { + CXBMCTinyXML xmlDoc; + xmlDoc.Parse(strHTML, reportedCharset); + + const auto realXmlCharset = xmlDoc.GetUsedCharset(); + if (!realXmlCharset.empty()) + { + CLog::Log(LOGDEBUG, "{}: Using \"{}\" charset for XML \"{}\"", __FUNCTION__, realXmlCharset, + scrURL.m_url); + std::string converted; + g_charsetConverter.ToUtf8(realXmlCharset, strHTML, converted); + strHTML = converted; + } + } + else if (ftype == CMime::FileTypePlainText || + StringUtils::EqualsNoCase(mimeType.substr(0, 5), "text/")) + { + std::string realTextCharset; + std::string converted; + CCharsetDetection::ConvertPlainTextToUtf8(strHTML, converted, reportedCharset, realTextCharset); + strHTML = converted; + if (reportedCharset != realTextCharset) + CLog::Log(LOGWARNING, + "{}: Using \"{}\" charset for plain text \"{}\" instead of server reported \"{}\" " + "charset", + __FUNCTION__, realTextCharset, scrURL.m_url, reportedCharset); + else + CLog::Log(LOGDEBUG, "{}: Using \"{}\" charset for plain text \"{}\"", __FUNCTION__, + realTextCharset, scrURL.m_url); + } + else if (!reportedCharset.empty()) + { + CLog::Log(LOGDEBUG, "{}: Using \"{}\" charset for \"{}\"", __FUNCTION__, reportedCharset, + scrURL.m_url); + if (reportedCharset != "UTF-8") + { + std::string converted; + g_charsetConverter.ToUtf8(reportedCharset, strHTML, converted); + strHTML = converted; + } + } + else + CLog::Log(LOGDEBUG, "{}: Using content of \"{}\" as binary or text with \"UTF-8\" charset", + __FUNCTION__, scrURL.m_url); + + if (!scrURL.m_cache.empty()) + { + const auto strCachePath = URIUtils::AddFileToFolder( + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_cachePath, "scrapers", + cacheContext, scrURL.m_cache); + XFILE::CFile file; + if (!file.OpenForWrite(strCachePath, true) || + file.Write(strHTML.data(), strHTML.size()) != static_cast(strHTML.size())) + return false; + } + return true; +} diff --git a/xbmc/utils/ScraperUrl.h b/xbmc/utils/ScraperUrl.h new file mode 100644 index 0000000..f6c13ba --- /dev/null +++ b/xbmc/utils/ScraperUrl.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include + +class TiXmlElement; +namespace XFILE +{ +class CCurlFile; +} + +class CScraperUrl +{ +public: + enum class UrlType + { + General = 1, + Season = 2 + }; + + struct SUrlEntry + { + explicit SUrlEntry(std::string url = "") + : m_url(std::move(url)), m_type(UrlType::General), m_post(false), m_isgz(false), m_season(-1) + { + } + + std::string m_spoof; + std::string m_url; + std::string m_cache; + std::string m_aspect; + UrlType m_type; + bool m_post; + bool m_isgz; + int m_season; + }; + + CScraperUrl(); + explicit CScraperUrl(std::string strUrl); + explicit CScraperUrl(const TiXmlElement* element); + ~CScraperUrl(); + + void Clear(); + + bool HasData() const { return !m_data.empty(); } + const std::string& GetData() const { return m_data; } + void SetData(std::string data); + + const std::string& GetTitle() const { return m_title; } + void SetTitle(std::string title) { m_title = std::move(title); } + + const std::string& GetId() const { return m_id; } + void SetId(std::string id) { m_id = std::move(id); } + + double GetRelevance() const { return m_relevance; } + void SetRelevance(double relevance) { m_relevance = relevance; } + + bool HasUrls() const { return !m_urls.empty(); } + const std::vector& GetUrls() const { return m_urls; } + void SetUrls(std::vector urls) { m_urls = std::move(urls); } + void AppendUrl(SUrlEntry url) { m_urls.push_back(std::move(url)); } + + const SUrlEntry GetFirstUrlByType(const std::string& type = "") const; + const SUrlEntry GetSeasonUrl(int season, const std::string& type = "") const; + unsigned int GetMaxSeasonUrl() const; + + std::string GetFirstThumbUrl() const; + + /*! \brief fetch the full URLs (including referrer) of thumbs + \param thumbs [out] vector of thumb URLs to fill + \param type the type of thumb URLs to fetch, if empty (the default) picks any + \param season number of season that we want thumbs for, -1 indicates no season (the default) + \param unique avoid adding duplicate URLs when adding to a thumbs vector with existing items + */ + void GetThumbUrls(std::vector& thumbs, + const std::string& type = "", + int season = -1, + bool unique = false) const; + + bool Parse(); + bool ParseFromData(std::string data); // copies by intention + bool ParseAndAppendUrl(const TiXmlElement* element); + bool ParseAndAppendUrlsFromEpisodeGuide(std::string episodeGuide); // copies by intention + void AddParsedUrl(std::string url, + std::string aspect = "", + std::string preview = "", + std::string referrer = "", + std::string cache = "", + bool post = false, + bool isgz = false, + int season = -1); + + /*! \brief fetch the full URL (including referrer) of a thumb + \param URL entry to use to create the full URL + \return the full URL, including referrer + */ + static std::string GetThumbUrl(const CScraperUrl::SUrlEntry& entry); + + static bool Get(const SUrlEntry& scrURL, + std::string& strHTML, + XFILE::CCurlFile& http, + const std::string& cacheContext); + + // ATTENTION: this member MUST NOT be used directly except from databases + std::string m_data; + +private: + std::string m_title; + std::string m_id; + double m_relevance; + std::vector m_urls; + bool m_parsed; +}; diff --git a/xbmc/utils/Screenshot.cpp b/xbmc/utils/Screenshot.cpp new file mode 100644 index 0000000..638ea64 --- /dev/null +++ b/xbmc/utils/Screenshot.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Screenshot.h" + +#include "ServiceBroker.h" +#include "URL.h" +#include "Util.h" +#include "filesystem/File.h" +#include "guilib/LocalizeStrings.h" +#include "pictures/Picture.h" +#include "settings/SettingPath.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "settings/windows/GUIControlSettings.h" +#include "utils/JobManager.h" +#include "utils/URIUtils.h" +#include "utils/log.h" + +using namespace XFILE; + +std::vector()>> CScreenShot::m_screenShotSurfaces; + +void CScreenShot::Register(std::function()> createFunc) +{ + m_screenShotSurfaces.emplace_back(createFunc); +} + +void CScreenShot::TakeScreenshot(const std::string& filename, bool sync) +{ + auto surface = m_screenShotSurfaces.back()(); + + if (!surface) + { + CLog::Log(LOGERROR, "failed to create screenshot surface"); + return; + } + + if (!surface->Capture()) + { + CLog::Log(LOGERROR, "Screenshot %s failed", CURL::GetRedacted(filename).c_str()); + return; + } + + surface->CaptureVideo(true); + + CLog::Log(LOGDEBUG, "Saving screenshot %s", CURL::GetRedacted(filename).c_str()); + + //set alpha byte to 0xFF + for (int y = 0; y < surface->GetHeight(); y++) + { + unsigned char* alphaptr = surface->GetBuffer() - 1 + y * surface->GetStride(); + for (int x = 0; x < surface->GetWidth(); x++) + *(alphaptr += 4) = 0xFF; + } + + //if sync is true, the png file needs to be completely written when this function returns + if (sync) + { + if (!CPicture::CreateThumbnailFromSurface(surface->GetBuffer(), surface->GetWidth(), surface->GetHeight(), surface->GetStride(), filename)) + CLog::Log(LOGERROR, "Unable to write screenshot %s", CURL::GetRedacted(filename).c_str()); + + surface->ReleaseBuffer(); + } + else + { + //make sure the file exists to avoid concurrency issues + XFILE::CFile file; + if (file.OpenForWrite(filename)) + file.Close(); + else + CLog::Log(LOGERROR, "Unable to create file %s", CURL::GetRedacted(filename).c_str()); + + //write .png file asynchronous with CThumbnailWriter, prevents stalling of the render thread + //buffer is deleted from CThumbnailWriter + CThumbnailWriter* thumbnailwriter = new CThumbnailWriter(surface->GetBuffer(), surface->GetWidth(), surface->GetHeight(), surface->GetStride(), filename); + CJobManager::GetInstance().AddJob(thumbnailwriter, NULL); + } +} + +void CScreenShot::TakeScreenshot() +{ + std::shared_ptr screenshotSetting = std::static_pointer_cast(CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(CSettings::SETTING_DEBUG_SCREENSHOTPATH)); + if (!screenshotSetting) + return; + + std::string strDir = screenshotSetting->GetValue(); + if (strDir.empty()) + { + if (!CGUIControlButtonSetting::GetPath(screenshotSetting, &g_localizeStrings)) + return; + + strDir = screenshotSetting->GetValue(); + } + + URIUtils::RemoveSlashAtEnd(strDir); + + if (!strDir.empty()) + { + std::string file = CUtil::GetNextFilename(URIUtils::AddFileToFolder(strDir, "screenshot%03d.png"), 999); + + if (!file.empty()) + { + TakeScreenshot(file, false); + } + else + { + CLog::Log(LOGWARNING, "Too many screen shots or invalid folder"); + } + } +} diff --git a/xbmc/utils/Screenshot.h b/xbmc/utils/Screenshot.h new file mode 100644 index 0000000..8642ca3 --- /dev/null +++ b/xbmc/utils/Screenshot.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "IScreenshotSurface.h" + +#include +#include +#include +#include + +class CScreenShot +{ +public: + static void Register(std::function()> createFunc); + + static void TakeScreenshot(); + static void TakeScreenshot(const std::string &filename, bool sync); + +private: + static std::vector()>> m_screenShotSurfaces; +}; diff --git a/xbmc/utils/SortUtils.cpp b/xbmc/utils/SortUtils.cpp new file mode 100644 index 0000000..840e69e --- /dev/null +++ b/xbmc/utils/SortUtils.cpp @@ -0,0 +1,1324 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "SortUtils.h" + +#include "LangInfo.h" +#include "URL.h" +#include "Util.h" +#include "utils/CharsetConverter.h" +#include "utils/StringUtils.h" +#include "utils/Variant.h" + +#include +#include + +std::string ArrayToString(SortAttribute attributes, const CVariant &variant, const std::string &separator = " / ") +{ + std::vector strArray; + if (variant.isArray()) + { + for (CVariant::const_iterator_array it = variant.begin_array(); it != variant.end_array(); it++) + { + if (attributes & SortAttributeIgnoreArticle) + strArray.push_back(SortUtils::RemoveArticles(it->asString())); + else + strArray.push_back(it->asString()); + } + + return StringUtils::Join(strArray, separator); + } + else if (variant.isString()) + { + if (attributes & SortAttributeIgnoreArticle) + return SortUtils::RemoveArticles(variant.asString()); + else + return variant.asString(); + } + + return ""; +} + +std::string ByLabel(SortAttribute attributes, const SortItem &values) +{ + if (attributes & SortAttributeIgnoreArticle) + return SortUtils::RemoveArticles(values.at(FieldLabel).asString()); + + return values.at(FieldLabel).asString(); +} + +std::string ByFile(SortAttribute attributes, const SortItem &values) +{ + CURL url(values.at(FieldPath).asString()); + + return StringUtils::Format("%s %" PRId64, url.GetFileNameWithoutPath().c_str(), values.at(FieldStartOffset).asInteger()); +} + +std::string ByPath(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%s %" PRId64, values.at(FieldPath).asString().c_str(), values.at(FieldStartOffset).asInteger()); +} + +std::string ByLastPlayed(SortAttribute attributes, const SortItem &values) +{ + if (attributes & SortAttributeIgnoreLabel) + return values.at(FieldLastPlayed).asString(); + + return StringUtils::Format("%s %s", values.at(FieldLastPlayed).asString().c_str(), ByLabel(attributes, values).c_str()); +} + +std::string ByPlaycount(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%i %s", (int)values.at(FieldPlaycount).asInteger(), ByLabel(attributes, values).c_str()); +} + +std::string ByDate(SortAttribute attributes, const SortItem &values) +{ + return values.at(FieldDate).asString() + " " + ByLabel(attributes, values); +} + +std::string ByDateAdded(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%s %d", values.at(FieldDateAdded).asString().c_str(), (int)values.at(FieldId).asInteger()); +} + +std::string BySize(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%" PRId64, values.at(FieldSize).asInteger()); +} + +std::string ByDriveType(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%d %s", (int)values.at(FieldDriveType).asInteger(), ByLabel(attributes, values).c_str()); +} + +std::string ByTitle(SortAttribute attributes, const SortItem &values) +{ + if (attributes & SortAttributeIgnoreArticle) + return SortUtils::RemoveArticles(values.at(FieldTitle).asString()); + + return values.at(FieldTitle).asString(); +} + +std::string ByAlbum(SortAttribute attributes, const SortItem &values) +{ + std::string album = values.at(FieldAlbum).asString(); + if (attributes & SortAttributeIgnoreArticle) + album = SortUtils::RemoveArticles(album); + + std::string label = StringUtils::Format("%s %s", album.c_str(), ArrayToString(attributes, values.at(FieldArtist)).c_str()); + + const CVariant &track = values.at(FieldTrackNumber); + if (!track.isNull()) + label += StringUtils::Format(" %i", (int)track.asInteger()); + + return label; +} + +std::string ByAlbumType(SortAttribute attributes, const SortItem &values) +{ + return values.at(FieldAlbumType).asString() + " " + ByLabel(attributes, values); +} + +std::string ByArtist(SortAttribute attributes, const SortItem &values) +{ + std::string label; + if (attributes & SortAttributeUseArtistSortName) + { + const CVariant &artistsort = values.at(FieldArtistSort); + if (!artistsort.isNull()) + label = artistsort.asString(); + } + if (label.empty()) + label = ArrayToString(attributes, values.at(FieldArtist)); + + const CVariant &album = values.at(FieldAlbum); + if (!album.isNull()) + label += " " + SortUtils::RemoveArticles(album.asString()); + + const CVariant &track = values.at(FieldTrackNumber); + if (!track.isNull()) + label += StringUtils::Format(" %i", (int)track.asInteger()); + + return label; +} + +std::string ByArtistThenYear(SortAttribute attributes, const SortItem &values) +{ + std::string label; + if (attributes & SortAttributeUseArtistSortName) + { + const CVariant &artistsort = values.at(FieldArtistSort); + if (!artistsort.isNull()) + label = artistsort.asString(); + } + if (label.empty()) + label = ArrayToString(attributes, values.at(FieldArtist)); + + const CVariant &year = values.at(FieldYear); + if (!year.isNull()) + label += StringUtils::Format(" %i", static_cast(year.asInteger())); + + const CVariant &album = values.at(FieldAlbum); + if (!album.isNull()) + label += " " + SortUtils::RemoveArticles(album.asString()); + + const CVariant &track = values.at(FieldTrackNumber); + if (!track.isNull()) + label += StringUtils::Format(" %i", (int)track.asInteger()); + + return label; +} + +std::string ByTrackNumber(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%i", (int)values.at(FieldTrackNumber).asInteger()); +} + +std::string ByTotalDiscs(SortAttribute attributes, const SortItem& values) +{ + return StringUtils::Format("%d %s", static_cast(values.at(FieldTotalDiscs).asInteger()), + ByLabel(attributes, values)); +} +std::string ByTime(SortAttribute attributes, const SortItem &values) +{ + std::string label; + const CVariant &time = values.at(FieldTime); + if (time.isInteger()) + label = StringUtils::Format("%i", (int)time.asInteger()); + else + label = StringUtils::Format("%s", time.asString().c_str()); + return label; +} + +std::string ByProgramCount(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%i", (int)values.at(FieldProgramCount).asInteger()); +} + +std::string ByPlaylistOrder(SortAttribute attributes, const SortItem &values) +{ + //! @todo Playlist order is hacked into program count variable (not nice, but ok until 2.0) + return ByProgramCount(attributes, values); +} + +std::string ByGenre(SortAttribute attributes, const SortItem &values) +{ + return ArrayToString(attributes, values.at(FieldGenre)); +} + +std::string ByCountry(SortAttribute attributes, const SortItem &values) +{ + return ArrayToString(attributes, values.at(FieldCountry)); +} + +std::string ByYear(SortAttribute attributes, const SortItem &values) +{ + std::string label; + const CVariant &airDate = values.at(FieldAirDate); + if (!airDate.isNull() && !airDate.asString().empty()) + label = airDate.asString() + " "; + + label += StringUtils::Format("%i", (int)values.at(FieldYear).asInteger()); + + const CVariant &album = values.at(FieldAlbum); + if (!album.isNull()) + label += " " + SortUtils::RemoveArticles(album.asString()); + + const CVariant &track = values.at(FieldTrackNumber); + if (!track.isNull()) + label += StringUtils::Format(" %i", (int)track.asInteger()); + + label += " " + ByLabel(attributes, values); + + return label; +} + +std::string ByOrigDate(SortAttribute attributes, const SortItem& values) +{ + std::string label; + label = values.at(FieldOrigDate).asString(); + + const CVariant &album = values.at(FieldAlbum); + if (!album.isNull()) + label += " " + SortUtils::RemoveArticles(album.asString()); + + const CVariant &track = values.at(FieldTrackNumber); + if (!track.isNull()) + label += StringUtils::Format(" %i", static_cast(track.asInteger())); + + label += " " + ByLabel(attributes, values); + + return label; +} + +std::string BySortTitle(SortAttribute attributes, const SortItem &values) +{ + std::string title = values.at(FieldSortTitle).asString(); + if (title.empty()) + title = values.at(FieldTitle).asString(); + + if (attributes & SortAttributeIgnoreArticle) + title = SortUtils::RemoveArticles(title); + + return title; +} + +std::string ByRating(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%f %s", values.at(FieldRating).asFloat(), ByLabel(attributes, values).c_str()); +} + +std::string ByUserRating(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%d %s", static_cast(values.at(FieldUserRating).asInteger()), ByLabel(attributes, values).c_str()); +} + +std::string ByVotes(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%d %s", (int)values.at(FieldVotes).asInteger(), ByLabel(attributes, values).c_str()); +} + +std::string ByTop250(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%d %s", (int)values.at(FieldTop250).asInteger(), ByLabel(attributes, values).c_str()); +} + +std::string ByMPAA(SortAttribute attributes, const SortItem &values) +{ + return values.at(FieldMPAA).asString() + " " + ByLabel(attributes, values); +} + +std::string ByStudio(SortAttribute attributes, const SortItem &values) +{ + return ArrayToString(attributes, values.at(FieldStudio)); +} + +std::string ByEpisodeNumber(SortAttribute attributes, const SortItem &values) +{ + // we calculate an offset number based on the episode's + // sort season and episode values. in addition + // we include specials 'episode' numbers to get proper + // sorting of multiple specials in a row. each + // of these are given their particular ranges to semi-ensure uniqueness. + // theoretical problem: if a show has > 2^15 specials and two of these are placed + // after each other they will sort backwards. if a show has > 2^32-1 seasons + // or if a season has > 2^16-1 episodes strange things will happen (overflow) + uint64_t num; + const CVariant &episodeSpecial = values.at(FieldEpisodeNumberSpecialSort); + const CVariant &seasonSpecial = values.at(FieldSeasonSpecialSort); + if (!episodeSpecial.isNull() && !seasonSpecial.isNull() && + (episodeSpecial.asInteger() > 0 || seasonSpecial.asInteger() > 0)) + num = ((uint64_t)seasonSpecial.asInteger() << 32) + (episodeSpecial.asInteger() << 16) - ((2 << 15) - values.at(FieldEpisodeNumber).asInteger()); + else + num = ((uint64_t)values.at(FieldSeason).asInteger() << 32) + (values.at(FieldEpisodeNumber).asInteger() << 16); + + std::string title; + if (values.find(FieldMediaType) != values.end() && values.at(FieldMediaType).asString() == MediaTypeMovie) + title = BySortTitle(attributes, values); + if (title.empty()) + title = ByLabel(attributes, values); + + return StringUtils::Format("%" PRIu64" %s", num, title.c_str()); +} + +std::string BySeason(SortAttribute attributes, const SortItem &values) +{ + int season = (int)values.at(FieldSeason).asInteger(); + const CVariant &specialSeason = values.at(FieldSeasonSpecialSort); + if (!specialSeason.isNull()) + season = (int)specialSeason.asInteger(); + + return StringUtils::Format("%i %s", season, ByLabel(attributes, values).c_str()); +} + +std::string ByNumberOfEpisodes(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%i %s", (int)values.at(FieldNumberOfEpisodes).asInteger(), ByLabel(attributes, values).c_str()); +} + +std::string ByNumberOfWatchedEpisodes(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%i %s", (int)values.at(FieldNumberOfWatchedEpisodes).asInteger(), ByLabel(attributes, values).c_str()); +} + +std::string ByTvShowStatus(SortAttribute attributes, const SortItem &values) +{ + return values.at(FieldTvShowStatus).asString() + " " + ByLabel(attributes, values); +} + +std::string ByTvShowTitle(SortAttribute attributes, const SortItem &values) +{ + return values.at(FieldTvShowTitle).asString() + " " + ByLabel(attributes, values); +} + +std::string ByProductionCode(SortAttribute attributes, const SortItem &values) +{ + return values.at(FieldProductionCode).asString(); +} + +std::string ByVideoResolution(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%i %s", (int)values.at(FieldVideoResolution).asInteger(), ByLabel(attributes, values).c_str()); +} + +std::string ByVideoCodec(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%s %s", values.at(FieldVideoCodec).asString().c_str(), ByLabel(attributes, values).c_str()); +} + +std::string ByVideoAspectRatio(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%.3f %s", values.at(FieldVideoAspectRatio).asFloat(), ByLabel(attributes, values).c_str()); +} + +std::string ByAudioChannels(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%i %s", (int)values.at(FieldAudioChannels).asInteger(), ByLabel(attributes, values).c_str()); +} + +std::string ByAudioCodec(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%s %s", values.at(FieldAudioCodec).asString().c_str(), ByLabel(attributes, values).c_str()); +} + +std::string ByAudioLanguage(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%s %s", values.at(FieldAudioLanguage).asString().c_str(), ByLabel(attributes, values).c_str()); +} + +std::string BySubtitleLanguage(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%s %s", values.at(FieldSubtitleLanguage).asString().c_str(), ByLabel(attributes, values).c_str()); +} + +std::string ByBitrate(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%" PRId64, values.at(FieldBitrate).asInteger()); +} + +std::string ByListeners(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%" PRId64, values.at(FieldListeners).asInteger()); +} + +std::string ByRandom(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%i", CUtil::GetRandomNumber()); +} + +std::string ByChannel(SortAttribute attributes, const SortItem &values) +{ + return values.at(FieldChannelName).asString(); +} + +std::string ByChannelNumber(SortAttribute attributes, const SortItem &values) +{ + return values.at(FieldChannelNumber).asString(); +} + +std::string ByClientChannelOrder(SortAttribute attributes, const SortItem& values) +{ + return values.at(FieldClientChannelOrder).asString(); +} + +std::string ByDateTaken(SortAttribute attributes, const SortItem &values) +{ + return values.at(FieldDateTaken).asString(); +} + +std::string ByRelevance(SortAttribute attributes, const SortItem &values) +{ + return StringUtils::Format("%i", (int)values.at(FieldRelevance).asInteger()); +} + +std::string ByInstallDate(SortAttribute attributes, const SortItem &values) +{ + return values.at(FieldInstallDate).asString(); +} + +std::string ByLastUpdated(SortAttribute attributes, const SortItem &values) +{ + return values.at(FieldLastUpdated).asString(); +} + +std::string ByLastUsed(SortAttribute attributes, const SortItem &values) +{ + return values.at(FieldLastUsed).asString(); +} + +std::string ByBPM(SortAttribute attributes, const SortItem& values) +{ + return StringUtils::Format("%d %s", static_cast(values.at(FieldBPM).asInteger()), + ByLabel(attributes, values)); +} + +bool preliminarySort(const SortItem &left, const SortItem &right, bool handleFolder, bool &result, std::wstring &labelLeft, std::wstring &labelRight) +{ + // make sure both items have the necessary data to do the sorting + SortItem::const_iterator itLeftSort, itRightSort; + if ((itLeftSort = left.find(FieldSort)) == left.end()) + { + result = false; + return true; + } + if ((itRightSort = right.find(FieldSort)) == right.end()) + { + result = true; + return true; + } + + // look at special sorting behaviour + SortItem::const_iterator itLeft, itRight; + SortSpecial leftSortSpecial = SortSpecialNone; + SortSpecial rightSortSpecial = SortSpecialNone; + if ((itLeft = left.find(FieldSortSpecial)) != left.end() && itLeft->second.asInteger() <= (int64_t)SortSpecialOnBottom) + leftSortSpecial = (SortSpecial)itLeft->second.asInteger(); + if ((itRight = right.find(FieldSortSpecial)) != right.end() && itRight->second.asInteger() <= (int64_t)SortSpecialOnBottom) + rightSortSpecial = (SortSpecial)itRight->second.asInteger(); + + // one has a special sort + if (leftSortSpecial != rightSortSpecial) + { + // left should be sorted on top + // or right should be sorted on bottom + // => left is sorted above right + if (leftSortSpecial == SortSpecialOnTop || + rightSortSpecial == SortSpecialOnBottom) + { + result = true; + return true; + } + + // otherwise right is sorted above left + result = false; + return true; + } + // both have either sort on top or sort on bottom -> leave as-is + else if (leftSortSpecial != SortSpecialNone && leftSortSpecial == rightSortSpecial) + { + result = false; + return true; + } + + if (handleFolder) + { + itLeft = left.find(FieldFolder); + itRight = right.find(FieldFolder); + if (itLeft != left.end() && itRight != right.end() && + itLeft->second.asBoolean() != itRight->second.asBoolean()) + { + result = itLeft->second.asBoolean(); + return true; + } + } + + labelLeft = itLeftSort->second.asWideString(); + labelRight = itRightSort->second.asWideString(); + + return false; +} + +bool SorterAscending(const SortItem &left, const SortItem &right) +{ + bool result; + std::wstring labelLeft, labelRight; + if (preliminarySort(left, right, true, result, labelLeft, labelRight)) + return result; + + return StringUtils::AlphaNumericCompare(labelLeft.c_str(), labelRight.c_str()) < 0; +} + +bool SorterDescending(const SortItem &left, const SortItem &right) +{ + bool result; + std::wstring labelLeft, labelRight; + if (preliminarySort(left, right, true, result, labelLeft, labelRight)) + return result; + + return StringUtils::AlphaNumericCompare(labelLeft.c_str(), labelRight.c_str()) > 0; +} + +bool SorterIgnoreFoldersAscending(const SortItem &left, const SortItem &right) +{ + bool result; + std::wstring labelLeft, labelRight; + if (preliminarySort(left, right, false, result, labelLeft, labelRight)) + return result; + + return StringUtils::AlphaNumericCompare(labelLeft.c_str(), labelRight.c_str()) < 0; +} + +bool SorterIgnoreFoldersDescending(const SortItem &left, const SortItem &right) +{ + bool result; + std::wstring labelLeft, labelRight; + if (preliminarySort(left, right, false, result, labelLeft, labelRight)) + return result; + + return StringUtils::AlphaNumericCompare(labelLeft.c_str(), labelRight.c_str()) > 0; +} + +bool SorterIndirectAscending(const SortItemPtr &left, const SortItemPtr &right) +{ + return SorterAscending(*left, *right); +} + +bool SorterIndirectDescending(const SortItemPtr &left, const SortItemPtr &right) +{ + return SorterDescending(*left, *right); +} + +bool SorterIndirectIgnoreFoldersAscending(const SortItemPtr &left, const SortItemPtr &right) +{ + return SorterIgnoreFoldersAscending(*left, *right); +} + +bool SorterIndirectIgnoreFoldersDescending(const SortItemPtr &left, const SortItemPtr &right) +{ + return SorterIgnoreFoldersDescending(*left, *right); +} + +// clang-format off +std::map fillPreparators() +{ + std::map preparators; + + preparators[SortByNone] = NULL; + preparators[SortByLabel] = ByLabel; + preparators[SortByDate] = ByDate; + preparators[SortBySize] = BySize; + preparators[SortByFile] = ByFile; + preparators[SortByPath] = ByPath; + preparators[SortByDriveType] = ByDriveType; + preparators[SortByTitle] = ByTitle; + preparators[SortByTrackNumber] = ByTrackNumber; + preparators[SortByTime] = ByTime; + preparators[SortByArtist] = ByArtist; + preparators[SortByArtistThenYear] = ByArtistThenYear; + preparators[SortByAlbum] = ByAlbum; + preparators[SortByAlbumType] = ByAlbumType; + preparators[SortByGenre] = ByGenre; + preparators[SortByCountry] = ByCountry; + preparators[SortByYear] = ByYear; + preparators[SortByRating] = ByRating; + preparators[SortByUserRating] = ByUserRating; + preparators[SortByVotes] = ByVotes; + preparators[SortByTop250] = ByTop250; + preparators[SortByProgramCount] = ByProgramCount; + preparators[SortByPlaylistOrder] = ByPlaylistOrder; + preparators[SortByEpisodeNumber] = ByEpisodeNumber; + preparators[SortBySeason] = BySeason; + preparators[SortByNumberOfEpisodes] = ByNumberOfEpisodes; + preparators[SortByNumberOfWatchedEpisodes] = ByNumberOfWatchedEpisodes; + preparators[SortByTvShowStatus] = ByTvShowStatus; + preparators[SortByTvShowTitle] = ByTvShowTitle; + preparators[SortBySortTitle] = BySortTitle; + preparators[SortByProductionCode] = ByProductionCode; + preparators[SortByMPAA] = ByMPAA; + preparators[SortByVideoResolution] = ByVideoResolution; + preparators[SortByVideoCodec] = ByVideoCodec; + preparators[SortByVideoAspectRatio] = ByVideoAspectRatio; + preparators[SortByAudioChannels] = ByAudioChannels; + preparators[SortByAudioCodec] = ByAudioCodec; + preparators[SortByAudioLanguage] = ByAudioLanguage; + preparators[SortBySubtitleLanguage] = BySubtitleLanguage; + preparators[SortByStudio] = ByStudio; + preparators[SortByDateAdded] = ByDateAdded; + preparators[SortByLastPlayed] = ByLastPlayed; + preparators[SortByPlaycount] = ByPlaycount; + preparators[SortByListeners] = ByListeners; + preparators[SortByBitrate] = ByBitrate; + preparators[SortByRandom] = ByRandom; + preparators[SortByChannel] = ByChannel; + preparators[SortByChannelNumber] = ByChannelNumber; + preparators[SortByClientChannelOrder] = ByClientChannelOrder; + preparators[SortByDateTaken] = ByDateTaken; + preparators[SortByRelevance] = ByRelevance; + preparators[SortByInstallDate] = ByInstallDate; + preparators[SortByLastUpdated] = ByLastUpdated; + preparators[SortByLastUsed] = ByLastUsed; + preparators[SortByTotalDiscs] = ByTotalDiscs; + preparators[SortByOrigDate] = ByOrigDate; + preparators[SortByBPM] = ByBPM; + + return preparators; +} +// clang-format on + +std::map fillSortingFields() +{ + std::map sortingFields; + + sortingFields.insert(std::pair(SortByNone, Fields())); + + sortingFields[SortByLabel].insert(FieldLabel); + sortingFields[SortByDate].insert(FieldDate); + sortingFields[SortBySize].insert(FieldSize); + sortingFields[SortByFile].insert(FieldPath); + sortingFields[SortByFile].insert(FieldStartOffset); + sortingFields[SortByPath].insert(FieldPath); + sortingFields[SortByPath].insert(FieldStartOffset); + sortingFields[SortByDriveType].insert(FieldDriveType); + sortingFields[SortByTitle].insert(FieldTitle); + sortingFields[SortByTrackNumber].insert(FieldTrackNumber); + sortingFields[SortByTime].insert(FieldTime); + sortingFields[SortByArtist].insert(FieldArtist); + sortingFields[SortByArtist].insert(FieldArtistSort); + sortingFields[SortByArtist].insert(FieldYear); + sortingFields[SortByArtist].insert(FieldAlbum); + sortingFields[SortByArtist].insert(FieldTrackNumber); + sortingFields[SortByArtistThenYear].insert(FieldArtist); + sortingFields[SortByArtistThenYear].insert(FieldArtistSort); + sortingFields[SortByArtistThenYear].insert(FieldYear); + sortingFields[SortByArtistThenYear].insert(FieldOrigDate); + sortingFields[SortByArtistThenYear].insert(FieldAlbum); + sortingFields[SortByArtistThenYear].insert(FieldTrackNumber); + sortingFields[SortByAlbum].insert(FieldAlbum); + sortingFields[SortByAlbum].insert(FieldArtist); + sortingFields[SortByAlbum].insert(FieldArtistSort); + sortingFields[SortByAlbum].insert(FieldTrackNumber); + sortingFields[SortByAlbumType].insert(FieldAlbumType); + sortingFields[SortByGenre].insert(FieldGenre); + sortingFields[SortByCountry].insert(FieldCountry); + sortingFields[SortByYear].insert(FieldYear); + sortingFields[SortByYear].insert(FieldAirDate); + sortingFields[SortByYear].insert(FieldAlbum); + sortingFields[SortByYear].insert(FieldTrackNumber); + sortingFields[SortByYear].insert(FieldOrigDate); + sortingFields[SortByRating].insert(FieldRating); + sortingFields[SortByUserRating].insert(FieldUserRating); + sortingFields[SortByVotes].insert(FieldVotes); + sortingFields[SortByTop250].insert(FieldTop250); + sortingFields[SortByProgramCount].insert(FieldProgramCount); + sortingFields[SortByPlaylistOrder].insert(FieldProgramCount); + sortingFields[SortByEpisodeNumber].insert(FieldEpisodeNumber); + sortingFields[SortByEpisodeNumber].insert(FieldSeason); + sortingFields[SortByEpisodeNumber].insert(FieldEpisodeNumberSpecialSort); + sortingFields[SortByEpisodeNumber].insert(FieldSeasonSpecialSort); + sortingFields[SortByEpisodeNumber].insert(FieldTitle); + sortingFields[SortByEpisodeNumber].insert(FieldSortTitle); + sortingFields[SortBySeason].insert(FieldSeason); + sortingFields[SortBySeason].insert(FieldSeasonSpecialSort); + sortingFields[SortByNumberOfEpisodes].insert(FieldNumberOfEpisodes); + sortingFields[SortByNumberOfWatchedEpisodes].insert(FieldNumberOfWatchedEpisodes); + sortingFields[SortByTvShowStatus].insert(FieldTvShowStatus); + sortingFields[SortByTvShowTitle].insert(FieldTvShowTitle); + sortingFields[SortBySortTitle].insert(FieldSortTitle); + sortingFields[SortBySortTitle].insert(FieldTitle); + sortingFields[SortByProductionCode].insert(FieldProductionCode); + sortingFields[SortByMPAA].insert(FieldMPAA); + sortingFields[SortByVideoResolution].insert(FieldVideoResolution); + sortingFields[SortByVideoCodec].insert(FieldVideoCodec); + sortingFields[SortByVideoAspectRatio].insert(FieldVideoAspectRatio); + sortingFields[SortByAudioChannels].insert(FieldAudioChannels); + sortingFields[SortByAudioCodec].insert(FieldAudioCodec); + sortingFields[SortByAudioLanguage].insert(FieldAudioLanguage); + sortingFields[SortBySubtitleLanguage].insert(FieldSubtitleLanguage); + sortingFields[SortByStudio].insert(FieldStudio); + sortingFields[SortByDateAdded].insert(FieldDateAdded); + sortingFields[SortByDateAdded].insert(FieldId); + sortingFields[SortByLastPlayed].insert(FieldLastPlayed); + sortingFields[SortByPlaycount].insert(FieldPlaycount); + sortingFields[SortByListeners].insert(FieldListeners); + sortingFields[SortByBitrate].insert(FieldBitrate); + sortingFields[SortByChannel].insert(FieldChannelName); + sortingFields[SortByChannelNumber].insert(FieldChannelNumber); + sortingFields[SortByClientChannelOrder].insert(FieldClientChannelOrder); + sortingFields[SortByDateTaken].insert(FieldDateTaken); + sortingFields[SortByRelevance].insert(FieldRelevance); + sortingFields[SortByInstallDate].insert(FieldInstallDate); + sortingFields[SortByLastUpdated].insert(FieldLastUpdated); + sortingFields[SortByLastUsed].insert(FieldLastUsed); + sortingFields[SortByTotalDiscs].insert(FieldTotalDiscs); + sortingFields[SortByOrigDate].insert(FieldOrigDate); + sortingFields[SortByOrigDate].insert(FieldAlbum); + sortingFields[SortByOrigDate].insert(FieldTrackNumber); + sortingFields[SortByBPM].insert(FieldBPM); + sortingFields.insert(std::pair(SortByRandom, Fields())); + + return sortingFields; +} + +std::map SortUtils::m_preparators = fillPreparators(); +std::map SortUtils::m_sortingFields = fillSortingFields(); + +void SortUtils::GetFieldsForSQLSort(const MediaType& mediaType, + SortBy sortMethod, + FieldList& fields) +{ + fields.clear(); + if (mediaType == MediaTypeNone) + return; + + if (mediaType == MediaTypeAlbum) + { + if (sortMethod == SortByLabel || sortMethod == SortByAlbum || sortMethod == SortByTitle) + { + fields.emplace_back(FieldAlbum); + fields.emplace_back(FieldArtist); + } + else if (sortMethod == SortByAlbumType) + { + fields.emplace_back(FieldAlbumType); + fields.emplace_back(FieldAlbum); + fields.emplace_back(FieldArtist); + } + else if (sortMethod == SortByArtist) + { + fields.emplace_back(FieldArtist); + fields.emplace_back(FieldAlbum); + } + else if (sortMethod == SortByArtistThenYear) + { + fields.emplace_back(FieldArtist); + fields.emplace_back(FieldYear); + fields.emplace_back(FieldAlbum); + } + else if (sortMethod == SortByYear) + { + fields.emplace_back(FieldYear); + fields.emplace_back(FieldAlbum); + } + else if (sortMethod == SortByGenre) + { + fields.emplace_back(FieldGenre); + fields.emplace_back(FieldAlbum); + } + else if (sortMethod == SortByDateAdded) + fields.emplace_back(FieldDateAdded); + else if (sortMethod == SortByPlaycount) + { + fields.emplace_back(FieldPlaycount); + fields.emplace_back(FieldAlbum); + } + else if (sortMethod == SortByLastPlayed) + { + fields.emplace_back(FieldLastPlayed); + fields.emplace_back(FieldAlbum); + } + else if (sortMethod == SortByRating) + { + fields.emplace_back(FieldRating); + fields.emplace_back(FieldAlbum); + } + else if (sortMethod == SortByVotes) + { + fields.emplace_back(FieldVotes); + fields.emplace_back(FieldAlbum); + } + else if (sortMethod == SortByUserRating) + { + fields.emplace_back(FieldUserRating); + fields.emplace_back(FieldAlbum); + } + else if (sortMethod == SortByTotalDiscs) + { + fields.emplace_back(FieldTotalDiscs); + fields.emplace_back(FieldAlbum); + } + else if (sortMethod == SortByOrigDate) + { + fields.emplace_back(FieldOrigDate); + fields.emplace_back(FieldAlbum); + } + } + else if (mediaType == MediaTypeSong) + { + if (sortMethod == SortByLabel || sortMethod == SortByTrackNumber) + fields.emplace_back(FieldTrackNumber); + else if (sortMethod == SortByTitle) + fields.emplace_back(FieldTitle); + else if (sortMethod == SortByAlbum) + { + fields.emplace_back(FieldAlbum); + fields.emplace_back(FieldAlbumArtist); + fields.emplace_back(FieldTrackNumber); + } + else if (sortMethod == SortByArtist) + { + fields.emplace_back(FieldArtist); + fields.emplace_back(FieldAlbum); + fields.emplace_back(FieldTrackNumber); + } + else if (sortMethod == SortByArtistThenYear) + { + fields.emplace_back(FieldArtist); + fields.emplace_back(FieldYear); + fields.emplace_back(FieldAlbum); + fields.emplace_back(FieldTrackNumber); + } + else if (sortMethod == SortByYear) + { + fields.emplace_back(FieldYear); + fields.emplace_back(FieldAlbum); + fields.emplace_back(FieldTrackNumber); + } + else if (sortMethod == SortByGenre) + { + fields.emplace_back(FieldGenre); + fields.emplace_back(FieldAlbum); + } + else if (sortMethod == SortByDateAdded) + fields.emplace_back(FieldDateAdded); + else if (sortMethod == SortByPlaycount) + { + fields.emplace_back(FieldPlaycount); + fields.emplace_back(FieldTrackNumber); + } + else if (sortMethod == SortByLastPlayed) + { + fields.emplace_back(FieldLastPlayed); + fields.emplace_back(FieldTrackNumber); + } + else if (sortMethod == SortByRating) + { + fields.emplace_back(FieldRating); + fields.emplace_back(FieldTrackNumber); + } + else if (sortMethod == SortByVotes) + { + fields.emplace_back(FieldVotes); + fields.emplace_back(FieldTrackNumber); + } + else if (sortMethod == SortByUserRating) + { + fields.emplace_back(FieldUserRating); + fields.emplace_back(FieldTrackNumber); + } + else if (sortMethod == SortByFile) + { + fields.emplace_back(FieldPath); + fields.emplace_back(FieldFilename); + fields.emplace_back(FieldStartOffset); + } + else if (sortMethod == SortByTime) + fields.emplace_back(FieldTime); + else if (sortMethod == SortByAlbumType) + { + fields.emplace_back(FieldAlbumType); + fields.emplace_back(FieldAlbum); + fields.emplace_back(FieldTrackNumber); + } + else if (sortMethod == SortByOrigDate) + { + fields.emplace_back(FieldOrigDate); + fields.emplace_back(FieldAlbum); + fields.emplace_back(FieldTrackNumber); + } + else if (sortMethod == SortByBPM) + fields.emplace_back(FieldBPM); + } + else if (mediaType == MediaTypeArtist) + { + if (sortMethod == SortByLabel || sortMethod == SortByTitle || sortMethod == SortByArtist) + fields.emplace_back(FieldArtist); + else if (sortMethod == SortByGenre) + fields.emplace_back(FieldGenre); + else if (sortMethod == SortByDateAdded) + fields.emplace_back(FieldDateAdded); + } + + // Add sort by id to define order when other fields same or sort none + fields.emplace_back(FieldId); + return; +} + + +void SortUtils::Sort(SortBy sortBy, SortOrder sortOrder, SortAttribute attributes, DatabaseResults& items, int limitEnd /* = -1 */, int limitStart /* = 0 */) +{ + if (sortBy != SortByNone) + { + // get the matching SortPreparator + SortPreparator preparator = getPreparator(sortBy); + if (preparator != NULL) + { + Fields sortingFields = GetFieldsForSorting(sortBy); + + // Prepare the string used for sorting and store it under FieldSort + for (DatabaseResults::iterator item = items.begin(); item != items.end(); ++item) + { + // add all fields to the item that are required for sorting if they are currently missing + for (Fields::const_iterator field = sortingFields.begin(); field != sortingFields.end(); ++field) + { + if (item->find(*field) == item->end()) + item->insert(std::pair(*field, CVariant::ConstNullVariant)); + } + + std::wstring sortLabel; + g_charsetConverter.utf8ToW(preparator(attributes, *item), sortLabel, false); + item->insert(std::pair(FieldSort, CVariant(sortLabel))); + } + + // Do the sorting + std::stable_sort(items.begin(), items.end(), getSorter(sortOrder, attributes)); + } + } + + if (limitStart > 0 && (size_t)limitStart < items.size()) + { + items.erase(items.begin(), items.begin() + limitStart); + limitEnd -= limitStart; + } + if (limitEnd > 0 && (size_t)limitEnd < items.size()) + items.erase(items.begin() + limitEnd, items.end()); +} + +void SortUtils::Sort(SortBy sortBy, SortOrder sortOrder, SortAttribute attributes, SortItems& items, int limitEnd /* = -1 */, int limitStart /* = 0 */) +{ + if (sortBy != SortByNone) + { + // get the matching SortPreparator + SortPreparator preparator = getPreparator(sortBy); + if (preparator != NULL) + { + Fields sortingFields = GetFieldsForSorting(sortBy); + + // Prepare the string used for sorting and store it under FieldSort + for (SortItems::iterator item = items.begin(); item != items.end(); ++item) + { + // add all fields to the item that are required for sorting if they are currently missing + for (Fields::const_iterator field = sortingFields.begin(); field != sortingFields.end(); ++field) + { + if ((*item)->find(*field) == (*item)->end()) + (*item)->insert(std::pair(*field, CVariant::ConstNullVariant)); + } + + std::wstring sortLabel; + g_charsetConverter.utf8ToW(preparator(attributes, **item), sortLabel, false); + (*item)->insert(std::pair(FieldSort, CVariant(sortLabel))); + } + + // Do the sorting + std::stable_sort(items.begin(), items.end(), getSorterIndirect(sortOrder, attributes)); + } + } + + if (limitStart > 0 && (size_t)limitStart < items.size()) + { + items.erase(items.begin(), items.begin() + limitStart); + limitEnd -= limitStart; + } + if (limitEnd > 0 && (size_t)limitEnd < items.size()) + items.erase(items.begin() + limitEnd, items.end()); +} + +void SortUtils::Sort(const SortDescription &sortDescription, DatabaseResults& items) +{ + Sort(sortDescription.sortBy, sortDescription.sortOrder, sortDescription.sortAttributes, items, sortDescription.limitEnd, sortDescription.limitStart); +} + +void SortUtils::Sort(const SortDescription &sortDescription, SortItems& items) +{ + Sort(sortDescription.sortBy, sortDescription.sortOrder, sortDescription.sortAttributes, items, sortDescription.limitEnd, sortDescription.limitStart); +} + +bool SortUtils::SortFromDataset(const SortDescription &sortDescription, const MediaType &mediaType, const std::unique_ptr &dataset, DatabaseResults &results) +{ + FieldList fields; + if (!DatabaseUtils::GetSelectFields(SortUtils::GetFieldsForSorting(sortDescription.sortBy), mediaType, fields)) + fields.clear(); + + if (!DatabaseUtils::GetDatabaseResults(mediaType, fields, dataset, results)) + return false; + + SortDescription sorting = sortDescription; + if (sortDescription.sortBy == SortByNone) + { + sorting.limitStart = 0; + sorting.limitEnd = -1; + } + + Sort(sorting, results); + + return true; +} + +const SortUtils::SortPreparator& SortUtils::getPreparator(SortBy sortBy) +{ + std::map::const_iterator it = m_preparators.find(sortBy); + if (it != m_preparators.end()) + return it->second; + + return m_preparators[SortByNone]; +} + +SortUtils::Sorter SortUtils::getSorter(SortOrder sortOrder, SortAttribute attributes) +{ + if (attributes & SortAttributeIgnoreFolders) + return sortOrder == SortOrderDescending ? SorterIgnoreFoldersDescending : SorterIgnoreFoldersAscending; + + return sortOrder == SortOrderDescending ? SorterDescending : SorterAscending; +} + +SortUtils::SorterIndirect SortUtils::getSorterIndirect(SortOrder sortOrder, SortAttribute attributes) +{ + if (attributes & SortAttributeIgnoreFolders) + return sortOrder == SortOrderDescending ? SorterIndirectIgnoreFoldersDescending : SorterIndirectIgnoreFoldersAscending; + + return sortOrder == SortOrderDescending ? SorterIndirectDescending : SorterIndirectAscending; +} + +const Fields& SortUtils::GetFieldsForSorting(SortBy sortBy) +{ + std::map::const_iterator it = m_sortingFields.find(sortBy); + if (it != m_sortingFields.end()) + return it->second; + + return m_sortingFields[SortByNone]; +} + +std::string SortUtils::RemoveArticles(const std::string &label) +{ + std::set sortTokens = g_langInfo.GetSortTokens(); + for (std::set::const_iterator token = sortTokens.begin(); token != sortTokens.end(); ++token) + { + if (token->size() < label.size() && StringUtils::StartsWithNoCase(label, *token)) + return label.substr(token->size()); + } + + return label; +} + +typedef struct +{ + SortBy sort; + SORT_METHOD old; + SortAttribute flags; + int label; +} sort_map; + +// clang-format off +const sort_map table[] = { + { SortByLabel, SORT_METHOD_LABEL, SortAttributeNone, 551 }, + { SortByLabel, SORT_METHOD_LABEL_IGNORE_THE, SortAttributeIgnoreArticle, 551 }, + { SortByLabel, SORT_METHOD_LABEL_IGNORE_FOLDERS, SortAttributeIgnoreFolders, 551 }, + { SortByDate, SORT_METHOD_DATE, SortAttributeNone, 552 }, + { SortBySize, SORT_METHOD_SIZE, SortAttributeNone, 553 }, + { SortByBitrate, SORT_METHOD_BITRATE, SortAttributeNone, 623 }, + { SortByDriveType, SORT_METHOD_DRIVE_TYPE, SortAttributeNone, 564 }, + { SortByTrackNumber, SORT_METHOD_TRACKNUM, SortAttributeNone, 554 }, + { SortByEpisodeNumber, SORT_METHOD_EPISODE, SortAttributeNone, 20359 },// 20360 "Episodes" used for SORT_METHOD_EPISODE for sorting tvshows by episode count + { SortByTime, SORT_METHOD_DURATION, SortAttributeNone, 180 }, + { SortByTime, SORT_METHOD_VIDEO_RUNTIME, SortAttributeNone, 180 }, + { SortByTitle, SORT_METHOD_TITLE, SortAttributeNone, 556 }, + { SortByTitle, SORT_METHOD_TITLE_IGNORE_THE, SortAttributeIgnoreArticle, 556 }, + { SortByTitle, SORT_METHOD_VIDEO_TITLE, SortAttributeNone, 556 }, + { SortByArtist, SORT_METHOD_ARTIST, SortAttributeNone, 557 }, + { SortByArtistThenYear, SORT_METHOD_ARTIST_AND_YEAR, SortAttributeNone, 578 }, + { SortByArtist, SORT_METHOD_ARTIST_IGNORE_THE, SortAttributeIgnoreArticle, 557 }, + { SortByAlbum, SORT_METHOD_ALBUM, SortAttributeNone, 558 }, + { SortByAlbum, SORT_METHOD_ALBUM_IGNORE_THE, SortAttributeIgnoreArticle, 558 }, + { SortByGenre, SORT_METHOD_GENRE, SortAttributeNone, 515 }, + { SortByCountry, SORT_METHOD_COUNTRY, SortAttributeNone, 574 }, + { SortByDateAdded, SORT_METHOD_DATEADDED, SortAttributeIgnoreFolders, 570 }, + { SortByFile, SORT_METHOD_FILE, SortAttributeIgnoreFolders, 561 }, + { SortByRating, SORT_METHOD_SONG_RATING, SortAttributeNone, 563 }, + { SortByRating, SORT_METHOD_VIDEO_RATING, SortAttributeIgnoreFolders, 563 }, + { SortByUserRating, SORT_METHOD_SONG_USER_RATING, SortAttributeIgnoreFolders, 38018 }, + { SortByUserRating, SORT_METHOD_VIDEO_USER_RATING, SortAttributeIgnoreFolders, 38018 }, + { SortBySortTitle, SORT_METHOD_VIDEO_SORT_TITLE, SortAttributeIgnoreFolders, 171 }, + { SortBySortTitle, SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE, (SortAttribute)(SortAttributeIgnoreFolders | SortAttributeIgnoreArticle), 171 }, + { SortByYear, SORT_METHOD_YEAR, SortAttributeIgnoreFolders, 562 }, + { SortByProductionCode, SORT_METHOD_PRODUCTIONCODE, SortAttributeNone, 20368 }, + { SortByProgramCount, SORT_METHOD_PROGRAM_COUNT, SortAttributeNone, 567 }, // label is "play count" + { SortByPlaylistOrder, SORT_METHOD_PLAYLIST_ORDER, SortAttributeIgnoreFolders, 559 }, + { SortByMPAA, SORT_METHOD_MPAA_RATING, SortAttributeNone, 20074 }, + { SortByStudio, SORT_METHOD_STUDIO, SortAttributeNone, 572 }, + { SortByStudio, SORT_METHOD_STUDIO_IGNORE_THE, SortAttributeIgnoreArticle, 572 }, + { SortByPath, SORT_METHOD_FULLPATH, SortAttributeNone, 573 }, + { SortByLastPlayed, SORT_METHOD_LASTPLAYED, SortAttributeIgnoreFolders, 568 }, + { SortByPlaycount, SORT_METHOD_PLAYCOUNT, SortAttributeIgnoreFolders, 567 }, + { SortByListeners, SORT_METHOD_LISTENERS, SortAttributeNone, 20455 }, + { SortByChannel, SORT_METHOD_CHANNEL, SortAttributeNone, 19029 }, + { SortByChannel, SORT_METHOD_CHANNEL_NUMBER, SortAttributeNone, 549 }, + { SortByChannel, SORT_METHOD_CLIENT_CHANNEL_ORDER, SortAttributeNone, 19315 }, + { SortByDateTaken, SORT_METHOD_DATE_TAKEN, SortAttributeIgnoreFolders, 577 }, + { SortByNone, SORT_METHOD_NONE, SortAttributeNone, 16018 }, + { SortByTotalDiscs, SORT_METHOD_TOTAL_DISCS, SortAttributeNone, 38077 }, + { SortByOrigDate, SORT_METHOD_ORIG_DATE, SortAttributeNone, 38079 }, + { SortByBPM, SORT_METHOD_BPM, SortAttributeNone, 38080 }, + + // the following have no corresponding SORT_METHOD_* + { SortByAlbumType, SORT_METHOD_NONE, SortAttributeNone, 564 }, + { SortByVotes, SORT_METHOD_NONE, SortAttributeNone, 205 }, + { SortByTop250, SORT_METHOD_NONE, SortAttributeNone, 13409 }, + { SortByMPAA, SORT_METHOD_NONE, SortAttributeNone, 20074 }, + { SortByDateAdded, SORT_METHOD_NONE, SortAttributeNone, 570 }, + { SortByTvShowTitle, SORT_METHOD_NONE, SortAttributeNone, 20364 }, + { SortByTvShowStatus, SORT_METHOD_NONE, SortAttributeNone, 126 }, + { SortBySeason, SORT_METHOD_NONE, SortAttributeNone, 20373 }, + { SortByNumberOfEpisodes, SORT_METHOD_NONE, SortAttributeNone, 20360 }, + { SortByNumberOfWatchedEpisodes, SORT_METHOD_NONE, SortAttributeNone, 21441 }, + { SortByVideoResolution, SORT_METHOD_NONE, SortAttributeNone, 21443 }, + { SortByVideoCodec, SORT_METHOD_NONE, SortAttributeNone, 21445 }, + { SortByVideoAspectRatio, SORT_METHOD_NONE, SortAttributeNone, 21374 }, + { SortByAudioChannels, SORT_METHOD_NONE, SortAttributeNone, 21444 }, + { SortByAudioCodec, SORT_METHOD_NONE, SortAttributeNone, 21446 }, + { SortByAudioLanguage, SORT_METHOD_NONE, SortAttributeNone, 21447 }, + { SortBySubtitleLanguage, SORT_METHOD_NONE, SortAttributeNone, 21448 }, + { SortByRandom, SORT_METHOD_NONE, SortAttributeNone, 590 } +}; +// clang-format on + +SORT_METHOD SortUtils::TranslateOldSortMethod(SortBy sortBy, bool ignoreArticle) +{ + for (const sort_map& t : table) + { + if (t.sort == sortBy) + { + if (ignoreArticle == ((t.flags & SortAttributeIgnoreArticle) == SortAttributeIgnoreArticle)) + return t.old; + } + } + for (const sort_map& t : table) + { + if (t.sort == sortBy) + return t.old; + } + return SORT_METHOD_NONE; +} + +SortDescription SortUtils::TranslateOldSortMethod(SORT_METHOD sortBy) +{ + SortDescription description; + for (const sort_map& t : table) + { + if (t.old == sortBy) + { + description.sortBy = t.sort; + description.sortAttributes = t.flags; + break; + } + } + return description; +} + +int SortUtils::GetSortLabel(SortBy sortBy) +{ + for (const sort_map& t : table) + { + if (t.sort == sortBy) + return t.label; + } + return 16018; // None +} + +template +T TypeFromString(const std::map& typeMap, const std::string& name, const T& defaultType) +{ + auto it = typeMap.find(name); + if (it == typeMap.end()) + return defaultType; + + return it->second; +} + +template +const std::string& TypeToString(const std::map& typeMap, const T& value) +{ + auto it = std::find_if(typeMap.begin(), typeMap.end(), + [&value](const std::pair& pair) + { + return pair.second == value; + }); + + if (it == typeMap.end()) + return StringUtils::Empty; + + return it->first; +} + +/** + * @brief Sort methods to translate string values to enum values. + * + * @warning On string changes, edit __SortBy__ enumerator to have strings right + * for documentation! + */ +const std::map sortMethods = { + { "label", SortByLabel }, + { "date", SortByDate }, + { "size", SortBySize }, + { "file", SortByFile }, + { "path", SortByPath }, + { "drivetype", SortByDriveType }, + { "title", SortByTitle }, + { "track", SortByTrackNumber }, + { "time", SortByTime }, + { "artist", SortByArtist }, + { "artistyear", SortByArtistThenYear }, + { "album", SortByAlbum }, + { "albumtype", SortByAlbumType }, + { "genre", SortByGenre }, + { "country", SortByCountry }, + { "year", SortByYear }, + { "rating", SortByRating }, + { "votes", SortByVotes }, + { "top250", SortByTop250 }, + { "programcount", SortByProgramCount }, + { "playlist", SortByPlaylistOrder }, + { "episode", SortByEpisodeNumber }, + { "season", SortBySeason }, + { "totalepisodes", SortByNumberOfEpisodes }, + { "watchedepisodes", SortByNumberOfWatchedEpisodes }, + { "tvshowstatus", SortByTvShowStatus }, + { "tvshowtitle", SortByTvShowTitle }, + { "sorttitle", SortBySortTitle }, + { "productioncode", SortByProductionCode }, + { "mpaa", SortByMPAA }, + { "videoresolution", SortByVideoResolution }, + { "videocodec", SortByVideoCodec }, + { "videoaspectratio", SortByVideoAspectRatio }, + { "audiochannels", SortByAudioChannels }, + { "audiocodec", SortByAudioCodec }, + { "audiolanguage", SortByAudioLanguage }, + { "subtitlelanguage", SortBySubtitleLanguage }, + { "studio", SortByStudio }, + { "dateadded", SortByDateAdded }, + { "lastplayed", SortByLastPlayed }, + { "playcount", SortByPlaycount }, + { "listeners", SortByListeners }, + { "bitrate", SortByBitrate }, + { "random", SortByRandom }, + { "channel", SortByChannel }, + { "channelnumber", SortByChannelNumber }, + { "clientchannelorder", SortByClientChannelOrder }, + { "datetaken", SortByDateTaken }, + { "userrating", SortByUserRating }, + { "installdate", SortByInstallDate }, + { "lastupdated", SortByLastUpdated }, + { "lastused", SortByLastUsed }, + { "totaldiscs", SortByTotalDiscs }, + { "originaldate", SortByOrigDate }, + { "bpm", SortByBPM }, +}; + +SortBy SortUtils::SortMethodFromString(const std::string& sortMethod) +{ + return TypeFromString(sortMethods, sortMethod, SortByNone); +} + +const std::string& SortUtils::SortMethodToString(SortBy sortMethod) +{ + return TypeToString(sortMethods, sortMethod); +} + +const std::map sortOrders = { + { "ascending", SortOrderAscending }, + { "descending", SortOrderDescending } +}; + +SortOrder SortUtils::SortOrderFromString(const std::string& sortOrder) +{ + return TypeFromString(sortOrders, sortOrder, SortOrderNone); +} + +const std::string& SortUtils::SortOrderToString(SortOrder sortOrder) +{ + return TypeToString(sortOrders, sortOrder); +} diff --git a/xbmc/utils/SortUtils.h b/xbmc/utils/SortUtils.h new file mode 100644 index 0000000..79629d4 --- /dev/null +++ b/xbmc/utils/SortUtils.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "DatabaseUtils.h" +#include "LabelFormatter.h" +#include "SortFileItem.h" + +#include +#include +#include +#include + +typedef enum { + SortOrderNone = 0, + SortOrderAscending, + SortOrderDescending +} SortOrder; + +typedef enum { + SortAttributeNone = 0x0, + SortAttributeIgnoreArticle = 0x1, + SortAttributeIgnoreFolders = 0x2, + SortAttributeUseArtistSortName = 0x4, + SortAttributeIgnoreLabel = 0x8 +} SortAttribute; + +typedef enum { + SortSpecialNone = 0, + SortSpecialOnTop = 1, + SortSpecialOnBottom = 2 +} SortSpecial; + +/// +/// \defgroup List_of_sort_methods List of sort methods +/// \addtogroup List_of_sort_methods +/// +/// \brief These ID's can be used with the \ref built_in_functions_6 "Container.SetSortMethod(id)" function +/// \note The on field named part with String shows the string used on +/// GUI to set this sort type. +/// +///@{ +typedef enum { + /// __0__ : + SortByNone = 0, + /// __1__ : Sort by Name (String: Label) + SortByLabel, + /// __2__ : Sort by Date (String: Date) + SortByDate, + /// __3__ : Sort by Size (String: Size) + SortBySize, + /// __4__ : Sort by filename (String: File) + SortByFile, + /// __5__ : Sort by path (String: Path) + SortByPath, + /// __6__ : Sort by drive type (String: DriveType) + SortByDriveType, + /// __7__ : Sort by title (String: Title) + SortByTitle, + /// __8__ : Sort by track number (String: TrackNumber) + SortByTrackNumber, + /// __9__ : Sort by time (String: Time) + SortByTime, + /// __10__ : Sort by artist (String: Artist) + SortByArtist, + /// __11__ : Sort by first artist then year (String: ArtistYear) + SortByArtistThenYear, + /// __12__ : Sort by album (String: Album) + SortByAlbum, + /// __13__ : Sort by album type (String: AlbumType) + SortByAlbumType, + /// __14__ : Sort by genre (String: Genre) + SortByGenre, + /// __15__ : Sort by country (String: Country) + SortByCountry, + /// __16__ : Sort by year (String: Year) + SortByYear, + /// __17__ : Sort by rating (String: Rating) + SortByRating, + /// __18__ : Sort by user rating (String: UserRating) + SortByUserRating, + /// __19__ : Sort by votes (String: Votes) + SortByVotes, + /// __20__ : Sort by top 250 (String: Top250) + SortByTop250, + /// __21__ : Sort by program count (String: ProgramCount) + SortByProgramCount, + /// __22__ : Sort by playlist order (String: Playlist) + SortByPlaylistOrder, + /// __23__ : Sort by episode number (String: Episode) + SortByEpisodeNumber, + /// __24__ : Sort by season (String: Season) + SortBySeason, + /// __25__ : Sort by number of episodes (String: TotalEpisodes) + SortByNumberOfEpisodes, + /// __26__ : Sort by number of watched episodes (String: WatchedEpisodes) + SortByNumberOfWatchedEpisodes, + /// __27__ : Sort by TV show status (String: TvShowStatus) + SortByTvShowStatus, + /// __28__ : Sort by TV show title (String: TvShowTitle) + SortByTvShowTitle, + /// __29__ : Sort by sort title (String: SortTitle) + SortBySortTitle, + /// __30__ : Sort by production code (String: ProductionCode) + SortByProductionCode, + /// __31__ : Sort by MPAA (String: MPAA) + SortByMPAA, + /// __32__ : Sort by video resolution (String: VideoResolution) + SortByVideoResolution, + /// __33__ : Sort by video codec (String: VideoCodec) + SortByVideoCodec, + /// __34__ : Sort by video aspect ratio (String: VideoAspectRatio) + SortByVideoAspectRatio, + /// __35__ : Sort by audio channels (String: AudioChannels) + SortByAudioChannels, + /// __36__ : Sort by audio codec (String: AudioCodec) + SortByAudioCodec, + /// __37__ : Sort by audio language (String: AudioLanguage) + SortByAudioLanguage, + /// __38__ : Sort by subtitle language (String: SubtitleLanguage) + SortBySubtitleLanguage, + /// __39__ : Sort by studio (String: Studio) + SortByStudio, + /// __40__ : Sort by date added (String: DateAdded) + SortByDateAdded, + /// __41__ : Sort by last played (String: LastPlayed) + SortByLastPlayed, + /// __42__ : Sort by playcount (String: PlayCount) + SortByPlaycount, + /// __43__ : Sort by listener (String: Listeners) + SortByListeners, + /// __44__ : Sort by bitrate (String: Bitrate) + SortByBitrate, + /// __45__ : Sort by random (String: Random) + SortByRandom, + /// __46__ : Sort by channel (String: Channel) + SortByChannel, + /// __47__ : Sort by channel number (String: ChannelNumber) + SortByChannelNumber, + /// __48__ : Sort by date taken (String: DateTaken) + SortByDateTaken, + /// __49__ : Sort by relevance + SortByRelevance, + /// __50__ : Sort by installation date (String: installdate) + SortByInstallDate, + /// __51__ : Sort by last updated (String: lastupdated) + SortByLastUpdated, + /// __52__ : Sort by last used (String: lastused) + SortByLastUsed, + /// __53__ : Sort by client channel order (String: ClientChannelOrder) + SortByClientChannelOrder, + /// __54__ : Sort by total number of discs (String: totaldiscs) + SortByTotalDiscs, + /// __55__ : Sort by original release date (String: Originaldate) + SortByOrigDate, + /// __56__ : Sort by BPM (String: bpm) + SortByBPM, +} SortBy; +///@} + +typedef struct SortDescription { + SortBy sortBy = SortByNone; + SortOrder sortOrder = SortOrderAscending; + SortAttribute sortAttributes = SortAttributeNone; + int limitStart = 0; + int limitEnd = -1; +} SortDescription; + +typedef struct GUIViewSortDetails +{ + SortDescription m_sortDescription; + int m_buttonLabel; + LABEL_MASKS m_labelMasks; +} GUIViewSortDetails; + +typedef DatabaseResult SortItem; +typedef std::shared_ptr SortItemPtr; +typedef std::vector SortItems; + +class SortUtils +{ +public: + static SORT_METHOD TranslateOldSortMethod(SortBy sortBy, bool ignoreArticle); + static SortDescription TranslateOldSortMethod(SORT_METHOD sortBy); + + static SortBy SortMethodFromString(const std::string& sortMethod); + static const std::string& SortMethodToString(SortBy sortMethod); + static SortOrder SortOrderFromString(const std::string& sortOrder); + static const std::string& SortOrderToString(SortOrder sortOrder); + + /*! \brief retrieve the label id associated with a sort method for displaying in the UI. + \param sortBy the sort method in question. + \return the label id of the sort method. + */ + static int GetSortLabel(SortBy sortBy); + + static void Sort(SortBy sortBy, SortOrder sortOrder, SortAttribute attributes, DatabaseResults& items, int limitEnd = -1, int limitStart = 0); + static void Sort(SortBy sortBy, SortOrder sortOrder, SortAttribute attributes, SortItems& items, int limitEnd = -1, int limitStart = 0); + static void Sort(const SortDescription &sortDescription, DatabaseResults& items); + static void Sort(const SortDescription &sortDescription, SortItems& items); + static bool SortFromDataset(const SortDescription &sortDescription, const MediaType &mediaType, const std::unique_ptr &dataset, DatabaseResults &results); + + static void GetFieldsForSQLSort(const MediaType& mediaType, SortBy sortMethod, FieldList& fields); + static const Fields& GetFieldsForSorting(SortBy sortBy); + static std::string RemoveArticles(const std::string &label); + + typedef std::string (*SortPreparator) (SortAttribute, const SortItem&); + typedef bool (*Sorter) (const DatabaseResult &, const DatabaseResult &); + typedef bool (*SorterIndirect) (const SortItemPtr &, const SortItemPtr &); + +private: + static const SortPreparator& getPreparator(SortBy sortBy); + static Sorter getSorter(SortOrder sortOrder, SortAttribute attributes); + static SorterIndirect getSorterIndirect(SortOrder sortOrder, SortAttribute attributes); + + static std::map m_preparators; + static std::map m_sortingFields; +}; diff --git a/xbmc/utils/Speed.cpp b/xbmc/utils/Speed.cpp new file mode 100644 index 0000000..441c16c --- /dev/null +++ b/xbmc/utils/Speed.cpp @@ -0,0 +1,582 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Speed.h" + +#include "utils/Archive.h" +#include "utils/StringUtils.h" + +#include + +CSpeed::CSpeed() +{ + m_value = 0.0; + m_valid = false; +} + +CSpeed::CSpeed(const CSpeed& speed) +{ + m_value = speed.m_value; + m_valid = speed.m_valid; +} + +CSpeed::CSpeed(double value) +{ + m_value = value; + m_valid = true; +} + +bool CSpeed::operator >(const CSpeed& right) const +{ + assert(IsValid()); + assert(right.IsValid()); + + if (!IsValid() || !right.IsValid()) + return false; + + if (this == &right) + return false; + + return (m_value > right.m_value); +} + +bool CSpeed::operator >=(const CSpeed& right) const +{ + return operator >(right) || operator ==(right); +} + +bool CSpeed::operator <(const CSpeed& right) const +{ + assert(IsValid()); + assert(right.IsValid()); + + if (!IsValid() || !right.IsValid()) + return false; + + if (this == &right) + return false; + + return (m_value < right.m_value); +} + +bool CSpeed::operator <=(const CSpeed& right) const +{ + return operator <(right) || operator ==(right); +} + +bool CSpeed::operator ==(const CSpeed& right) const +{ + assert(IsValid()); + assert(right.IsValid()); + + if (!IsValid() || !right.IsValid()) + return false; + + if (this == &right) + return true; + + return (m_value == right.m_value); +} + +bool CSpeed::operator !=(const CSpeed& right) const +{ + return !operator ==(right.m_value); +} + +CSpeed& CSpeed::operator =(const CSpeed& right) +{ + m_valid = right.m_valid; + m_value = right.m_value; + return *this; +} + +const CSpeed& CSpeed::operator +=(const CSpeed& right) +{ + assert(IsValid()); + assert(right.IsValid()); + + m_value += right.m_value; + return *this; +} + +const CSpeed& CSpeed::operator -=(const CSpeed& right) +{ + assert(IsValid()); + assert(right.IsValid()); + + m_value -= right.m_value; + return *this; +} + +const CSpeed& CSpeed::operator *=(const CSpeed& right) +{ + assert(IsValid()); + assert(right.IsValid()); + + m_value *= right.m_value; + return *this; +} + +const CSpeed& CSpeed::operator /=(const CSpeed& right) +{ + assert(IsValid()); + assert(right.IsValid()); + + m_value /= right.m_value; + return *this; +} + +CSpeed CSpeed::operator +(const CSpeed& right) const +{ + assert(IsValid()); + assert(right.IsValid()); + + CSpeed temp(*this); + + if (!IsValid() || !right.IsValid()) + temp.SetValid(false); + else + temp.m_value += right.m_value; + + return temp; +} + +CSpeed CSpeed::operator -(const CSpeed& right) const +{ + assert(IsValid()); + assert(right.IsValid()); + + CSpeed temp(*this); + if (!IsValid() || !right.IsValid()) + temp.SetValid(false); + else + temp.m_value -= right.m_value; + + return temp; +} + +CSpeed CSpeed::operator *(const CSpeed& right) const +{ + assert(IsValid()); + assert(right.IsValid()); + + CSpeed temp(*this); + if (!IsValid() || !right.IsValid()) + temp.SetValid(false); + else + temp.m_value *= right.m_value; + return temp; +} + +CSpeed CSpeed::operator /(const CSpeed& right) const +{ + assert(IsValid()); + assert(right.IsValid()); + + CSpeed temp(*this); + if (!IsValid() || !right.IsValid()) + temp.SetValid(false); + else + temp.m_value /= right.m_value; + return temp; +} + +CSpeed& CSpeed::operator ++() +{ + assert(IsValid()); + + m_value++; + return *this; +} + +CSpeed& CSpeed::operator --() +{ + assert(IsValid()); + + m_value--; + return *this; +} + +CSpeed CSpeed::operator ++(int) +{ + assert(IsValid()); + + CSpeed temp(*this); + m_value++; + return temp; +} + +CSpeed CSpeed::operator --(int) +{ + assert(IsValid()); + + CSpeed temp(*this); + m_value--; + return temp; +} + +bool CSpeed::operator >(double right) const +{ + assert(IsValid()); + + if (!IsValid()) + return false; + + return (m_value > right); +} + +bool CSpeed::operator >=(double right) const +{ + return operator >(right) || operator ==(right); +} + +bool CSpeed::operator <(double right) const +{ + assert(IsValid()); + + if (!IsValid()) + return false; + + return (m_value < right); +} + +bool CSpeed::operator <=(double right) const +{ + return operator <(right) || operator ==(right); +} + +bool CSpeed::operator ==(double right) const +{ + if (!IsValid()) + return false; + + return (m_value == right); +} + +bool CSpeed::operator !=(double right) const +{ + return !operator ==(right); +} + +const CSpeed& CSpeed::operator +=(double right) +{ + assert(IsValid()); + + m_value += right; + return *this; +} + +const CSpeed& CSpeed::operator -=(double right) +{ + assert(IsValid()); + + m_value -= right; + return *this; +} + +const CSpeed& CSpeed::operator *=(double right) +{ + assert(IsValid()); + + m_value *= right; + return *this; +} + +const CSpeed& CSpeed::operator /=(double right) +{ + assert(IsValid()); + + m_value /= right; + return *this; +} + +CSpeed CSpeed::operator +(double right) const +{ + assert(IsValid()); + + CSpeed temp(*this); + temp.m_value += right; + return temp; +} + +CSpeed CSpeed::operator -(double right) const +{ + assert(IsValid()); + + CSpeed temp(*this); + temp.m_value -= right; + return temp; +} + +CSpeed CSpeed::operator *(double right) const +{ + assert(IsValid()); + + CSpeed temp(*this); + temp.m_value *= right; + return temp; +} + +CSpeed CSpeed::operator /(double right) const +{ + assert(IsValid()); + + CSpeed temp(*this); + temp.m_value /= right; + return temp; +} + +CSpeed CSpeed::CreateFromKilometresPerHour(double value) +{ + return CSpeed(value / 3.6); +} + +CSpeed CSpeed::CreateFromMetresPerMinute(double value) +{ + return CSpeed(value / 60.0); +} + +CSpeed CSpeed::CreateFromMetresPerSecond(double value) +{ + return CSpeed(value); +} + +CSpeed CSpeed::CreateFromFeetPerHour(double value) +{ + return CreateFromFeetPerMinute(value / 60.0); +} + +CSpeed CSpeed::CreateFromFeetPerMinute(double value) +{ + return CreateFromFeetPerSecond(value / 60.0); +} + +CSpeed CSpeed::CreateFromFeetPerSecond(double value) +{ + return CSpeed(value / 3.280839895); +} + +CSpeed CSpeed::CreateFromMilesPerHour(double value) +{ + return CSpeed(value / 2.236936292); +} + +CSpeed CSpeed::CreateFromKnots(double value) +{ + return CSpeed(value / 1.943846172); +} + +CSpeed CSpeed::CreateFromBeaufort(unsigned int value) +{ + if (value == 0) + return CSpeed(0.15); + if (value == 1) + return CSpeed(0.9); + if (value == 2) + return CSpeed(2.4); + if (value == 3) + return CSpeed(4.4); + if (value == 4) + return CSpeed(6.75); + if (value == 5) + return CSpeed(9.4); + if (value == 6) + return CSpeed(12.35); + if (value == 7) + return CSpeed(15.55); + if (value == 8) + return CSpeed(18.95); + if (value == 9) + return CSpeed(22.6); + if (value == 10) + return CSpeed(26.45); + if (value == 11) + return CSpeed(30.5); + + return CSpeed(32.6); +} + +CSpeed CSpeed::CreateFromInchPerSecond(double value) +{ + return CSpeed(value / 39.37007874); +} + +CSpeed CSpeed::CreateFromYardPerSecond(double value) +{ + return CSpeed(value / 1.093613298); +} + +CSpeed CSpeed::CreateFromFurlongPerFortnight(double value) +{ + return CSpeed(value / 6012.885613871); +} + +void CSpeed::Archive(CArchive& ar) +{ + if (ar.IsStoring()) + { + ar << m_value; + ar << m_valid; + } + else + { + ar >> m_value; + ar >> m_valid; + } +} + +bool CSpeed::IsValid() const +{ + return m_valid; +} + +double CSpeed::ToKilometresPerHour() const +{ + return m_value * 3.6; +} + +double CSpeed::ToMetresPerMinute() const +{ + return m_value * 60.0; +} + +double CSpeed::ToMetresPerSecond() const +{ + return m_value; +} + +double CSpeed::ToFeetPerHour() const +{ + return ToFeetPerMinute() * 60.0; +} + +double CSpeed::ToFeetPerMinute() const +{ + return ToFeetPerSecond() * 60.0; +} + +double CSpeed::ToFeetPerSecond() const +{ + return m_value * 3.280839895; +} + +double CSpeed::ToMilesPerHour() const +{ + return m_value * 2.236936292; +} + +double CSpeed::ToKnots() const +{ + return m_value * 1.943846172; +} + +double CSpeed::ToBeaufort() const +{ + if (m_value < 0.3) + return 0; + if (m_value >= 0.3 && m_value < 1.5) + return 1; + if (m_value >= 1.5 && m_value < 3.3) + return 2; + if (m_value >= 3.3 && m_value < 5.5) + return 3; + if (m_value >= 5.5 && m_value < 8.0) + return 4; + if (m_value >= 8.0 && m_value < 10.8) + return 5; + if (m_value >= 10.8 && m_value < 13.9) + return 6; + if (m_value >= 13.9 && m_value < 17.2) + return 7; + if (m_value >= 17.2 && m_value < 20.7) + return 8; + if (m_value >= 20.7 && m_value < 24.5) + return 9; + if (m_value >= 24.5 && m_value < 28.4) + return 10; + if (m_value >= 28.4 && m_value < 32.6) + return 11; + + return 12; +} + +double CSpeed::ToInchPerSecond() const +{ + return m_value * 39.37007874; +} + +double CSpeed::ToYardPerSecond() const +{ + return m_value * 1.093613298; +} + +double CSpeed::ToFurlongPerFortnight() const +{ + return m_value * 6012.885613871; +} + +double CSpeed::To(Unit speedUnit) const +{ + if (!IsValid()) + return 0; + + double value = 0.0; + + switch (speedUnit) + { + case UnitKilometresPerHour: + value = ToKilometresPerHour(); + break; + case UnitMetresPerMinute: + value = ToMetresPerMinute(); + break; + case UnitMetresPerSecond: + value = ToMetresPerSecond(); + break; + case UnitFeetPerHour: + value = ToFeetPerHour(); + break; + case UnitFeetPerMinute: + value = ToFeetPerMinute(); + break; + case UnitFeetPerSecond: + value = ToFeetPerSecond(); + break; + case UnitMilesPerHour: + value = ToMilesPerHour(); + break; + case UnitKnots: + value = ToKnots(); + break; + case UnitBeaufort: + value = ToBeaufort(); + break; + case UnitInchPerSecond: + value = ToInchPerSecond(); + break; + case UnitYardPerSecond: + value = ToYardPerSecond(); + break; + case UnitFurlongPerFortnight: + value = ToFurlongPerFortnight(); + break; + default: + assert(false); + break; + } + return value; +} + +// Returns temperature as localized string +std::string CSpeed::ToString(Unit speedUnit) const +{ + if (!IsValid()) + return ""; + + return StringUtils::Format("%2.0f", To(speedUnit)); +} diff --git a/xbmc/utils/Speed.h b/xbmc/utils/Speed.h new file mode 100644 index 0000000..8ad5d05 --- /dev/null +++ b/xbmc/utils/Speed.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/IArchivable.h" + +#include + +class CSpeed : public IArchivable +{ +public: + CSpeed(); + CSpeed(const CSpeed& speed); + + typedef enum Unit + { + UnitKilometresPerHour = 0, + UnitMetresPerMinute, + UnitMetresPerSecond, + UnitFeetPerHour, + UnitFeetPerMinute, + UnitFeetPerSecond, + UnitMilesPerHour, + UnitKnots, + UnitBeaufort, + UnitInchPerSecond, + UnitYardPerSecond, + UnitFurlongPerFortnight + } Unit; + + static CSpeed CreateFromKilometresPerHour(double value); + static CSpeed CreateFromMetresPerMinute(double value); + static CSpeed CreateFromMetresPerSecond(double value); + static CSpeed CreateFromFeetPerHour(double value); + static CSpeed CreateFromFeetPerMinute(double value); + static CSpeed CreateFromFeetPerSecond(double value); + static CSpeed CreateFromMilesPerHour(double value); + static CSpeed CreateFromKnots(double value); + static CSpeed CreateFromBeaufort(unsigned int value); + static CSpeed CreateFromInchPerSecond(double value); + static CSpeed CreateFromYardPerSecond(double value); + static CSpeed CreateFromFurlongPerFortnight(double value); + + bool operator >(const CSpeed& right) const; + bool operator >=(const CSpeed& right) const; + bool operator <(const CSpeed& right) const; + bool operator <=(const CSpeed& right) const; + bool operator ==(const CSpeed& right) const; + bool operator !=(const CSpeed& right) const; + + CSpeed& operator =(const CSpeed& right); + const CSpeed& operator +=(const CSpeed& right); + const CSpeed& operator -=(const CSpeed& right); + const CSpeed& operator *=(const CSpeed& right); + const CSpeed& operator /=(const CSpeed& right); + CSpeed operator +(const CSpeed& right) const; + CSpeed operator -(const CSpeed& right) const; + CSpeed operator *(const CSpeed& right) const; + CSpeed operator /(const CSpeed& right) const; + + bool operator >(double right) const; + bool operator >=(double right) const; + bool operator <(double right) const; + bool operator <=(double right) const; + bool operator ==(double right) const; + bool operator !=(double right) const; + + const CSpeed& operator +=(double right); + const CSpeed& operator -=(double right); + const CSpeed& operator *=(double right); + const CSpeed& operator /=(double right); + CSpeed operator +(double right) const; + CSpeed operator -(double right) const; + CSpeed operator *(double right) const; + CSpeed operator /(double right) const; + + CSpeed& operator ++(); + CSpeed& operator --(); + CSpeed operator ++(int); + CSpeed operator --(int); + + void Archive(CArchive& ar) override; + + bool IsValid() const; + + double ToKilometresPerHour() const; + double ToMetresPerMinute() const; + double ToMetresPerSecond() const; + double ToFeetPerHour() const; + double ToFeetPerMinute() const; + double ToFeetPerSecond() const; + double ToMilesPerHour() const; + double ToKnots() const; + double ToBeaufort() const; + double ToInchPerSecond() const; + double ToYardPerSecond() const; + double ToFurlongPerFortnight() const; + + double To(Unit speedUnit) const; + std::string ToString(Unit speedUnit) const; + +protected: + explicit CSpeed(double value); + + void SetValid(bool valid) { m_valid = valid; } + + double m_value; // we store in m/s + bool m_valid; +}; + diff --git a/xbmc/utils/StaticLoggerBase.cpp b/xbmc/utils/StaticLoggerBase.cpp new file mode 100644 index 0000000..5bcc06a --- /dev/null +++ b/xbmc/utils/StaticLoggerBase.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "StaticLoggerBase.h" + +#include "ServiceBroker.h" +#include "utils/log.h" + +Logger CStaticLoggerBase::s_logger; + +CStaticLoggerBase::CStaticLoggerBase(const std::string& loggerName) +{ + if (s_logger == nullptr) + s_logger = CServiceBroker::GetLogging().GetLogger(loggerName); +} diff --git a/xbmc/utils/StaticLoggerBase.h b/xbmc/utils/StaticLoggerBase.h new file mode 100644 index 0000000..a3da35f --- /dev/null +++ b/xbmc/utils/StaticLoggerBase.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/logtypes.h" + +#include + +class CStaticLoggerBase +{ +protected: + explicit CStaticLoggerBase(const std::string& loggerName); + + static Logger s_logger; +}; diff --git a/xbmc/utils/Stopwatch.cpp b/xbmc/utils/Stopwatch.cpp new file mode 100644 index 0000000..bec498f --- /dev/null +++ b/xbmc/utils/Stopwatch.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Stopwatch.h" +#if defined(TARGET_POSIX) +#include "threads/SystemClock.h" +#if !defined(TARGET_DARWIN) && !defined(TARGET_FREEBSD) +#include +#endif +#endif +#include "utils/TimeUtils.h" + +CStopWatch::CStopWatch(bool useFrameTime /*=false*/) +{ + m_timerPeriod = 0.0f; + m_startTick = 0; + m_stopTick = 0; + m_isRunning = false; + m_useFrameTime = useFrameTime; + +#ifdef TARGET_POSIX + m_timerPeriod = 1.0f / 1000.0f; // we want seconds +#else + if (m_useFrameTime) + m_timerPeriod = 1.0f / 1000.0f; //frametime is in milliseconds + else + m_timerPeriod = 1.0f / (float)CurrentHostFrequency(); +#endif +} + +CStopWatch::~CStopWatch() = default; + +int64_t CStopWatch::GetTicks() const +{ + if (m_useFrameTime) + return CTimeUtils::GetFrameTime(); +#ifndef TARGET_POSIX + return CurrentHostCounter(); +#else + return XbmcThreads::SystemClockMillis(); +#endif +} diff --git a/xbmc/utils/Stopwatch.h b/xbmc/utils/Stopwatch.h new file mode 100644 index 0000000..186a54c --- /dev/null +++ b/xbmc/utils/Stopwatch.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +class CStopWatch +{ +public: + explicit CStopWatch(bool useFrameTime=false); + ~CStopWatch(); + + /*! + \brief Retrieve the running state of the stopwatch. + + \return True if stopwatch has been started but not stopped. + */ + inline bool IsRunning() const + { + return m_isRunning; + } + + /*! + \brief Record start time and change state to running. + */ + inline void StartZero() + { + m_startTick = GetTicks(); + m_isRunning = true; + } + + /*! + \brief Record start time and change state to running, only if the stopwatch is stopped. + */ + inline void Start() + { + if (!m_isRunning) + StartZero(); + } + + /*! + \brief Record stop time and change state to not running. + */ + inline void Stop() + { + if(m_isRunning) + { + m_stopTick = GetTicks(); + m_isRunning = false; + } + } + + /*! + \brief Set the start time such that time elapsed is now zero. + */ + void Reset() + { + if (m_isRunning) + m_startTick = GetTicks(); + else + m_startTick = m_stopTick; + } + + /*! + \brief Retrieve time elapsed between the last call to Start(), StartZero() + or Reset() and; if running, now; if stopped, the last call to Stop(). + + \return Elapsed time, in seconds, as a float. + */ + float GetElapsedSeconds() const + { + int64_t totalTicks = (m_isRunning ? GetTicks() : m_stopTick) - m_startTick; + return (float)totalTicks * m_timerPeriod; + } + + /*! + \brief Retrieve time elapsed between the last call to Start(), StartZero() + or Reset() and; if running, now; if stopped, the last call to Stop(). + + \return Elapsed time, in milliseconds, as a float. + */ + float GetElapsedMilliseconds() const + { + return GetElapsedSeconds() * 1000.0f; + } + +private: + int64_t GetTicks() const; + float m_timerPeriod; // to save division in GetElapsed...() + int64_t m_startTick; + int64_t m_stopTick; + bool m_isRunning; + bool m_useFrameTime; +}; diff --git a/xbmc/utils/StreamDetails.cpp b/xbmc/utils/StreamDetails.cpp new file mode 100644 index 0000000..558af46 --- /dev/null +++ b/xbmc/utils/StreamDetails.cpp @@ -0,0 +1,627 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "StreamDetails.h" + +#include "LangInfo.h" +#include "StreamUtils.h" +#include "cores/VideoPlayer/Interface/StreamInfo.h" +#include "utils/Archive.h" +#include "utils/LangCodeExpander.h" +#include "utils/Variant.h" + +#include + +const float VIDEOASPECT_EPSILON = 0.025f; + +CStreamDetailVideo::CStreamDetailVideo() : + CStreamDetail(CStreamDetail::VIDEO) +{ +} + +CStreamDetailVideo::CStreamDetailVideo(const VideoStreamInfo &info, int duration) : + CStreamDetail(CStreamDetail::VIDEO), + m_iWidth(info.width), + m_iHeight(info.height), + m_fAspect(info.videoAspectRatio), + m_iDuration(duration), + m_strCodec(info.codecName), + m_strStereoMode(info.stereoMode), + m_strLanguage(info.language) +{ +} + +void CStreamDetailVideo::Archive(CArchive& ar) +{ + if (ar.IsStoring()) + { + ar << m_strCodec; + ar << m_fAspect; + ar << m_iHeight; + ar << m_iWidth; + ar << m_iDuration; + ar << m_strStereoMode; + ar << m_strLanguage; + } + else + { + ar >> m_strCodec; + ar >> m_fAspect; + ar >> m_iHeight; + ar >> m_iWidth; + ar >> m_iDuration; + ar >> m_strStereoMode; + ar >> m_strLanguage; + } +} +void CStreamDetailVideo::Serialize(CVariant& value) const +{ + value["codec"] = m_strCodec; + value["aspect"] = m_fAspect; + value["height"] = m_iHeight; + value["width"] = m_iWidth; + value["duration"] = m_iDuration; + value["stereomode"] = m_strStereoMode; + value["language"] = m_strLanguage; +} + +bool CStreamDetailVideo::IsWorseThan(const CStreamDetail &that) const +{ + if (that.m_eType != CStreamDetail::VIDEO) + return true; + + // Best video stream is that with the most pixels + auto &sdv = static_cast(that); + return (sdv.m_iWidth * sdv.m_iHeight) > (m_iWidth * m_iHeight); +} + +CStreamDetailAudio::CStreamDetailAudio() : + CStreamDetail(CStreamDetail::AUDIO) +{ +} + +CStreamDetailAudio::CStreamDetailAudio(const AudioStreamInfo &info) : + CStreamDetail(CStreamDetail::AUDIO), + m_iChannels(info.channels), + m_strCodec(info.codecName), + m_strLanguage(info.language) +{ +} + +void CStreamDetailAudio::Archive(CArchive& ar) +{ + if (ar.IsStoring()) + { + ar << m_strCodec; + ar << m_strLanguage; + ar << m_iChannels; + } + else + { + ar >> m_strCodec; + ar >> m_strLanguage; + ar >> m_iChannels; + } +} +void CStreamDetailAudio::Serialize(CVariant& value) const +{ + value["codec"] = m_strCodec; + value["language"] = m_strLanguage; + value["channels"] = m_iChannels; +} + +bool CStreamDetailAudio::IsWorseThan(const CStreamDetail &that) const +{ + if (that.m_eType != CStreamDetail::AUDIO) + return true; + + auto &sda = static_cast(that); + // First choice is the thing with the most channels + if (sda.m_iChannels > m_iChannels) + return true; + if (m_iChannels > sda.m_iChannels) + return false; + + // In case of a tie, revert to codec priority + return StreamUtils::GetCodecPriority(sda.m_strCodec) > StreamUtils::GetCodecPriority(m_strCodec); +} + +CStreamDetailSubtitle::CStreamDetailSubtitle() : + CStreamDetail(CStreamDetail::SUBTITLE) +{ +} + +CStreamDetailSubtitle::CStreamDetailSubtitle(const SubtitleStreamInfo &info) : + CStreamDetail(CStreamDetail::SUBTITLE), + m_strLanguage(info.language) +{ +} + +void CStreamDetailSubtitle::Archive(CArchive& ar) +{ + if (ar.IsStoring()) + { + ar << m_strLanguage; + } + else + { + ar >> m_strLanguage; + } +} +void CStreamDetailSubtitle::Serialize(CVariant& value) const +{ + value["language"] = m_strLanguage; +} + +bool CStreamDetailSubtitle::IsWorseThan(const CStreamDetail &that) const +{ + if (that.m_eType != CStreamDetail::SUBTITLE) + return true; + + if (g_LangCodeExpander.CompareISO639Codes(m_strLanguage, static_cast(that).m_strLanguage)) + return false; + + // the best subtitle should be the one in the user's preferred language + // If preferred language is set to "original" this is "eng" + return m_strLanguage.empty() || + g_LangCodeExpander.CompareISO639Codes(static_cast(that).m_strLanguage, g_langInfo.GetSubtitleLanguage()); +} + +CStreamDetailSubtitle& CStreamDetailSubtitle::operator=(const CStreamDetailSubtitle &that) +{ + if (this != &that) + { + this->m_pParent = that.m_pParent; + this->m_strLanguage = that.m_strLanguage; + } + return *this; +} + +CStreamDetails& CStreamDetails::operator=(const CStreamDetails &that) +{ + if (this != &that) + { + Reset(); + for (const auto &iter : that.m_vecItems) + { + switch (iter->m_eType) + { + case CStreamDetail::VIDEO: + AddStream(new CStreamDetailVideo(static_cast(*iter))); + break; + case CStreamDetail::AUDIO: + AddStream(new CStreamDetailAudio(static_cast(*iter))); + break; + case CStreamDetail::SUBTITLE: + AddStream(new CStreamDetailSubtitle(static_cast(*iter))); + break; + } + } + + DetermineBestStreams(); + } /* if this != that */ + + return *this; +} + +bool CStreamDetails::operator ==(const CStreamDetails &right) const +{ + if (this == &right) return true; + + if (GetVideoStreamCount() != right.GetVideoStreamCount() || + GetAudioStreamCount() != right.GetAudioStreamCount() || + GetSubtitleStreamCount() != right.GetSubtitleStreamCount()) + return false; + + for (int iStream=1; iStream<=GetVideoStreamCount(); iStream++) + { + if (GetVideoCodec(iStream) != right.GetVideoCodec(iStream) || + GetVideoWidth(iStream) != right.GetVideoWidth(iStream) || + GetVideoHeight(iStream) != right.GetVideoHeight(iStream) || + GetVideoDuration(iStream) != right.GetVideoDuration(iStream) || + fabs(GetVideoAspect(iStream) - right.GetVideoAspect(iStream)) > VIDEOASPECT_EPSILON) + return false; + } + + for (int iStream=1; iStream<=GetAudioStreamCount(); iStream++) + { + if (GetAudioCodec(iStream) != right.GetAudioCodec(iStream) || + GetAudioLanguage(iStream) != right.GetAudioLanguage(iStream) || + GetAudioChannels(iStream) != right.GetAudioChannels(iStream) ) + return false; + } + + for (int iStream=1; iStream<=GetSubtitleStreamCount(); iStream++) + { + if (GetSubtitleLanguage(iStream) != right.GetSubtitleLanguage(iStream) ) + return false; + } + + return true; +} + +bool CStreamDetails::operator !=(const CStreamDetails &right) const +{ + if (this == &right) return false; + + return !(*this == right); +} + +CStreamDetail *CStreamDetails::NewStream(CStreamDetail::StreamType type) +{ + CStreamDetail *retVal = NULL; + switch (type) + { + case CStreamDetail::VIDEO: + retVal = new CStreamDetailVideo(); + break; + case CStreamDetail::AUDIO: + retVal = new CStreamDetailAudio(); + break; + case CStreamDetail::SUBTITLE: + retVal = new CStreamDetailSubtitle(); + break; + } + + if (retVal) + AddStream(retVal); + + return retVal; +} + +std::string CStreamDetails::GetVideoLanguage(int idx) const +{ + const CStreamDetailVideo *item = static_cast(GetNthStream(CStreamDetail::VIDEO, idx)); + if (item) + return item->m_strLanguage; + else + return ""; +} + +int CStreamDetails::GetStreamCount(CStreamDetail::StreamType type) const +{ + int retVal = 0; + for (const auto &iter : m_vecItems) + if (iter->m_eType == type) + retVal++; + return retVal; +} + +int CStreamDetails::GetVideoStreamCount(void) const +{ + return GetStreamCount(CStreamDetail::VIDEO); +} + +int CStreamDetails::GetAudioStreamCount(void) const +{ + return GetStreamCount(CStreamDetail::AUDIO); +} + +int CStreamDetails::GetSubtitleStreamCount(void) const +{ + return GetStreamCount(CStreamDetail::SUBTITLE); +} + +CStreamDetails::CStreamDetails(const CStreamDetails &that) +{ + m_pBestVideo = nullptr; + m_pBestAudio = nullptr; + m_pBestSubtitle = nullptr; + *this = that; +} + +void CStreamDetails::AddStream(CStreamDetail *item) +{ + item->m_pParent = this; + m_vecItems.emplace_back(item); +} + +void CStreamDetails::Reset(void) +{ + m_pBestVideo = nullptr; + m_pBestAudio = nullptr; + m_pBestSubtitle = nullptr; + + m_vecItems.clear(); +} + +const CStreamDetail* CStreamDetails::GetNthStream(CStreamDetail::StreamType type, int idx) const +{ + if (idx == 0) + { + switch (type) + { + case CStreamDetail::VIDEO: + return m_pBestVideo; + break; + case CStreamDetail::AUDIO: + return m_pBestAudio; + break; + case CStreamDetail::SUBTITLE: + return m_pBestSubtitle; + break; + default: + return NULL; + break; + } + } + + for (const auto &iter : m_vecItems) + if (iter->m_eType == type) + { + idx--; + if (idx < 1) + return iter.get(); + } + + return NULL; +} + +std::string CStreamDetails::GetVideoCodec(int idx) const +{ + const CStreamDetailVideo *item = static_cast(GetNthStream(CStreamDetail::VIDEO, idx)); + if (item) + return item->m_strCodec; + else + return ""; +} + +float CStreamDetails::GetVideoAspect(int idx) const +{ + const CStreamDetailVideo *item = static_cast(GetNthStream(CStreamDetail::VIDEO, idx)); + if (item) + return item->m_fAspect; + else + return 0.0; +} + +int CStreamDetails::GetVideoWidth(int idx) const +{ + const CStreamDetailVideo *item = static_cast(GetNthStream(CStreamDetail::VIDEO, idx)); + if (item) + return item->m_iWidth; + else + return 0; +} + +int CStreamDetails::GetVideoHeight(int idx) const +{ + const CStreamDetailVideo *item = static_cast(GetNthStream(CStreamDetail::VIDEO, idx)); + if (item) + return item->m_iHeight; + else + return 0; +} + +int CStreamDetails::GetVideoDuration(int idx) const +{ + const CStreamDetailVideo *item = static_cast(GetNthStream(CStreamDetail::VIDEO, idx)); + if (item) + return item->m_iDuration; + else + return 0; +} + +void CStreamDetails::SetVideoDuration(int idx, const int duration) +{ + CStreamDetailVideo *item = const_cast(static_cast(GetNthStream(CStreamDetail::VIDEO, idx))); + if (item) + item->m_iDuration = duration; +} + +std::string CStreamDetails::GetStereoMode(int idx) const +{ + const CStreamDetailVideo *item = static_cast(GetNthStream(CStreamDetail::VIDEO, idx)); + if (item) + return item->m_strStereoMode; + else + return ""; +} + +std::string CStreamDetails::GetAudioCodec(int idx) const +{ + const CStreamDetailAudio *item = static_cast(GetNthStream(CStreamDetail::AUDIO, idx)); + if (item) + return item->m_strCodec; + else + return ""; +} + +std::string CStreamDetails::GetAudioLanguage(int idx) const +{ + const CStreamDetailAudio *item = static_cast(GetNthStream(CStreamDetail::AUDIO, idx)); + if (item) + return item->m_strLanguage; + else + return ""; +} + +int CStreamDetails::GetAudioChannels(int idx) const +{ + const CStreamDetailAudio *item = static_cast(GetNthStream(CStreamDetail::AUDIO, idx)); + if (item) + return item->m_iChannels; + else + return -1; +} + +std::string CStreamDetails::GetSubtitleLanguage(int idx) const +{ + const CStreamDetailSubtitle *item = static_cast(GetNthStream(CStreamDetail::SUBTITLE, idx)); + if (item) + return item->m_strLanguage; + else + return ""; +} + +void CStreamDetails::Archive(CArchive& ar) +{ + if (ar.IsStoring()) + { + ar << (int)m_vecItems.size(); + + for (auto &iter : m_vecItems) + { + // the type goes before the actual item. When loading we need + // to know the type before we can construct an instance to serialize + ar << (int)iter->m_eType; + ar << (*iter); + } + } + else + { + int count; + ar >> count; + + Reset(); + for (int i=0; i> type; + p = NewStream(CStreamDetail::StreamType(type)); + if (p) + ar >> (*p); + } + + DetermineBestStreams(); + } +} +void CStreamDetails::Serialize(CVariant& value) const +{ + // make sure these properties are always present + value["audio"] = CVariant(CVariant::VariantTypeArray); + value["video"] = CVariant(CVariant::VariantTypeArray); + value["subtitle"] = CVariant(CVariant::VariantTypeArray); + + CVariant v; + for (const auto &iter : m_vecItems) + { + v.clear(); + iter->Serialize(v); + switch (iter->m_eType) + { + case CStreamDetail::AUDIO: + value["audio"].push_back(v); + break; + case CStreamDetail::VIDEO: + value["video"].push_back(v); + break; + case CStreamDetail::SUBTITLE: + value["subtitle"].push_back(v); + break; + } + } +} + +void CStreamDetails::DetermineBestStreams(void) +{ + m_pBestVideo = NULL; + m_pBestAudio = NULL; + m_pBestSubtitle = NULL; + + for (const auto &iter : m_vecItems) + { + const CStreamDetail **champion; + switch (iter->m_eType) + { + case CStreamDetail::VIDEO: + champion = (const CStreamDetail **)&m_pBestVideo; + break; + case CStreamDetail::AUDIO: + champion = (const CStreamDetail **)&m_pBestAudio; + break; + case CStreamDetail::SUBTITLE: + champion = (const CStreamDetail **)&m_pBestSubtitle; + break; + default: + champion = NULL; + } /* switch type */ + + if (!champion) + continue; + + if ((*champion == NULL) || (*champion)->IsWorseThan(*iter)) + *champion = iter.get(); + } /* for each */ +} + +std::string CStreamDetails::VideoDimsToResolutionDescription(int iWidth, int iHeight) +{ + if (iWidth == 0 || iHeight == 0) + return ""; + + else if (iWidth <= 720 && iHeight <= 480) + return "480"; + // 720x576 (PAL) (768 when rescaled for square pixels) + else if (iWidth <= 768 && iHeight <= 576) + return "576"; + // 960x540 (sometimes 544 which is multiple of 16) + else if (iWidth <= 960 && iHeight <= 544) + return "540"; + // 1280x720 + else if (iWidth <= 1280 && iHeight <= 720) + return "720"; + // 1920x1080 + else if (iWidth <= 1920 && iHeight <= 1080) + return "1080"; + // 4K + else if (iWidth <= 4096 && iHeight <= 2160) + return "4K"; + // 8K + else if (iWidth <= 8192 && iHeight <= 4320) + return "8K"; + else + return ""; +} + +std::string CStreamDetails::VideoAspectToAspectDescription(float fAspect) +{ + if (fAspect == 0.0f) + return ""; + + // Given that we're never going to be able to handle every single possibility in + // aspect ratios, particularly when cropping prior to video encoding is taken into account + // the best we can do is take the "common" aspect ratios, and return the closest one available. + // The cutoffs are the geometric mean of the two aspect ratios either side. + if (fAspect < 1.3499f) // sqrt(1.33*1.37) + return "1.33"; + else if (fAspect < 1.5080f) // sqrt(1.37*1.66) + return "1.37"; + else if (fAspect < 1.7190f) // sqrt(1.66*1.78) + return "1.66"; + else if (fAspect < 1.8147f) // sqrt(1.78*1.85) + return "1.78"; + else if (fAspect < 2.0174f) // sqrt(1.85*2.20) + return "1.85"; + else if (fAspect < 2.2738f) // sqrt(2.20*2.35) + return "2.20"; + else if (fAspect < 2.3749f) // sqrt(2.35*2.40) + return "2.35"; + else if (fAspect < 2.4739f) // sqrt(2.40*2.55) + return "2.40"; + else if (fAspect < 2.6529f) // sqrt(2.55*2.76) + return "2.55"; + return "2.76"; +} + +bool CStreamDetails::SetStreams(const VideoStreamInfo& videoInfo, int videoDuration, const AudioStreamInfo& audioInfo, const SubtitleStreamInfo& subtitleInfo) +{ + if (!videoInfo.valid && !audioInfo.valid && !subtitleInfo.valid) + return false; + Reset(); + if (videoInfo.valid) + AddStream(new CStreamDetailVideo(videoInfo, videoDuration)); + if (audioInfo.valid) + AddStream(new CStreamDetailAudio(audioInfo)); + if (subtitleInfo.valid) + AddStream(new CStreamDetailSubtitle(subtitleInfo)); + DetermineBestStreams(); + return true; +} diff --git a/xbmc/utils/StreamDetails.h b/xbmc/utils/StreamDetails.h new file mode 100644 index 0000000..fae9d46 --- /dev/null +++ b/xbmc/utils/StreamDetails.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "ISerializable.h" +#include "utils/IArchivable.h" + +#include +#include +#include + +class CStreamDetails; +class CVariant; +struct VideoStreamInfo; +struct AudioStreamInfo; +struct SubtitleStreamInfo; + +class CStreamDetail : public IArchivable, public ISerializable +{ +public: + enum StreamType { + VIDEO, + AUDIO, + SUBTITLE + }; + + explicit CStreamDetail(StreamType type) : m_eType(type), m_pParent(NULL) {}; + virtual ~CStreamDetail() = default; + virtual bool IsWorseThan(const CStreamDetail &that) const = 0; + + const StreamType m_eType; + +protected: + CStreamDetails *m_pParent; + friend class CStreamDetails; +}; + +class CStreamDetailVideo final : public CStreamDetail +{ +public: + CStreamDetailVideo(); + CStreamDetailVideo(const VideoStreamInfo &info, int duration = 0); + void Archive(CArchive& ar) override; + void Serialize(CVariant& value) const override; + bool IsWorseThan(const CStreamDetail &that) const override; + + int m_iWidth = 0; + int m_iHeight = 0; + float m_fAspect = 0.0; + int m_iDuration = 0; + std::string m_strCodec; + std::string m_strStereoMode; + std::string m_strLanguage; +}; + +class CStreamDetailAudio final : public CStreamDetail +{ +public: + CStreamDetailAudio(); + CStreamDetailAudio(const AudioStreamInfo &info); + void Archive(CArchive& ar) override; + void Serialize(CVariant& value) const override; + bool IsWorseThan(const CStreamDetail &that) const override; + + int m_iChannels = -1; + std::string m_strCodec; + std::string m_strLanguage; +}; + +class CStreamDetailSubtitle final : public CStreamDetail +{ +public: + CStreamDetailSubtitle(); + CStreamDetailSubtitle(const SubtitleStreamInfo &info); + CStreamDetailSubtitle& operator=(const CStreamDetailSubtitle &that); + void Archive(CArchive& ar) override; + void Serialize(CVariant& value) const override; + bool IsWorseThan(const CStreamDetail &that) const override; + + std::string m_strLanguage; +}; + +class CStreamDetails final : public IArchivable, public ISerializable +{ +public: + CStreamDetails() { Reset(); }; + CStreamDetails(const CStreamDetails &that); + CStreamDetails& operator=(const CStreamDetails &that); + bool operator ==(const CStreamDetails &that) const; + bool operator !=(const CStreamDetails &that) const; + + static std::string VideoDimsToResolutionDescription(int iWidth, int iHeight); + static std::string VideoAspectToAspectDescription(float fAspect); + + bool HasItems(void) const { return m_vecItems.size() > 0; }; + int GetStreamCount(CStreamDetail::StreamType type) const; + int GetVideoStreamCount(void) const; + int GetAudioStreamCount(void) const; + int GetSubtitleStreamCount(void) const; + const CStreamDetail* GetNthStream(CStreamDetail::StreamType type, int idx) const; + + std::string GetVideoCodec(int idx = 0) const; + float GetVideoAspect(int idx = 0) const; + int GetVideoWidth(int idx = 0) const; + int GetVideoHeight(int idx = 0) const; + int GetVideoDuration(int idx = 0) const; + void SetVideoDuration(int idx, const int duration); + std::string GetStereoMode(int idx = 0) const; + std::string GetVideoLanguage(int idx = 0) const; + + std::string GetAudioCodec(int idx = 0) const; + std::string GetAudioLanguage(int idx = 0) const; + int GetAudioChannels(int idx = 0) const; + + std::string GetSubtitleLanguage(int idx = 0) const; + + void AddStream(CStreamDetail *item); + void Reset(void); + void DetermineBestStreams(void); + + void Archive(CArchive& ar) override; + void Serialize(CVariant& value) const override; + + bool SetStreams(const VideoStreamInfo& videoInfo, int videoDuration, const AudioStreamInfo& audioInfo, const SubtitleStreamInfo& subtitleInfo); +private: + CStreamDetail *NewStream(CStreamDetail::StreamType type); + std::vector> m_vecItems; + const CStreamDetailVideo *m_pBestVideo; + const CStreamDetailAudio *m_pBestAudio; + const CStreamDetailSubtitle *m_pBestSubtitle; +}; diff --git a/xbmc/utils/StreamUtils.cpp b/xbmc/utils/StreamUtils.cpp new file mode 100644 index 0000000..bd34fec --- /dev/null +++ b/xbmc/utils/StreamUtils.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "StreamUtils.h" + +int StreamUtils::GetCodecPriority(const std::string &codec) +{ + /* + * Technically flac, truehd, and dtshd_ma are equivalently good as they're all lossless. However, + * ffmpeg can't decode dtshd_ma losslessy yet. + */ + if (codec == "flac") // Lossless FLAC + return 7; + if (codec == "truehd") // Dolby TrueHD + return 6; + if (codec == "dtshd_ma") // DTS-HD Master Audio (previously known as DTS++) + return 5; + if (codec == "dtshd_hra") // DTS-HD High Resolution Audio + return 4; + if (codec == "eac3") // Dolby Digital Plus + return 3; + if (codec == "dca") // DTS + return 2; + if (codec == "ac3") // Dolby Digital + return 1; + return 0; +} diff --git a/xbmc/utils/StreamUtils.h b/xbmc/utils/StreamUtils.h new file mode 100644 index 0000000..e4c2f66 --- /dev/null +++ b/xbmc/utils/StreamUtils.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +class StreamUtils +{ +public: + static int GetCodecPriority(const std::string &codec); +}; diff --git a/xbmc/utils/StringUtils.cpp b/xbmc/utils/StringUtils.cpp new file mode 100644 index 0000000..4195b18 --- /dev/null +++ b/xbmc/utils/StringUtils.cpp @@ -0,0 +1,1808 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ +//----------------------------------------------------------------------- +// +// File: StringUtils.cpp +// +// Purpose: ATL split string utility +// Author: Paul J. Weiss +// +// Modified to use J O'Leary's std::string class by kraqh3d +// +//------------------------------------------------------------------------ + +#ifdef HAVE_NEW_CROSSGUID +#include +#else +#include +#endif + +#if defined(TARGET_ANDROID) +#include +#endif + +#include "CharsetConverter.h" +#include "LangInfo.h" +#include "StringUtils.h" +#include "Util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// don't move or std functions end up in PCRE namespace +// clang-format off +#include "utils/RegExp.h" +// clang-format on + +#define FORMAT_BLOCK_SIZE 512 // # of bytes for initial allocation for printf + +static constexpr const char* ADDON_GUID_RE = "^(\\{){0,1}[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}(\\}){0,1}$"; + +/* empty string for use in returns by ref */ +const std::string StringUtils::Empty = ""; + +// Copyright (c) Leigh Brasington 2012. All rights reserved. +// This code may be used and reproduced without written permission. +// http://www.leighb.com/tounicupper.htm +// +// The tables were constructed from +// http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Fnls%2Frbagslowtoupmaptable.htm + +static constexpr wchar_t unicode_lowers[] = { + (wchar_t)0x0061, (wchar_t)0x0062, (wchar_t)0x0063, (wchar_t)0x0064, (wchar_t)0x0065, (wchar_t)0x0066, (wchar_t)0x0067, (wchar_t)0x0068, (wchar_t)0x0069, + (wchar_t)0x006A, (wchar_t)0x006B, (wchar_t)0x006C, (wchar_t)0x006D, (wchar_t)0x006E, (wchar_t)0x006F, (wchar_t)0x0070, (wchar_t)0x0071, (wchar_t)0x0072, + (wchar_t)0x0073, (wchar_t)0x0074, (wchar_t)0x0075, (wchar_t)0x0076, (wchar_t)0x0077, (wchar_t)0x0078, (wchar_t)0x0079, (wchar_t)0x007A, (wchar_t)0x00E0, + (wchar_t)0x00E1, (wchar_t)0x00E2, (wchar_t)0x00E3, (wchar_t)0x00E4, (wchar_t)0x00E5, (wchar_t)0x00E6, (wchar_t)0x00E7, (wchar_t)0x00E8, (wchar_t)0x00E9, + (wchar_t)0x00EA, (wchar_t)0x00EB, (wchar_t)0x00EC, (wchar_t)0x00ED, (wchar_t)0x00EE, (wchar_t)0x00EF, (wchar_t)0x00F0, (wchar_t)0x00F1, (wchar_t)0x00F2, + (wchar_t)0x00F3, (wchar_t)0x00F4, (wchar_t)0x00F5, (wchar_t)0x00F6, (wchar_t)0x00F8, (wchar_t)0x00F9, (wchar_t)0x00FA, (wchar_t)0x00FB, (wchar_t)0x00FC, + (wchar_t)0x00FD, (wchar_t)0x00FE, (wchar_t)0x00FF, (wchar_t)0x0101, (wchar_t)0x0103, (wchar_t)0x0105, (wchar_t)0x0107, (wchar_t)0x0109, (wchar_t)0x010B, + (wchar_t)0x010D, (wchar_t)0x010F, (wchar_t)0x0111, (wchar_t)0x0113, (wchar_t)0x0115, (wchar_t)0x0117, (wchar_t)0x0119, (wchar_t)0x011B, (wchar_t)0x011D, + (wchar_t)0x011F, (wchar_t)0x0121, (wchar_t)0x0123, (wchar_t)0x0125, (wchar_t)0x0127, (wchar_t)0x0129, (wchar_t)0x012B, (wchar_t)0x012D, (wchar_t)0x012F, + (wchar_t)0x0131, (wchar_t)0x0133, (wchar_t)0x0135, (wchar_t)0x0137, (wchar_t)0x013A, (wchar_t)0x013C, (wchar_t)0x013E, (wchar_t)0x0140, (wchar_t)0x0142, + (wchar_t)0x0144, (wchar_t)0x0146, (wchar_t)0x0148, (wchar_t)0x014B, (wchar_t)0x014D, (wchar_t)0x014F, (wchar_t)0x0151, (wchar_t)0x0153, (wchar_t)0x0155, + (wchar_t)0x0157, (wchar_t)0x0159, (wchar_t)0x015B, (wchar_t)0x015D, (wchar_t)0x015F, (wchar_t)0x0161, (wchar_t)0x0163, (wchar_t)0x0165, (wchar_t)0x0167, + (wchar_t)0x0169, (wchar_t)0x016B, (wchar_t)0x016D, (wchar_t)0x016F, (wchar_t)0x0171, (wchar_t)0x0173, (wchar_t)0x0175, (wchar_t)0x0177, (wchar_t)0x017A, + (wchar_t)0x017C, (wchar_t)0x017E, (wchar_t)0x0183, (wchar_t)0x0185, (wchar_t)0x0188, (wchar_t)0x018C, (wchar_t)0x0192, (wchar_t)0x0199, (wchar_t)0x01A1, + (wchar_t)0x01A3, (wchar_t)0x01A5, (wchar_t)0x01A8, (wchar_t)0x01AD, (wchar_t)0x01B0, (wchar_t)0x01B4, (wchar_t)0x01B6, (wchar_t)0x01B9, (wchar_t)0x01BD, + (wchar_t)0x01C6, (wchar_t)0x01C9, (wchar_t)0x01CC, (wchar_t)0x01CE, (wchar_t)0x01D0, (wchar_t)0x01D2, (wchar_t)0x01D4, (wchar_t)0x01D6, (wchar_t)0x01D8, + (wchar_t)0x01DA, (wchar_t)0x01DC, (wchar_t)0x01DF, (wchar_t)0x01E1, (wchar_t)0x01E3, (wchar_t)0x01E5, (wchar_t)0x01E7, (wchar_t)0x01E9, (wchar_t)0x01EB, + (wchar_t)0x01ED, (wchar_t)0x01EF, (wchar_t)0x01F3, (wchar_t)0x01F5, (wchar_t)0x01FB, (wchar_t)0x01FD, (wchar_t)0x01FF, (wchar_t)0x0201, (wchar_t)0x0203, + (wchar_t)0x0205, (wchar_t)0x0207, (wchar_t)0x0209, (wchar_t)0x020B, (wchar_t)0x020D, (wchar_t)0x020F, (wchar_t)0x0211, (wchar_t)0x0213, (wchar_t)0x0215, + (wchar_t)0x0217, (wchar_t)0x0253, (wchar_t)0x0254, (wchar_t)0x0257, (wchar_t)0x0258, (wchar_t)0x0259, (wchar_t)0x025B, (wchar_t)0x0260, (wchar_t)0x0263, + (wchar_t)0x0268, (wchar_t)0x0269, (wchar_t)0x026F, (wchar_t)0x0272, (wchar_t)0x0275, (wchar_t)0x0283, (wchar_t)0x0288, (wchar_t)0x028A, (wchar_t)0x028B, + (wchar_t)0x0292, (wchar_t)0x03AC, (wchar_t)0x03AD, (wchar_t)0x03AE, (wchar_t)0x03AF, (wchar_t)0x03B1, (wchar_t)0x03B2, (wchar_t)0x03B3, (wchar_t)0x03B4, + (wchar_t)0x03B5, (wchar_t)0x03B6, (wchar_t)0x03B7, (wchar_t)0x03B8, (wchar_t)0x03B9, (wchar_t)0x03BA, (wchar_t)0x03BB, (wchar_t)0x03BC, (wchar_t)0x03BD, + (wchar_t)0x03BE, (wchar_t)0x03BF, (wchar_t)0x03C0, (wchar_t)0x03C1, (wchar_t)0x03C3, (wchar_t)0x03C4, (wchar_t)0x03C5, (wchar_t)0x03C6, (wchar_t)0x03C7, + (wchar_t)0x03C8, (wchar_t)0x03C9, (wchar_t)0x03CA, (wchar_t)0x03CB, (wchar_t)0x03CC, (wchar_t)0x03CD, (wchar_t)0x03CE, (wchar_t)0x03E3, (wchar_t)0x03E5, + (wchar_t)0x03E7, (wchar_t)0x03E9, (wchar_t)0x03EB, (wchar_t)0x03ED, (wchar_t)0x03EF, (wchar_t)0x0430, (wchar_t)0x0431, (wchar_t)0x0432, (wchar_t)0x0433, + (wchar_t)0x0434, (wchar_t)0x0435, (wchar_t)0x0436, (wchar_t)0x0437, (wchar_t)0x0438, (wchar_t)0x0439, (wchar_t)0x043A, (wchar_t)0x043B, (wchar_t)0x043C, + (wchar_t)0x043D, (wchar_t)0x043E, (wchar_t)0x043F, (wchar_t)0x0440, (wchar_t)0x0441, (wchar_t)0x0442, (wchar_t)0x0443, (wchar_t)0x0444, (wchar_t)0x0445, + (wchar_t)0x0446, (wchar_t)0x0447, (wchar_t)0x0448, (wchar_t)0x0449, (wchar_t)0x044A, (wchar_t)0x044B, (wchar_t)0x044C, (wchar_t)0x044D, (wchar_t)0x044E, + (wchar_t)0x044F, (wchar_t)0x0451, (wchar_t)0x0452, (wchar_t)0x0453, (wchar_t)0x0454, (wchar_t)0x0455, (wchar_t)0x0456, (wchar_t)0x0457, (wchar_t)0x0458, + (wchar_t)0x0459, (wchar_t)0x045A, (wchar_t)0x045B, (wchar_t)0x045C, (wchar_t)0x045E, (wchar_t)0x045F, (wchar_t)0x0461, (wchar_t)0x0463, (wchar_t)0x0465, + (wchar_t)0x0467, (wchar_t)0x0469, (wchar_t)0x046B, (wchar_t)0x046D, (wchar_t)0x046F, (wchar_t)0x0471, (wchar_t)0x0473, (wchar_t)0x0475, (wchar_t)0x0477, + (wchar_t)0x0479, (wchar_t)0x047B, (wchar_t)0x047D, (wchar_t)0x047F, (wchar_t)0x0481, (wchar_t)0x0491, (wchar_t)0x0493, (wchar_t)0x0495, (wchar_t)0x0497, + (wchar_t)0x0499, (wchar_t)0x049B, (wchar_t)0x049D, (wchar_t)0x049F, (wchar_t)0x04A1, (wchar_t)0x04A3, (wchar_t)0x04A5, (wchar_t)0x04A7, (wchar_t)0x04A9, + (wchar_t)0x04AB, (wchar_t)0x04AD, (wchar_t)0x04AF, (wchar_t)0x04B1, (wchar_t)0x04B3, (wchar_t)0x04B5, (wchar_t)0x04B7, (wchar_t)0x04B9, (wchar_t)0x04BB, + (wchar_t)0x04BD, (wchar_t)0x04BF, (wchar_t)0x04C2, (wchar_t)0x04C4, (wchar_t)0x04C8, (wchar_t)0x04CC, (wchar_t)0x04D1, (wchar_t)0x04D3, (wchar_t)0x04D5, + (wchar_t)0x04D7, (wchar_t)0x04D9, (wchar_t)0x04DB, (wchar_t)0x04DD, (wchar_t)0x04DF, (wchar_t)0x04E1, (wchar_t)0x04E3, (wchar_t)0x04E5, (wchar_t)0x04E7, + (wchar_t)0x04E9, (wchar_t)0x04EB, (wchar_t)0x04EF, (wchar_t)0x04F1, (wchar_t)0x04F3, (wchar_t)0x04F5, (wchar_t)0x04F9, (wchar_t)0x0561, (wchar_t)0x0562, + (wchar_t)0x0563, (wchar_t)0x0564, (wchar_t)0x0565, (wchar_t)0x0566, (wchar_t)0x0567, (wchar_t)0x0568, (wchar_t)0x0569, (wchar_t)0x056A, (wchar_t)0x056B, + (wchar_t)0x056C, (wchar_t)0x056D, (wchar_t)0x056E, (wchar_t)0x056F, (wchar_t)0x0570, (wchar_t)0x0571, (wchar_t)0x0572, (wchar_t)0x0573, (wchar_t)0x0574, + (wchar_t)0x0575, (wchar_t)0x0576, (wchar_t)0x0577, (wchar_t)0x0578, (wchar_t)0x0579, (wchar_t)0x057A, (wchar_t)0x057B, (wchar_t)0x057C, (wchar_t)0x057D, + (wchar_t)0x057E, (wchar_t)0x057F, (wchar_t)0x0580, (wchar_t)0x0581, (wchar_t)0x0582, (wchar_t)0x0583, (wchar_t)0x0584, (wchar_t)0x0585, (wchar_t)0x0586, + (wchar_t)0x10D0, (wchar_t)0x10D1, (wchar_t)0x10D2, (wchar_t)0x10D3, (wchar_t)0x10D4, (wchar_t)0x10D5, (wchar_t)0x10D6, (wchar_t)0x10D7, (wchar_t)0x10D8, + (wchar_t)0x10D9, (wchar_t)0x10DA, (wchar_t)0x10DB, (wchar_t)0x10DC, (wchar_t)0x10DD, (wchar_t)0x10DE, (wchar_t)0x10DF, (wchar_t)0x10E0, (wchar_t)0x10E1, + (wchar_t)0x10E2, (wchar_t)0x10E3, (wchar_t)0x10E4, (wchar_t)0x10E5, (wchar_t)0x10E6, (wchar_t)0x10E7, (wchar_t)0x10E8, (wchar_t)0x10E9, (wchar_t)0x10EA, + (wchar_t)0x10EB, (wchar_t)0x10EC, (wchar_t)0x10ED, (wchar_t)0x10EE, (wchar_t)0x10EF, (wchar_t)0x10F0, (wchar_t)0x10F1, (wchar_t)0x10F2, (wchar_t)0x10F3, + (wchar_t)0x10F4, (wchar_t)0x10F5, (wchar_t)0x1E01, (wchar_t)0x1E03, (wchar_t)0x1E05, (wchar_t)0x1E07, (wchar_t)0x1E09, (wchar_t)0x1E0B, (wchar_t)0x1E0D, + (wchar_t)0x1E0F, (wchar_t)0x1E11, (wchar_t)0x1E13, (wchar_t)0x1E15, (wchar_t)0x1E17, (wchar_t)0x1E19, (wchar_t)0x1E1B, (wchar_t)0x1E1D, (wchar_t)0x1E1F, + (wchar_t)0x1E21, (wchar_t)0x1E23, (wchar_t)0x1E25, (wchar_t)0x1E27, (wchar_t)0x1E29, (wchar_t)0x1E2B, (wchar_t)0x1E2D, (wchar_t)0x1E2F, (wchar_t)0x1E31, + (wchar_t)0x1E33, (wchar_t)0x1E35, (wchar_t)0x1E37, (wchar_t)0x1E39, (wchar_t)0x1E3B, (wchar_t)0x1E3D, (wchar_t)0x1E3F, (wchar_t)0x1E41, (wchar_t)0x1E43, + (wchar_t)0x1E45, (wchar_t)0x1E47, (wchar_t)0x1E49, (wchar_t)0x1E4B, (wchar_t)0x1E4D, (wchar_t)0x1E4F, (wchar_t)0x1E51, (wchar_t)0x1E53, (wchar_t)0x1E55, + (wchar_t)0x1E57, (wchar_t)0x1E59, (wchar_t)0x1E5B, (wchar_t)0x1E5D, (wchar_t)0x1E5F, (wchar_t)0x1E61, (wchar_t)0x1E63, (wchar_t)0x1E65, (wchar_t)0x1E67, + (wchar_t)0x1E69, (wchar_t)0x1E6B, (wchar_t)0x1E6D, (wchar_t)0x1E6F, (wchar_t)0x1E71, (wchar_t)0x1E73, (wchar_t)0x1E75, (wchar_t)0x1E77, (wchar_t)0x1E79, + (wchar_t)0x1E7B, (wchar_t)0x1E7D, (wchar_t)0x1E7F, (wchar_t)0x1E81, (wchar_t)0x1E83, (wchar_t)0x1E85, (wchar_t)0x1E87, (wchar_t)0x1E89, (wchar_t)0x1E8B, + (wchar_t)0x1E8D, (wchar_t)0x1E8F, (wchar_t)0x1E91, (wchar_t)0x1E93, (wchar_t)0x1E95, (wchar_t)0x1EA1, (wchar_t)0x1EA3, (wchar_t)0x1EA5, (wchar_t)0x1EA7, + (wchar_t)0x1EA9, (wchar_t)0x1EAB, (wchar_t)0x1EAD, (wchar_t)0x1EAF, (wchar_t)0x1EB1, (wchar_t)0x1EB3, (wchar_t)0x1EB5, (wchar_t)0x1EB7, (wchar_t)0x1EB9, + (wchar_t)0x1EBB, (wchar_t)0x1EBD, (wchar_t)0x1EBF, (wchar_t)0x1EC1, (wchar_t)0x1EC3, (wchar_t)0x1EC5, (wchar_t)0x1EC7, (wchar_t)0x1EC9, (wchar_t)0x1ECB, + (wchar_t)0x1ECD, (wchar_t)0x1ECF, (wchar_t)0x1ED1, (wchar_t)0x1ED3, (wchar_t)0x1ED5, (wchar_t)0x1ED7, (wchar_t)0x1ED9, (wchar_t)0x1EDB, (wchar_t)0x1EDD, + (wchar_t)0x1EDF, (wchar_t)0x1EE1, (wchar_t)0x1EE3, (wchar_t)0x1EE5, (wchar_t)0x1EE7, (wchar_t)0x1EE9, (wchar_t)0x1EEB, (wchar_t)0x1EED, (wchar_t)0x1EEF, + (wchar_t)0x1EF1, (wchar_t)0x1EF3, (wchar_t)0x1EF5, (wchar_t)0x1EF7, (wchar_t)0x1EF9, (wchar_t)0x1F00, (wchar_t)0x1F01, (wchar_t)0x1F02, (wchar_t)0x1F03, + (wchar_t)0x1F04, (wchar_t)0x1F05, (wchar_t)0x1F06, (wchar_t)0x1F07, (wchar_t)0x1F10, (wchar_t)0x1F11, (wchar_t)0x1F12, (wchar_t)0x1F13, (wchar_t)0x1F14, + (wchar_t)0x1F15, (wchar_t)0x1F20, (wchar_t)0x1F21, (wchar_t)0x1F22, (wchar_t)0x1F23, (wchar_t)0x1F24, (wchar_t)0x1F25, (wchar_t)0x1F26, (wchar_t)0x1F27, + (wchar_t)0x1F30, (wchar_t)0x1F31, (wchar_t)0x1F32, (wchar_t)0x1F33, (wchar_t)0x1F34, (wchar_t)0x1F35, (wchar_t)0x1F36, (wchar_t)0x1F37, (wchar_t)0x1F40, + (wchar_t)0x1F41, (wchar_t)0x1F42, (wchar_t)0x1F43, (wchar_t)0x1F44, (wchar_t)0x1F45, (wchar_t)0x1F51, (wchar_t)0x1F53, (wchar_t)0x1F55, (wchar_t)0x1F57, + (wchar_t)0x1F60, (wchar_t)0x1F61, (wchar_t)0x1F62, (wchar_t)0x1F63, (wchar_t)0x1F64, (wchar_t)0x1F65, (wchar_t)0x1F66, (wchar_t)0x1F67, (wchar_t)0x1F80, + (wchar_t)0x1F81, (wchar_t)0x1F82, (wchar_t)0x1F83, (wchar_t)0x1F84, (wchar_t)0x1F85, (wchar_t)0x1F86, (wchar_t)0x1F87, (wchar_t)0x1F90, (wchar_t)0x1F91, + (wchar_t)0x1F92, (wchar_t)0x1F93, (wchar_t)0x1F94, (wchar_t)0x1F95, (wchar_t)0x1F96, (wchar_t)0x1F97, (wchar_t)0x1FA0, (wchar_t)0x1FA1, (wchar_t)0x1FA2, + (wchar_t)0x1FA3, (wchar_t)0x1FA4, (wchar_t)0x1FA5, (wchar_t)0x1FA6, (wchar_t)0x1FA7, (wchar_t)0x1FB0, (wchar_t)0x1FB1, (wchar_t)0x1FD0, (wchar_t)0x1FD1, + (wchar_t)0x1FE0, (wchar_t)0x1FE1, (wchar_t)0x24D0, (wchar_t)0x24D1, (wchar_t)0x24D2, (wchar_t)0x24D3, (wchar_t)0x24D4, (wchar_t)0x24D5, (wchar_t)0x24D6, + (wchar_t)0x24D7, (wchar_t)0x24D8, (wchar_t)0x24D9, (wchar_t)0x24DA, (wchar_t)0x24DB, (wchar_t)0x24DC, (wchar_t)0x24DD, (wchar_t)0x24DE, (wchar_t)0x24DF, + (wchar_t)0x24E0, (wchar_t)0x24E1, (wchar_t)0x24E2, (wchar_t)0x24E3, (wchar_t)0x24E4, (wchar_t)0x24E5, (wchar_t)0x24E6, (wchar_t)0x24E7, (wchar_t)0x24E8, + (wchar_t)0x24E9, (wchar_t)0xFF41, (wchar_t)0xFF42, (wchar_t)0xFF43, (wchar_t)0xFF44, (wchar_t)0xFF45, (wchar_t)0xFF46, (wchar_t)0xFF47, (wchar_t)0xFF48, + (wchar_t)0xFF49, (wchar_t)0xFF4A, (wchar_t)0xFF4B, (wchar_t)0xFF4C, (wchar_t)0xFF4D, (wchar_t)0xFF4E, (wchar_t)0xFF4F, (wchar_t)0xFF50, (wchar_t)0xFF51, + (wchar_t)0xFF52, (wchar_t)0xFF53, (wchar_t)0xFF54, (wchar_t)0xFF55, (wchar_t)0xFF56, (wchar_t)0xFF57, (wchar_t)0xFF58, (wchar_t)0xFF59, (wchar_t)0xFF5A +}; + +static const wchar_t unicode_uppers[] = { + (wchar_t)0x0041, (wchar_t)0x0042, (wchar_t)0x0043, (wchar_t)0x0044, (wchar_t)0x0045, (wchar_t)0x0046, (wchar_t)0x0047, (wchar_t)0x0048, (wchar_t)0x0049, + (wchar_t)0x004A, (wchar_t)0x004B, (wchar_t)0x004C, (wchar_t)0x004D, (wchar_t)0x004E, (wchar_t)0x004F, (wchar_t)0x0050, (wchar_t)0x0051, (wchar_t)0x0052, + (wchar_t)0x0053, (wchar_t)0x0054, (wchar_t)0x0055, (wchar_t)0x0056, (wchar_t)0x0057, (wchar_t)0x0058, (wchar_t)0x0059, (wchar_t)0x005A, (wchar_t)0x00C0, + (wchar_t)0x00C1, (wchar_t)0x00C2, (wchar_t)0x00C3, (wchar_t)0x00C4, (wchar_t)0x00C5, (wchar_t)0x00C6, (wchar_t)0x00C7, (wchar_t)0x00C8, (wchar_t)0x00C9, + (wchar_t)0x00CA, (wchar_t)0x00CB, (wchar_t)0x00CC, (wchar_t)0x00CD, (wchar_t)0x00CE, (wchar_t)0x00CF, (wchar_t)0x00D0, (wchar_t)0x00D1, (wchar_t)0x00D2, + (wchar_t)0x00D3, (wchar_t)0x00D4, (wchar_t)0x00D5, (wchar_t)0x00D6, (wchar_t)0x00D8, (wchar_t)0x00D9, (wchar_t)0x00DA, (wchar_t)0x00DB, (wchar_t)0x00DC, + (wchar_t)0x00DD, (wchar_t)0x00DE, (wchar_t)0x0178, (wchar_t)0x0100, (wchar_t)0x0102, (wchar_t)0x0104, (wchar_t)0x0106, (wchar_t)0x0108, (wchar_t)0x010A, + (wchar_t)0x010C, (wchar_t)0x010E, (wchar_t)0x0110, (wchar_t)0x0112, (wchar_t)0x0114, (wchar_t)0x0116, (wchar_t)0x0118, (wchar_t)0x011A, (wchar_t)0x011C, + (wchar_t)0x011E, (wchar_t)0x0120, (wchar_t)0x0122, (wchar_t)0x0124, (wchar_t)0x0126, (wchar_t)0x0128, (wchar_t)0x012A, (wchar_t)0x012C, (wchar_t)0x012E, + (wchar_t)0x0049, (wchar_t)0x0132, (wchar_t)0x0134, (wchar_t)0x0136, (wchar_t)0x0139, (wchar_t)0x013B, (wchar_t)0x013D, (wchar_t)0x013F, (wchar_t)0x0141, + (wchar_t)0x0143, (wchar_t)0x0145, (wchar_t)0x0147, (wchar_t)0x014A, (wchar_t)0x014C, (wchar_t)0x014E, (wchar_t)0x0150, (wchar_t)0x0152, (wchar_t)0x0154, + (wchar_t)0x0156, (wchar_t)0x0158, (wchar_t)0x015A, (wchar_t)0x015C, (wchar_t)0x015E, (wchar_t)0x0160, (wchar_t)0x0162, (wchar_t)0x0164, (wchar_t)0x0166, + (wchar_t)0x0168, (wchar_t)0x016A, (wchar_t)0x016C, (wchar_t)0x016E, (wchar_t)0x0170, (wchar_t)0x0172, (wchar_t)0x0174, (wchar_t)0x0176, (wchar_t)0x0179, + (wchar_t)0x017B, (wchar_t)0x017D, (wchar_t)0x0182, (wchar_t)0x0184, (wchar_t)0x0187, (wchar_t)0x018B, (wchar_t)0x0191, (wchar_t)0x0198, (wchar_t)0x01A0, + (wchar_t)0x01A2, (wchar_t)0x01A4, (wchar_t)0x01A7, (wchar_t)0x01AC, (wchar_t)0x01AF, (wchar_t)0x01B3, (wchar_t)0x01B5, (wchar_t)0x01B8, (wchar_t)0x01BC, + (wchar_t)0x01C4, (wchar_t)0x01C7, (wchar_t)0x01CA, (wchar_t)0x01CD, (wchar_t)0x01CF, (wchar_t)0x01D1, (wchar_t)0x01D3, (wchar_t)0x01D5, (wchar_t)0x01D7, + (wchar_t)0x01D9, (wchar_t)0x01DB, (wchar_t)0x01DE, (wchar_t)0x01E0, (wchar_t)0x01E2, (wchar_t)0x01E4, (wchar_t)0x01E6, (wchar_t)0x01E8, (wchar_t)0x01EA, + (wchar_t)0x01EC, (wchar_t)0x01EE, (wchar_t)0x01F1, (wchar_t)0x01F4, (wchar_t)0x01FA, (wchar_t)0x01FC, (wchar_t)0x01FE, (wchar_t)0x0200, (wchar_t)0x0202, + (wchar_t)0x0204, (wchar_t)0x0206, (wchar_t)0x0208, (wchar_t)0x020A, (wchar_t)0x020C, (wchar_t)0x020E, (wchar_t)0x0210, (wchar_t)0x0212, (wchar_t)0x0214, + (wchar_t)0x0216, (wchar_t)0x0181, (wchar_t)0x0186, (wchar_t)0x018A, (wchar_t)0x018E, (wchar_t)0x018F, (wchar_t)0x0190, (wchar_t)0x0193, (wchar_t)0x0194, + (wchar_t)0x0197, (wchar_t)0x0196, (wchar_t)0x019C, (wchar_t)0x019D, (wchar_t)0x019F, (wchar_t)0x01A9, (wchar_t)0x01AE, (wchar_t)0x01B1, (wchar_t)0x01B2, + (wchar_t)0x01B7, (wchar_t)0x0386, (wchar_t)0x0388, (wchar_t)0x0389, (wchar_t)0x038A, (wchar_t)0x0391, (wchar_t)0x0392, (wchar_t)0x0393, (wchar_t)0x0394, + (wchar_t)0x0395, (wchar_t)0x0396, (wchar_t)0x0397, (wchar_t)0x0398, (wchar_t)0x0399, (wchar_t)0x039A, (wchar_t)0x039B, (wchar_t)0x039C, (wchar_t)0x039D, + (wchar_t)0x039E, (wchar_t)0x039F, (wchar_t)0x03A0, (wchar_t)0x03A1, (wchar_t)0x03A3, (wchar_t)0x03A4, (wchar_t)0x03A5, (wchar_t)0x03A6, (wchar_t)0x03A7, + (wchar_t)0x03A8, (wchar_t)0x03A9, (wchar_t)0x03AA, (wchar_t)0x03AB, (wchar_t)0x038C, (wchar_t)0x038E, (wchar_t)0x038F, (wchar_t)0x03E2, (wchar_t)0x03E4, + (wchar_t)0x03E6, (wchar_t)0x03E8, (wchar_t)0x03EA, (wchar_t)0x03EC, (wchar_t)0x03EE, (wchar_t)0x0410, (wchar_t)0x0411, (wchar_t)0x0412, (wchar_t)0x0413, + (wchar_t)0x0414, (wchar_t)0x0415, (wchar_t)0x0416, (wchar_t)0x0417, (wchar_t)0x0418, (wchar_t)0x0419, (wchar_t)0x041A, (wchar_t)0x041B, (wchar_t)0x041C, + (wchar_t)0x041D, (wchar_t)0x041E, (wchar_t)0x041F, (wchar_t)0x0420, (wchar_t)0x0421, (wchar_t)0x0422, (wchar_t)0x0423, (wchar_t)0x0424, (wchar_t)0x0425, + (wchar_t)0x0426, (wchar_t)0x0427, (wchar_t)0x0428, (wchar_t)0x0429, (wchar_t)0x042A, (wchar_t)0x042B, (wchar_t)0x042C, (wchar_t)0x042D, (wchar_t)0x042E, + (wchar_t)0x042F, (wchar_t)0x0401, (wchar_t)0x0402, (wchar_t)0x0403, (wchar_t)0x0404, (wchar_t)0x0405, (wchar_t)0x0406, (wchar_t)0x0407, (wchar_t)0x0408, + (wchar_t)0x0409, (wchar_t)0x040A, (wchar_t)0x040B, (wchar_t)0x040C, (wchar_t)0x040E, (wchar_t)0x040F, (wchar_t)0x0460, (wchar_t)0x0462, (wchar_t)0x0464, + (wchar_t)0x0466, (wchar_t)0x0468, (wchar_t)0x046A, (wchar_t)0x046C, (wchar_t)0x046E, (wchar_t)0x0470, (wchar_t)0x0472, (wchar_t)0x0474, (wchar_t)0x0476, + (wchar_t)0x0478, (wchar_t)0x047A, (wchar_t)0x047C, (wchar_t)0x047E, (wchar_t)0x0480, (wchar_t)0x0490, (wchar_t)0x0492, (wchar_t)0x0494, (wchar_t)0x0496, + (wchar_t)0x0498, (wchar_t)0x049A, (wchar_t)0x049C, (wchar_t)0x049E, (wchar_t)0x04A0, (wchar_t)0x04A2, (wchar_t)0x04A4, (wchar_t)0x04A6, (wchar_t)0x04A8, + (wchar_t)0x04AA, (wchar_t)0x04AC, (wchar_t)0x04AE, (wchar_t)0x04B0, (wchar_t)0x04B2, (wchar_t)0x04B4, (wchar_t)0x04B6, (wchar_t)0x04B8, (wchar_t)0x04BA, + (wchar_t)0x04BC, (wchar_t)0x04BE, (wchar_t)0x04C1, (wchar_t)0x04C3, (wchar_t)0x04C7, (wchar_t)0x04CB, (wchar_t)0x04D0, (wchar_t)0x04D2, (wchar_t)0x04D4, + (wchar_t)0x04D6, (wchar_t)0x04D8, (wchar_t)0x04DA, (wchar_t)0x04DC, (wchar_t)0x04DE, (wchar_t)0x04E0, (wchar_t)0x04E2, (wchar_t)0x04E4, (wchar_t)0x04E6, + (wchar_t)0x04E8, (wchar_t)0x04EA, (wchar_t)0x04EE, (wchar_t)0x04F0, (wchar_t)0x04F2, (wchar_t)0x04F4, (wchar_t)0x04F8, (wchar_t)0x0531, (wchar_t)0x0532, + (wchar_t)0x0533, (wchar_t)0x0534, (wchar_t)0x0535, (wchar_t)0x0536, (wchar_t)0x0537, (wchar_t)0x0538, (wchar_t)0x0539, (wchar_t)0x053A, (wchar_t)0x053B, + (wchar_t)0x053C, (wchar_t)0x053D, (wchar_t)0x053E, (wchar_t)0x053F, (wchar_t)0x0540, (wchar_t)0x0541, (wchar_t)0x0542, (wchar_t)0x0543, (wchar_t)0x0544, + (wchar_t)0x0545, (wchar_t)0x0546, (wchar_t)0x0547, (wchar_t)0x0548, (wchar_t)0x0549, (wchar_t)0x054A, (wchar_t)0x054B, (wchar_t)0x054C, (wchar_t)0x054D, + (wchar_t)0x054E, (wchar_t)0x054F, (wchar_t)0x0550, (wchar_t)0x0551, (wchar_t)0x0552, (wchar_t)0x0553, (wchar_t)0x0554, (wchar_t)0x0555, (wchar_t)0x0556, + (wchar_t)0x10A0, (wchar_t)0x10A1, (wchar_t)0x10A2, (wchar_t)0x10A3, (wchar_t)0x10A4, (wchar_t)0x10A5, (wchar_t)0x10A6, (wchar_t)0x10A7, (wchar_t)0x10A8, + (wchar_t)0x10A9, (wchar_t)0x10AA, (wchar_t)0x10AB, (wchar_t)0x10AC, (wchar_t)0x10AD, (wchar_t)0x10AE, (wchar_t)0x10AF, (wchar_t)0x10B0, (wchar_t)0x10B1, + (wchar_t)0x10B2, (wchar_t)0x10B3, (wchar_t)0x10B4, (wchar_t)0x10B5, (wchar_t)0x10B6, (wchar_t)0x10B7, (wchar_t)0x10B8, (wchar_t)0x10B9, (wchar_t)0x10BA, + (wchar_t)0x10BB, (wchar_t)0x10BC, (wchar_t)0x10BD, (wchar_t)0x10BE, (wchar_t)0x10BF, (wchar_t)0x10C0, (wchar_t)0x10C1, (wchar_t)0x10C2, (wchar_t)0x10C3, + (wchar_t)0x10C4, (wchar_t)0x10C5, (wchar_t)0x1E00, (wchar_t)0x1E02, (wchar_t)0x1E04, (wchar_t)0x1E06, (wchar_t)0x1E08, (wchar_t)0x1E0A, (wchar_t)0x1E0C, + (wchar_t)0x1E0E, (wchar_t)0x1E10, (wchar_t)0x1E12, (wchar_t)0x1E14, (wchar_t)0x1E16, (wchar_t)0x1E18, (wchar_t)0x1E1A, (wchar_t)0x1E1C, (wchar_t)0x1E1E, + (wchar_t)0x1E20, (wchar_t)0x1E22, (wchar_t)0x1E24, (wchar_t)0x1E26, (wchar_t)0x1E28, (wchar_t)0x1E2A, (wchar_t)0x1E2C, (wchar_t)0x1E2E, (wchar_t)0x1E30, + (wchar_t)0x1E32, (wchar_t)0x1E34, (wchar_t)0x1E36, (wchar_t)0x1E38, (wchar_t)0x1E3A, (wchar_t)0x1E3C, (wchar_t)0x1E3E, (wchar_t)0x1E40, (wchar_t)0x1E42, + (wchar_t)0x1E44, (wchar_t)0x1E46, (wchar_t)0x1E48, (wchar_t)0x1E4A, (wchar_t)0x1E4C, (wchar_t)0x1E4E, (wchar_t)0x1E50, (wchar_t)0x1E52, (wchar_t)0x1E54, + (wchar_t)0x1E56, (wchar_t)0x1E58, (wchar_t)0x1E5A, (wchar_t)0x1E5C, (wchar_t)0x1E5E, (wchar_t)0x1E60, (wchar_t)0x1E62, (wchar_t)0x1E64, (wchar_t)0x1E66, + (wchar_t)0x1E68, (wchar_t)0x1E6A, (wchar_t)0x1E6C, (wchar_t)0x1E6E, (wchar_t)0x1E70, (wchar_t)0x1E72, (wchar_t)0x1E74, (wchar_t)0x1E76, (wchar_t)0x1E78, + (wchar_t)0x1E7A, (wchar_t)0x1E7C, (wchar_t)0x1E7E, (wchar_t)0x1E80, (wchar_t)0x1E82, (wchar_t)0x1E84, (wchar_t)0x1E86, (wchar_t)0x1E88, (wchar_t)0x1E8A, + (wchar_t)0x1E8C, (wchar_t)0x1E8E, (wchar_t)0x1E90, (wchar_t)0x1E92, (wchar_t)0x1E94, (wchar_t)0x1EA0, (wchar_t)0x1EA2, (wchar_t)0x1EA4, (wchar_t)0x1EA6, + (wchar_t)0x1EA8, (wchar_t)0x1EAA, (wchar_t)0x1EAC, (wchar_t)0x1EAE, (wchar_t)0x1EB0, (wchar_t)0x1EB2, (wchar_t)0x1EB4, (wchar_t)0x1EB6, (wchar_t)0x1EB8, + (wchar_t)0x1EBA, (wchar_t)0x1EBC, (wchar_t)0x1EBE, (wchar_t)0x1EC0, (wchar_t)0x1EC2, (wchar_t)0x1EC4, (wchar_t)0x1EC6, (wchar_t)0x1EC8, (wchar_t)0x1ECA, + (wchar_t)0x1ECC, (wchar_t)0x1ECE, (wchar_t)0x1ED0, (wchar_t)0x1ED2, (wchar_t)0x1ED4, (wchar_t)0x1ED6, (wchar_t)0x1ED8, (wchar_t)0x1EDA, (wchar_t)0x1EDC, + (wchar_t)0x1EDE, (wchar_t)0x1EE0, (wchar_t)0x1EE2, (wchar_t)0x1EE4, (wchar_t)0x1EE6, (wchar_t)0x1EE8, (wchar_t)0x1EEA, (wchar_t)0x1EEC, (wchar_t)0x1EEE, + (wchar_t)0x1EF0, (wchar_t)0x1EF2, (wchar_t)0x1EF4, (wchar_t)0x1EF6, (wchar_t)0x1EF8, (wchar_t)0x1F08, (wchar_t)0x1F09, (wchar_t)0x1F0A, (wchar_t)0x1F0B, + (wchar_t)0x1F0C, (wchar_t)0x1F0D, (wchar_t)0x1F0E, (wchar_t)0x1F0F, (wchar_t)0x1F18, (wchar_t)0x1F19, (wchar_t)0x1F1A, (wchar_t)0x1F1B, (wchar_t)0x1F1C, + (wchar_t)0x1F1D, (wchar_t)0x1F28, (wchar_t)0x1F29, (wchar_t)0x1F2A, (wchar_t)0x1F2B, (wchar_t)0x1F2C, (wchar_t)0x1F2D, (wchar_t)0x1F2E, (wchar_t)0x1F2F, + (wchar_t)0x1F38, (wchar_t)0x1F39, (wchar_t)0x1F3A, (wchar_t)0x1F3B, (wchar_t)0x1F3C, (wchar_t)0x1F3D, (wchar_t)0x1F3E, (wchar_t)0x1F3F, (wchar_t)0x1F48, + (wchar_t)0x1F49, (wchar_t)0x1F4A, (wchar_t)0x1F4B, (wchar_t)0x1F4C, (wchar_t)0x1F4D, (wchar_t)0x1F59, (wchar_t)0x1F5B, (wchar_t)0x1F5D, (wchar_t)0x1F5F, + (wchar_t)0x1F68, (wchar_t)0x1F69, (wchar_t)0x1F6A, (wchar_t)0x1F6B, (wchar_t)0x1F6C, (wchar_t)0x1F6D, (wchar_t)0x1F6E, (wchar_t)0x1F6F, (wchar_t)0x1F88, + (wchar_t)0x1F89, (wchar_t)0x1F8A, (wchar_t)0x1F8B, (wchar_t)0x1F8C, (wchar_t)0x1F8D, (wchar_t)0x1F8E, (wchar_t)0x1F8F, (wchar_t)0x1F98, (wchar_t)0x1F99, + (wchar_t)0x1F9A, (wchar_t)0x1F9B, (wchar_t)0x1F9C, (wchar_t)0x1F9D, (wchar_t)0x1F9E, (wchar_t)0x1F9F, (wchar_t)0x1FA8, (wchar_t)0x1FA9, (wchar_t)0x1FAA, + (wchar_t)0x1FAB, (wchar_t)0x1FAC, (wchar_t)0x1FAD, (wchar_t)0x1FAE, (wchar_t)0x1FAF, (wchar_t)0x1FB8, (wchar_t)0x1FB9, (wchar_t)0x1FD8, (wchar_t)0x1FD9, + (wchar_t)0x1FE8, (wchar_t)0x1FE9, (wchar_t)0x24B6, (wchar_t)0x24B7, (wchar_t)0x24B8, (wchar_t)0x24B9, (wchar_t)0x24BA, (wchar_t)0x24BB, (wchar_t)0x24BC, + (wchar_t)0x24BD, (wchar_t)0x24BE, (wchar_t)0x24BF, (wchar_t)0x24C0, (wchar_t)0x24C1, (wchar_t)0x24C2, (wchar_t)0x24C3, (wchar_t)0x24C4, (wchar_t)0x24C5, + (wchar_t)0x24C6, (wchar_t)0x24C7, (wchar_t)0x24C8, (wchar_t)0x24C9, (wchar_t)0x24CA, (wchar_t)0x24CB, (wchar_t)0x24CC, (wchar_t)0x24CD, (wchar_t)0x24CE, + (wchar_t)0x24CF, (wchar_t)0xFF21, (wchar_t)0xFF22, (wchar_t)0xFF23, (wchar_t)0xFF24, (wchar_t)0xFF25, (wchar_t)0xFF26, (wchar_t)0xFF27, (wchar_t)0xFF28, + (wchar_t)0xFF29, (wchar_t)0xFF2A, (wchar_t)0xFF2B, (wchar_t)0xFF2C, (wchar_t)0xFF2D, (wchar_t)0xFF2E, (wchar_t)0xFF2F, (wchar_t)0xFF30, (wchar_t)0xFF31, + (wchar_t)0xFF32, (wchar_t)0xFF33, (wchar_t)0xFF34, (wchar_t)0xFF35, (wchar_t)0xFF36, (wchar_t)0xFF37, (wchar_t)0xFF38, (wchar_t)0xFF39, (wchar_t)0xFF3A +}; + + +std::string StringUtils::FormatV(const char *fmt, va_list args) +{ + if (!fmt || !fmt[0]) + return ""; + + int size = FORMAT_BLOCK_SIZE; + va_list argCopy; + + while (true) + { + char *cstr = reinterpret_cast(malloc(sizeof(char) * size)); + if (!cstr) + return ""; + + va_copy(argCopy, args); + int nActual = vsnprintf(cstr, size, fmt, argCopy); + va_end(argCopy); + + if (nActual > -1 && nActual < size) // We got a valid result + { + std::string str(cstr, nActual); + free(cstr); + return str; + } + free(cstr); +#ifndef TARGET_WINDOWS + if (nActual > -1) // Exactly what we will need (glibc 2.1) + size = nActual + 1; + else // Let's try to double the size (glibc 2.0) + size *= 2; +#else // TARGET_WINDOWS + va_copy(argCopy, args); + size = _vscprintf(fmt, argCopy); + va_end(argCopy); + if (size < 0) + return ""; + else + size++; // increment for null-termination +#endif // TARGET_WINDOWS + } + + return ""; // unreachable +} + +std::wstring StringUtils::FormatV(const wchar_t *fmt, va_list args) +{ + if (!fmt || !fmt[0]) + return L""; + + int size = FORMAT_BLOCK_SIZE; + va_list argCopy; + + while (true) + { + wchar_t *cstr = reinterpret_cast(malloc(sizeof(wchar_t) * size)); + if (!cstr) + return L""; + + va_copy(argCopy, args); + int nActual = vswprintf(cstr, size, fmt, argCopy); + va_end(argCopy); + + if (nActual > -1 && nActual < size) // We got a valid result + { + std::wstring str(cstr, nActual); + free(cstr); + return str; + } + free(cstr); + +#ifndef TARGET_WINDOWS + if (nActual > -1) // Exactly what we will need (glibc 2.1) + size = nActual + 1; + else // Let's try to double the size (glibc 2.0) + size *= 2; +#else // TARGET_WINDOWS + va_copy(argCopy, args); + size = _vscwprintf(fmt, argCopy); + va_end(argCopy); + if (size < 0) + return L""; + else + size++; // increment for null-termination +#endif // TARGET_WINDOWS + } + + return L""; +} + +int compareWchar (const void* a, const void* b) +{ + if (*(const wchar_t*)a < *(const wchar_t*)b) + return -1; + else if (*(const wchar_t*)a > *(const wchar_t*)b) + return 1; + return 0; +} + +wchar_t tolowerUnicode(const wchar_t& c) +{ + wchar_t* p = (wchar_t*) bsearch (&c, unicode_uppers, sizeof(unicode_uppers) / sizeof(wchar_t), sizeof(wchar_t), compareWchar); + if (p) + return *(unicode_lowers + (p - unicode_uppers)); + + return c; +} + +wchar_t toupperUnicode(const wchar_t& c) +{ + wchar_t* p = (wchar_t*) bsearch (&c, unicode_lowers, sizeof(unicode_lowers) / sizeof(wchar_t), sizeof(wchar_t), compareWchar); + if (p) + return *(unicode_uppers + (p - unicode_lowers)); + + return c; +} + +void StringUtils::ToUpper(std::string &str) +{ + std::transform(str.begin(), str.end(), str.begin(), ::toupper); +} + +void StringUtils::ToUpper(std::wstring &str) +{ + transform(str.begin(), str.end(), str.begin(), toupperUnicode); +} + +void StringUtils::ToLower(std::string &str) +{ + transform(str.begin(), str.end(), str.begin(), ::tolower); +} + +void StringUtils::ToLower(std::wstring &str) +{ + transform(str.begin(), str.end(), str.begin(), tolowerUnicode); +} + +void StringUtils::ToCapitalize(std::string &str) +{ + std::wstring wstr; + g_charsetConverter.utf8ToW(str, wstr); + ToCapitalize(wstr); + g_charsetConverter.wToUTF8(wstr, str); +} + +void StringUtils::ToCapitalize(std::wstring &str) +{ + const std::locale& loc = g_langInfo.GetSystemLocale(); + bool isFirstLetter = true; + for (std::wstring::iterator it = str.begin(); it < str.end(); ++it) + { + // capitalize after spaces and punctuation characters (except apostrophes) + if (std::isspace(*it, loc) || (std::ispunct(*it, loc) && *it != '\'')) + isFirstLetter = true; + else if (isFirstLetter) + { + *it = std::toupper(*it, loc); + isFirstLetter = false; + } + } +} + +bool StringUtils::EqualsNoCase(const std::string &str1, const std::string &str2) +{ + // before we do the char-by-char comparison, first compare sizes of both strings. + // This led to a 33% improvement in benchmarking on average. (size() just returns a member of std::string) + if (str1.size() != str2.size()) + return false; + return EqualsNoCase(str1.c_str(), str2.c_str()); +} + +bool StringUtils::EqualsNoCase(const std::string &str1, const char *s2) +{ + return EqualsNoCase(str1.c_str(), s2); +} + +bool StringUtils::EqualsNoCase(const char *s1, const char *s2) +{ + char c2; // we need only one char outside the loop + do + { + const char c1 = *s1++; // const local variable should help compiler to optimize + c2 = *s2++; + if (c1 != c2 && ::tolower(c1) != ::tolower(c2)) // This includes the possibility that one of the characters is the null-terminator, which implies a string mismatch. + return false; + } while (c2 != '\0'); // At this point, we know c1 == c2, so there's no need to test them both. + return true; +} + +int StringUtils::CompareNoCase(const std::string& str1, const std::string& str2, size_t n /* = 0 */) +{ + return CompareNoCase(str1.c_str(), str2.c_str(), n); +} + +int StringUtils::CompareNoCase(const char* s1, const char* s2, size_t n /* = 0 */) +{ + char c2; // we need only one char outside the loop + size_t index = 0; + do + { + const char c1 = *s1++; // const local variable should help compiler to optimize + c2 = *s2++; + index++; + if (c1 != c2 && ::tolower(c1) != ::tolower(c2)) // This includes the possibility that one of the characters is the null-terminator, which implies a string mismatch. + return ::tolower(c1) - ::tolower(c2); + } while (c2 != '\0' && + index != n); // At this point, we know c1 == c2, so there's no need to test them both. + return 0; +} + +std::string StringUtils::Left(const std::string &str, size_t count) +{ + count = std::max((size_t)0, std::min(count, str.size())); + return str.substr(0, count); +} + +std::string StringUtils::Mid(const std::string &str, size_t first, size_t count /* = string::npos */) +{ + if (first + count > str.size()) + count = str.size() - first; + + if (first > str.size()) + return std::string(); + + assert(first + count <= str.size()); + + return str.substr(first, count); +} + +std::string StringUtils::Right(const std::string &str, size_t count) +{ + count = std::max((size_t)0, std::min(count, str.size())); + return str.substr(str.size() - count); +} + +std::string& StringUtils::Trim(std::string &str) +{ + TrimLeft(str); + return TrimRight(str); +} + +std::string& StringUtils::Trim(std::string &str, const char* const chars) +{ + TrimLeft(str, chars); + return TrimRight(str, chars); +} + +// hack to check only first byte of UTF-8 character +// without this hack "TrimX" functions failed on Win32 and OS X with UTF-8 strings +static int isspace_c(char c) +{ + return (c & 0x80) == 0 && ::isspace(c); +} + +std::string& StringUtils::TrimLeft(std::string &str) +{ + str.erase(str.begin(), std::find_if(str.begin(), str.end(), std::not1(std::function(isspace_c)))); + return str; +} + +std::string& StringUtils::TrimLeft(std::string &str, const char* const chars) +{ + size_t nidx = str.find_first_not_of(chars); + str.erase(0, nidx); + return str; +} + +std::string& StringUtils::TrimRight(std::string &str) +{ + str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(std::function(isspace_c))).base(), str.end()); + return str; +} + +std::string& StringUtils::TrimRight(std::string &str, const char* const chars) +{ + size_t nidx = str.find_last_not_of(chars); + str.erase(str.npos == nidx ? 0 : ++nidx); + return str; +} + +int StringUtils::ReturnDigits(const std::string& str) +{ + std::stringstream ss; + for (const auto& character : str) + { + if (isdigit(character)) + ss << character; + } + return atoi(ss.str().c_str()); +} + +std::string& StringUtils::RemoveDuplicatedSpacesAndTabs(std::string& str) +{ + std::string::iterator it = str.begin(); + bool onSpace = false; + while(it != str.end()) + { + if (*it == '\t') + *it = ' '; + + if (*it == ' ') + { + if (onSpace) + { + it = str.erase(it); + continue; + } + else + onSpace = true; + } + else + onSpace = false; + + ++it; + } + return str; +} + +int StringUtils::Replace(std::string &str, char oldChar, char newChar) +{ + int replacedChars = 0; + for (std::string::iterator it = str.begin(); it != str.end(); ++it) + { + if (*it == oldChar) + { + *it = newChar; + replacedChars++; + } + } + + return replacedChars; +} + +int StringUtils::Replace(std::string &str, const std::string &oldStr, const std::string &newStr) +{ + if (oldStr.empty()) + return 0; + + int replacedChars = 0; + size_t index = 0; + + while (index < str.size() && (index = str.find(oldStr, index)) != std::string::npos) + { + str.replace(index, oldStr.size(), newStr); + index += newStr.size(); + replacedChars++; + } + + return replacedChars; +} + +int StringUtils::Replace(std::wstring &str, const std::wstring &oldStr, const std::wstring &newStr) +{ + if (oldStr.empty()) + return 0; + + int replacedChars = 0; + size_t index = 0; + + while (index < str.size() && (index = str.find(oldStr, index)) != std::string::npos) + { + str.replace(index, oldStr.size(), newStr); + index += newStr.size(); + replacedChars++; + } + + return replacedChars; +} + +bool StringUtils::StartsWith(const std::string &str1, const std::string &str2) +{ + return str1.compare(0, str2.size(), str2) == 0; +} + +bool StringUtils::StartsWith(const std::string &str1, const char *s2) +{ + return StartsWith(str1.c_str(), s2); +} + +bool StringUtils::StartsWith(const char *s1, const char *s2) +{ + while (*s2 != '\0') + { + if (*s1 != *s2) + return false; + s1++; + s2++; + } + return true; +} + +bool StringUtils::StartsWithNoCase(const std::string &str1, const std::string &str2) +{ + return StartsWithNoCase(str1.c_str(), str2.c_str()); +} + +bool StringUtils::StartsWithNoCase(const std::string &str1, const char *s2) +{ + return StartsWithNoCase(str1.c_str(), s2); +} + +bool StringUtils::StartsWithNoCase(const char *s1, const char *s2) +{ + while (*s2 != '\0') + { + if (::tolower(*s1) != ::tolower(*s2)) + return false; + s1++; + s2++; + } + return true; +} + +bool StringUtils::EndsWith(const std::string &str1, const std::string &str2) +{ + if (str1.size() < str2.size()) + return false; + return str1.compare(str1.size() - str2.size(), str2.size(), str2) == 0; +} + +bool StringUtils::EndsWith(const std::string &str1, const char *s2) +{ + size_t len2 = strlen(s2); + if (str1.size() < len2) + return false; + return str1.compare(str1.size() - len2, len2, s2) == 0; +} + +bool StringUtils::EndsWithNoCase(const std::string &str1, const std::string &str2) +{ + if (str1.size() < str2.size()) + return false; + const char *s1 = str1.c_str() + str1.size() - str2.size(); + const char *s2 = str2.c_str(); + while (*s2 != '\0') + { + if (::tolower(*s1) != ::tolower(*s2)) + return false; + s1++; + s2++; + } + return true; +} + +bool StringUtils::EndsWithNoCase(const std::string &str1, const char *s2) +{ + size_t len2 = strlen(s2); + if (str1.size() < len2) + return false; + const char *s1 = str1.c_str() + str1.size() - len2; + while (*s2 != '\0') + { + if (::tolower(*s1) != ::tolower(*s2)) + return false; + s1++; + s2++; + } + return true; +} + +std::vector StringUtils::Split(const std::string& input, const std::string& delimiter, unsigned int iMaxStrings) +{ + std::vector result; + SplitTo(std::back_inserter(result), input, delimiter, iMaxStrings); + return result; +} + +std::vector StringUtils::Split(const std::string& input, const char delimiter, size_t iMaxStrings) +{ + std::vector result; + SplitTo(std::back_inserter(result), input, delimiter, iMaxStrings); + return result; +} + +std::vector StringUtils::Split(const std::string& input, const std::vector& delimiters) +{ + std::vector result; + SplitTo(std::back_inserter(result), input, delimiters); + return result; +} + +std::vector StringUtils::SplitMulti(const std::vector &input, const std::vector &delimiters, unsigned int iMaxStrings /* = 0 */) +{ + if (input.empty()) + return std::vector(); + + std::vector results(input); + + if (delimiters.empty() || (iMaxStrings > 0 && iMaxStrings <= input.size())) + return results; + + std::vector strings1; + if (iMaxStrings == 0) + { + for (size_t di = 0; di < delimiters.size(); di++) + { + for (size_t i = 0; i < results.size(); i++) + { + std::vector substrings = StringUtils::Split(results[i], delimiters[di]); + for (size_t j = 0; j < substrings.size(); j++) + strings1.push_back(substrings[j]); + } + results = strings1; + strings1.clear(); + } + return results; + } + + // Control the number of strings input is split into, keeping the original strings. + // Note iMaxStrings > input.size() + int iNew = iMaxStrings - results.size(); + for (size_t di = 0; di < delimiters.size(); di++) + { + for (size_t i = 0; i < results.size(); i++) + { + if (iNew > 0) + { + std::vector substrings = StringUtils::Split(results[i], delimiters[di], iNew + 1); + iNew = iNew - substrings.size() + 1; + for (size_t j = 0; j < substrings.size(); j++) + strings1.push_back(substrings[j]); + } + else + strings1.push_back(results[i]); + } + results = strings1; + iNew = iMaxStrings - results.size(); + strings1.clear(); + if ((iNew <= 0)) + break; //Stop trying any more delimiters + } + return results; +} + +// returns the number of occurrences of strFind in strInput. +int StringUtils::FindNumber(const std::string& strInput, const std::string &strFind) +{ + size_t pos = strInput.find(strFind, 0); + int numfound = 0; + while (pos != std::string::npos) + { + numfound++; + pos = strInput.find(strFind, pos + 1); + } + return numfound; +} + +// Plane maps for MySQL utf8_general_ci (now known as utf8mb3_general_ci) collation +// Derived from https://github.com/MariaDB/server/blob/10.5/strings/ctype-utf8.c + +// clang-format off +static const uint16_t plane00[] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x039C, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x00C6, 0x0043, 0x0045, 0x0045, 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049, + 0x00D0, 0x004E, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x00D7, 0x00D8, 0x0055, 0x0055, 0x0055, 0x0055, 0x0059, 0x00DE, 0x0053, + 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x00C6, 0x0043, 0x0045, 0x0045, 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049, + 0x00D0, 0x004E, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x00F7, 0x00D8, 0x0055, 0x0055, 0x0055, 0x0055, 0x0059, 0x00DE, 0x0059 +}; + +static const uint16_t plane01[] = { + 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0043, 0x0043, 0x0043, 0x0043, 0x0043, 0x0043, 0x0043, 0x0043, 0x0044, 0x0044, + 0x0110, 0x0110, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0047, 0x0047, 0x0047, 0x0047, + 0x0047, 0x0047, 0x0047, 0x0047, 0x0048, 0x0048, 0x0126, 0x0126, 0x0049, 0x0049, 0x0049, 0x0049, 0x0049, 0x0049, 0x0049, 0x0049, + 0x0049, 0x0049, 0x0132, 0x0132, 0x004A, 0x004A, 0x004B, 0x004B, 0x0138, 0x004C, 0x004C, 0x004C, 0x004C, 0x004C, 0x004C, 0x013F, + 0x013F, 0x0141, 0x0141, 0x004E, 0x004E, 0x004E, 0x004E, 0x004E, 0x004E, 0x0149, 0x014A, 0x014A, 0x004F, 0x004F, 0x004F, 0x004F, + 0x004F, 0x004F, 0x0152, 0x0152, 0x0052, 0x0052, 0x0052, 0x0052, 0x0052, 0x0052, 0x0053, 0x0053, 0x0053, 0x0053, 0x0053, 0x0053, + 0x0053, 0x0053, 0x0054, 0x0054, 0x0054, 0x0054, 0x0166, 0x0166, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, + 0x0055, 0x0055, 0x0055, 0x0055, 0x0057, 0x0057, 0x0059, 0x0059, 0x0059, 0x005A, 0x005A, 0x005A, 0x005A, 0x005A, 0x005A, 0x0053, + 0x0180, 0x0181, 0x0182, 0x0182, 0x0184, 0x0184, 0x0186, 0x0187, 0x0187, 0x0189, 0x018A, 0x018B, 0x018B, 0x018D, 0x018E, 0x018F, + 0x0190, 0x0191, 0x0191, 0x0193, 0x0194, 0x01F6, 0x0196, 0x0197, 0x0198, 0x0198, 0x019A, 0x019B, 0x019C, 0x019D, 0x019E, 0x019F, + 0x004F, 0x004F, 0x01A2, 0x01A2, 0x01A4, 0x01A4, 0x01A6, 0x01A7, 0x01A7, 0x01A9, 0x01AA, 0x01AB, 0x01AC, 0x01AC, 0x01AE, 0x0055, + 0x0055, 0x01B1, 0x01B2, 0x01B3, 0x01B3, 0x01B5, 0x01B5, 0x01B7, 0x01B8, 0x01B8, 0x01BA, 0x01BB, 0x01BC, 0x01BC, 0x01BE, 0x01F7, + 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C4, 0x01C4, 0x01C4, 0x01C7, 0x01C7, 0x01C7, 0x01CA, 0x01CA, 0x01CA, 0x0041, 0x0041, 0x0049, + 0x0049, 0x004F, 0x004F, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x018E, 0x0041, 0x0041, + 0x0041, 0x0041, 0x00C6, 0x00C6, 0x01E4, 0x01E4, 0x0047, 0x0047, 0x004B, 0x004B, 0x004F, 0x004F, 0x004F, 0x004F, 0x01B7, 0x01B7, + 0x004A, 0x01F1, 0x01F1, 0x01F1, 0x0047, 0x0047, 0x01F6, 0x01F7, 0x004E, 0x004E, 0x0041, 0x0041, 0x00C6, 0x00C6, 0x00D8, 0x00D8 +}; + +static const uint16_t plane02[] = { + 0x0041, 0x0041, 0x0041, 0x0041, 0x0045, 0x0045, 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049, 0x004F, 0x004F, 0x004F, 0x004F, + 0x0052, 0x0052, 0x0052, 0x0052, 0x0055, 0x0055, 0x0055, 0x0055, 0x0053, 0x0053, 0x0054, 0x0054, 0x021C, 0x021C, 0x0048, 0x0048, + 0x0220, 0x0221, 0x0222, 0x0222, 0x0224, 0x0224, 0x0041, 0x0041, 0x0045, 0x0045, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, + 0x004F, 0x004F, 0x0059, 0x0059, 0x0234, 0x0235, 0x0236, 0x0237, 0x0238, 0x0239, 0x023A, 0x023B, 0x023C, 0x023D, 0x023E, 0x023F, + 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, 0x0248, 0x0249, 0x024A, 0x024B, 0x024C, 0x024D, 0x024E, 0x024F, + 0x0250, 0x0251, 0x0252, 0x0181, 0x0186, 0x0255, 0x0189, 0x018A, 0x0258, 0x018F, 0x025A, 0x0190, 0x025C, 0x025D, 0x025E, 0x025F, + 0x0193, 0x0261, 0x0262, 0x0194, 0x0264, 0x0265, 0x0266, 0x0267, 0x0197, 0x0196, 0x026A, 0x026B, 0x026C, 0x026D, 0x026E, 0x019C, + 0x0270, 0x0271, 0x019D, 0x0273, 0x0274, 0x019F, 0x0276, 0x0277, 0x0278, 0x0279, 0x027A, 0x027B, 0x027C, 0x027D, 0x027E, 0x027F, + 0x01A6, 0x0281, 0x0282, 0x01A9, 0x0284, 0x0285, 0x0286, 0x0287, 0x01AE, 0x0289, 0x01B1, 0x01B2, 0x028C, 0x028D, 0x028E, 0x028F, + 0x0290, 0x0291, 0x01B7, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, 0x0298, 0x0299, 0x029A, 0x029B, 0x029C, 0x029D, 0x029E, 0x029F, + 0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x02A4, 0x02A5, 0x02A6, 0x02A7, 0x02A8, 0x02A9, 0x02AA, 0x02AB, 0x02AC, 0x02AD, 0x02AE, 0x02AF, + 0x02B0, 0x02B1, 0x02B2, 0x02B3, 0x02B4, 0x02B5, 0x02B6, 0x02B7, 0x02B8, 0x02B9, 0x02BA, 0x02BB, 0x02BC, 0x02BD, 0x02BE, 0x02BF, + 0x02C0, 0x02C1, 0x02C2, 0x02C3, 0x02C4, 0x02C5, 0x02C6, 0x02C7, 0x02C8, 0x02C9, 0x02CA, 0x02CB, 0x02CC, 0x02CD, 0x02CE, 0x02CF, + 0x02D0, 0x02D1, 0x02D2, 0x02D3, 0x02D4, 0x02D5, 0x02D6, 0x02D7, 0x02D8, 0x02D9, 0x02DA, 0x02DB, 0x02DC, 0x02DD, 0x02DE, 0x02DF, + 0x02E0, 0x02E1, 0x02E2, 0x02E3, 0x02E4, 0x02E5, 0x02E6, 0x02E7, 0x02E8, 0x02E9, 0x02EA, 0x02EB, 0x02EC, 0x02ED, 0x02EE, 0x02EF, + 0x02F0, 0x02F1, 0x02F2, 0x02F3, 0x02F4, 0x02F5, 0x02F6, 0x02F7, 0x02F8, 0x02F9, 0x02FA, 0x02FB, 0x02FC, 0x02FD, 0x02FE, 0x02FF +}; + +static const uint16_t plane03[] = { + 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F, + 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, 0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F, + 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, 0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F, + 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F, + 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0399, 0x0346, 0x0347, 0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F, + 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F, + 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F, + 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F, + 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0391, 0x0387, 0x0395, 0x0397, 0x0399, 0x038B, 0x039F, 0x038D, 0x03A5, 0x03A9, + 0x0399, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0x03A2, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x0399, 0x03A5, 0x0391, 0x0395, 0x0397, 0x0399, + 0x03A5, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0x03A3, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x0399, 0x03A5, 0x039F, 0x03A5, 0x03A9, 0x03CF, + 0x0392, 0x0398, 0x03D2, 0x03D2, 0x03D2, 0x03A6, 0x03A0, 0x03D7, 0x03D8, 0x03D9, 0x03DA, 0x03DA, 0x03DC, 0x03DC, 0x03DE, 0x03DE, + 0x03E0, 0x03E0, 0x03E2, 0x03E2, 0x03E4, 0x03E4, 0x03E6, 0x03E6, 0x03E8, 0x03E8, 0x03EA, 0x03EA, 0x03EC, 0x03EC, 0x03EE, 0x03EE, + 0x039A, 0x03A1, 0x03A3, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7, 0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF +}; + +static const uint16_t plane04[] = { + 0x0415, 0x0415, 0x0402, 0x0413, 0x0404, 0x0405, 0x0406, 0x0406, 0x0408, 0x0409, 0x040A, 0x040B, 0x041A, 0x0418, 0x0423, 0x040F, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0415, 0x0415, 0x0402, 0x0413, 0x0404, 0x0405, 0x0406, 0x0406, 0x0408, 0x0409, 0x040A, 0x040B, 0x041A, 0x0418, 0x0423, 0x040F, + 0x0460, 0x0460, 0x0462, 0x0462, 0x0464, 0x0464, 0x0466, 0x0466, 0x0468, 0x0468, 0x046A, 0x046A, 0x046C, 0x046C, 0x046E, 0x046E, + 0x0470, 0x0470, 0x0472, 0x0472, 0x0474, 0x0474, 0x0474, 0x0474, 0x0478, 0x0478, 0x047A, 0x047A, 0x047C, 0x047C, 0x047E, 0x047E, + 0x0480, 0x0480, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048C, 0x048E, 0x048E, + 0x0490, 0x0490, 0x0492, 0x0492, 0x0494, 0x0494, 0x0496, 0x0496, 0x0498, 0x0498, 0x049A, 0x049A, 0x049C, 0x049C, 0x049E, 0x049E, + 0x04A0, 0x04A0, 0x04A2, 0x04A2, 0x04A4, 0x04A4, 0x04A6, 0x04A6, 0x04A8, 0x04A8, 0x04AA, 0x04AA, 0x04AC, 0x04AC, 0x04AE, 0x04AE, + 0x04B0, 0x04B0, 0x04B2, 0x04B2, 0x04B4, 0x04B4, 0x04B6, 0x04B6, 0x04B8, 0x04B8, 0x04BA, 0x04BA, 0x04BC, 0x04BC, 0x04BE, 0x04BE, + 0x04C0, 0x0416, 0x0416, 0x04C3, 0x04C3, 0x04C5, 0x04C6, 0x04C7, 0x04C7, 0x04C9, 0x04CA, 0x04CB, 0x04CB, 0x04CD, 0x04CE, 0x04CF, + 0x0410, 0x0410, 0x0410, 0x0410, 0x04D4, 0x04D4, 0x0415, 0x0415, 0x04D8, 0x04D8, 0x04D8, 0x04D8, 0x0416, 0x0416, 0x0417, 0x0417, + 0x04E0, 0x04E0, 0x0418, 0x0418, 0x0418, 0x0418, 0x041E, 0x041E, 0x04E8, 0x04E8, 0x04E8, 0x04E8, 0x042D, 0x042D, 0x0423, 0x0423, + 0x0423, 0x0423, 0x0423, 0x0423, 0x0427, 0x0427, 0x04F6, 0x04F7, 0x042B, 0x042B, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF +}; + +static const uint16_t plane05[] = { + 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F, + 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, 0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F, + 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, 0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F, + 0x0530, 0x0531, 0x0532, 0x0533, 0x0534, 0x0535, 0x0536, 0x0537, 0x0538, 0x0539, 0x053A, 0x053B, 0x053C, 0x053D, 0x053E, 0x053F, + 0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547, 0x0548, 0x0549, 0x054A, 0x054B, 0x054C, 0x054D, 0x054E, 0x054F, + 0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0x0557, 0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F, + 0x0560, 0x0531, 0x0532, 0x0533, 0x0534, 0x0535, 0x0536, 0x0537, 0x0538, 0x0539, 0x053A, 0x053B, 0x053C, 0x053D, 0x053E, 0x053F, + 0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547, 0x0548, 0x0549, 0x054A, 0x054B, 0x054C, 0x054D, 0x054E, 0x054F, + 0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0x0587, 0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F, + 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, 0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F, + 0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7, 0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF, + 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, 0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, + 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7, 0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF, + 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7, 0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF +}; + +static const uint16_t plane1E[] = { + 0x0041, 0x0041, 0x0042, 0x0042, 0x0042, 0x0042, 0x0042, 0x0042, 0x0043, 0x0043, 0x0044, 0x0044, 0x0044, 0x0044, 0x0044, 0x0044, + 0x0044, 0x0044, 0x0044, 0x0044, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0046, 0x0046, + 0x0047, 0x0047, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0049, 0x0049, 0x0049, 0x0049, + 0x004B, 0x004B, 0x004B, 0x004B, 0x004B, 0x004B, 0x004C, 0x004C, 0x004C, 0x004C, 0x004C, 0x004C, 0x004C, 0x004C, 0x004D, 0x004D, + 0x004D, 0x004D, 0x004D, 0x004D, 0x004E, 0x004E, 0x004E, 0x004E, 0x004E, 0x004E, 0x004E, 0x004E, 0x004F, 0x004F, 0x004F, 0x004F, + 0x004F, 0x004F, 0x004F, 0x004F, 0x0050, 0x0050, 0x0050, 0x0050, 0x0052, 0x0052, 0x0052, 0x0052, 0x0052, 0x0052, 0x0052, 0x0052, + 0x0053, 0x0053, 0x0053, 0x0053, 0x0053, 0x0053, 0x0053, 0x0053, 0x0053, 0x0053, 0x0054, 0x0054, 0x0054, 0x0054, 0x0054, 0x0054, + 0x0054, 0x0054, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0056, 0x0056, 0x0056, 0x0056, + 0x0057, 0x0057, 0x0057, 0x0057, 0x0057, 0x0057, 0x0057, 0x0057, 0x0057, 0x0057, 0x0058, 0x0058, 0x0058, 0x0058, 0x0059, 0x0059, + 0x005A, 0x005A, 0x005A, 0x005A, 0x005A, 0x005A, 0x0048, 0x0054, 0x0057, 0x0059, 0x1E9A, 0x0053, 0x1E9C, 0x1E9D, 0x1E9E, 0x1E9F, + 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, + 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, + 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049, 0x004F, 0x004F, 0x004F, 0x004F, + 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, + 0x004F, 0x004F, 0x004F, 0x004F, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055, + 0x0055, 0x0055, 0x0059, 0x0059, 0x0059, 0x0059, 0x0059, 0x0059, 0x0059, 0x0059, 0x1EFA, 0x1EFB, 0x1EFC, 0x1EFD, 0x1EFE, 0x1EFF +}; + +static const uint16_t plane1F[] = { + 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, + 0x0395, 0x0395, 0x0395, 0x0395, 0x0395, 0x0395, 0x1F16, 0x1F17, 0x0395, 0x0395, 0x0395, 0x0395, 0x0395, 0x0395, 0x1F1E, 0x1F1F, + 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, + 0x0399, 0x0399, 0x0399, 0x0399, 0x0399, 0x0399, 0x0399, 0x0399, 0x0399, 0x0399, 0x0399, 0x0399, 0x0399, 0x0399, 0x0399, 0x0399, + 0x039F, 0x039F, 0x039F, 0x039F, 0x039F, 0x039F, 0x1F46, 0x1F47, 0x039F, 0x039F, 0x039F, 0x039F, 0x039F, 0x039F, 0x1F4E, 0x1F4F, + 0x03A5, 0x03A5, 0x03A5, 0x03A5, 0x03A5, 0x03A5, 0x03A5, 0x03A5, 0x1F58, 0x03A5, 0x1F5A, 0x03A5, 0x1F5C, 0x03A5, 0x1F5E, 0x03A5, + 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, + 0x0391, 0x1FBB, 0x0395, 0x1FC9, 0x0397, 0x1FCB, 0x0399, 0x1FDB, 0x039F, 0x1FF9, 0x03A5, 0x1FEB, 0x03A9, 0x1FFB, 0x1F7E, 0x1F7F, + 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, + 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, 0x0397, + 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, 0x03A9, + 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x1FB5, 0x0391, 0x0391, 0x0391, 0x0391, 0x0391, 0x1FBB, 0x0391, 0x1FBD, 0x0399, 0x1FBF, + 0x1FC0, 0x1FC1, 0x0397, 0x0397, 0x0397, 0x1FC5, 0x0397, 0x0397, 0x0395, 0x1FC9, 0x0397, 0x1FCB, 0x0397, 0x1FCD, 0x1FCE, 0x1FCF, + 0x0399, 0x0399, 0x0399, 0x1FD3, 0x1FD4, 0x1FD5, 0x0399, 0x0399, 0x0399, 0x0399, 0x0399, 0x1FDB, 0x1FDC, 0x1FDD, 0x1FDE, 0x1FDF, + 0x03A5, 0x03A5, 0x03A5, 0x1FE3, 0x03A1, 0x03A1, 0x03A5, 0x03A5, 0x03A5, 0x03A5, 0x03A5, 0x1FEB, 0x03A1, 0x1FED, 0x1FEE, 0x1FEF, + 0x1FF0, 0x1FF1, 0x03A9, 0x03A9, 0x03A9, 0x1FF5, 0x03A9, 0x03A9, 0x039F, 0x1FF9, 0x03A9, 0x1FFB, 0x03A9, 0x1FFD, 0x1FFE, 0x1FFF +}; + +static const uint16_t plane21[] = { + 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, 0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F, + 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, 0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F, + 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F, + 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, 0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F, + 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, 0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F, + 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F, + 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216A, 0x216B, 0x216C, 0x216D, 0x216E, 0x216F, + 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216A, 0x216B, 0x216C, 0x216D, 0x216E, 0x216F, + 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, 0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F, + 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, 0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F, + 0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7, 0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF, + 0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7, 0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF, + 0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7, 0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF, + 0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7, 0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF, + 0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7, 0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF, + 0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7, 0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF +}; + +static const uint16_t plane24[] = { + 0x2400, 0x2401, 0x2402, 0x2403, 0x2404, 0x2405, 0x2406, 0x2407, 0x2408, 0x2409, 0x240A, 0x240B, 0x240C, 0x240D, 0x240E, 0x240F, + 0x2410, 0x2411, 0x2412, 0x2413, 0x2414, 0x2415, 0x2416, 0x2417, 0x2418, 0x2419, 0x241A, 0x241B, 0x241C, 0x241D, 0x241E, 0x241F, + 0x2420, 0x2421, 0x2422, 0x2423, 0x2424, 0x2425, 0x2426, 0x2427, 0x2428, 0x2429, 0x242A, 0x242B, 0x242C, 0x242D, 0x242E, 0x242F, + 0x2430, 0x2431, 0x2432, 0x2433, 0x2434, 0x2435, 0x2436, 0x2437, 0x2438, 0x2439, 0x243A, 0x243B, 0x243C, 0x243D, 0x243E, 0x243F, + 0x2440, 0x2441, 0x2442, 0x2443, 0x2444, 0x2445, 0x2446, 0x2447, 0x2448, 0x2449, 0x244A, 0x244B, 0x244C, 0x244D, 0x244E, 0x244F, + 0x2450, 0x2451, 0x2452, 0x2453, 0x2454, 0x2455, 0x2456, 0x2457, 0x2458, 0x2459, 0x245A, 0x245B, 0x245C, 0x245D, 0x245E, 0x245F, + 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E, 0x246F, + 0x2470, 0x2471, 0x2472, 0x2473, 0x2474, 0x2475, 0x2476, 0x2477, 0x2478, 0x2479, 0x247A, 0x247B, 0x247C, 0x247D, 0x247E, 0x247F, + 0x2480, 0x2481, 0x2482, 0x2483, 0x2484, 0x2485, 0x2486, 0x2487, 0x2488, 0x2489, 0x248A, 0x248B, 0x248C, 0x248D, 0x248E, 0x248F, + 0x2490, 0x2491, 0x2492, 0x2493, 0x2494, 0x2495, 0x2496, 0x2497, 0x2498, 0x2499, 0x249A, 0x249B, 0x249C, 0x249D, 0x249E, 0x249F, + 0x24A0, 0x24A1, 0x24A2, 0x24A3, 0x24A4, 0x24A5, 0x24A6, 0x24A7, 0x24A8, 0x24A9, 0x24AA, 0x24AB, 0x24AC, 0x24AD, 0x24AE, 0x24AF, + 0x24B0, 0x24B1, 0x24B2, 0x24B3, 0x24B4, 0x24B5, 0x24B6, 0x24B7, 0x24B8, 0x24B9, 0x24BA, 0x24BB, 0x24BC, 0x24BD, 0x24BE, 0x24BF, + 0x24C0, 0x24C1, 0x24C2, 0x24C3, 0x24C4, 0x24C5, 0x24C6, 0x24C7, 0x24C8, 0x24C9, 0x24CA, 0x24CB, 0x24CC, 0x24CD, 0x24CE, 0x24CF, + 0x24B6, 0x24B7, 0x24B8, 0x24B9, 0x24BA, 0x24BB, 0x24BC, 0x24BD, 0x24BE, 0x24BF, 0x24C0, 0x24C1, 0x24C2, 0x24C3, 0x24C4, 0x24C5, + 0x24C6, 0x24C7, 0x24C8, 0x24C9, 0x24CA, 0x24CB, 0x24CC, 0x24CD, 0x24CE, 0x24CF, 0x24EA, 0x24EB, 0x24EC, 0x24ED, 0x24EE, 0x24EF, + 0x24F0, 0x24F1, 0x24F2, 0x24F3, 0x24F4, 0x24F5, 0x24F6, 0x24F7, 0x24F8, 0x24F9, 0x24FA, 0x24FB, 0x24FC, 0x24FD, 0x24FE, 0x24FF +}; + +static const uint16_t planeFF[] = { + 0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07, 0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F, + 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F, + 0xFF20, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, + 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F, + 0xFF40, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, + 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F, + 0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F, + 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77, 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F, + 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F, + 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F, + 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7, 0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF, + 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7, 0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF, + 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF, + 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7, 0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF, + 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7, 0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF, + 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF +}; + +static const uint16_t* const planemap[256] = { + plane00, plane01, plane02, plane03, plane04, plane05, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, plane1E, plane1F, NULL, + plane21, NULL, NULL, plane24, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, planeFF +}; +// clang-format on + +static wchar_t GetCollationWeight(const wchar_t& r) +{ + // Lookup the "weight" of a UTF8 char, equivalent lowercase ascii letter, in the plane map, + // the character comparison value used by using "accent folding" collation utf8_general_ci + // in MySQL (AKA utf8mb3_general_ci in MariaDB 10) + auto index = r >> 8; + if (index > 255) + return 0xFFFD; + auto plane = planemap[index]; + if (plane == nullptr) + return r; + return static_cast(plane[r & 0xFF]); +} + +// Compares separately the numeric and alphabetic parts of a wide string. +// returns negative if left < right, positive if left > right +// and 0 if they are identical. +// See also the equivalent StringUtils::AlphaNumericCollation() for UFT8 data +int64_t StringUtils::AlphaNumericCompare(const wchar_t* left, const wchar_t* right) +{ + const wchar_t *l = left; + const wchar_t *r = right; + const wchar_t *ld, *rd; + wchar_t lc, rc; + int64_t lnum, rnum; + bool lsym, rsym; + while (*l != 0 && *r != 0) + { + // check if we have a numerical value + if (*l >= L'0' && *l <= L'9' && *r >= L'0' && *r <= L'9') + { + ld = l; + lnum = *ld++ - L'0'; + while (*ld >= L'0' && *ld <= L'9' && ld < l + 15) + { // compare only up to 15 digits + lnum *= 10; + lnum += *ld++ - L'0'; + } + rd = r; + rnum = *rd++ - L'0'; + while (*rd >= L'0' && *rd <= L'9' && rd < r + 15) + { // compare only up to 15 digits + rnum *= 10; + rnum += *rd++ - L'0'; + } + // do we have numbers? + if (lnum != rnum) + { // yes - and they're different! + return lnum - rnum; + } + l = ld; + r = rd; + continue; + } + + lc = *l; + rc = *r; + // Put ascii punctuation and symbols e.g. !#$&()*+,-./:;<=>?@[\]^_ `{|}~ above the other + // alphanumeric ascii, rather than some being mixed between the numbers and letters, and + // above all other unicode letters, symbols and punctuation. + // (Locale collation of these chars varies across platforms) + lsym = (lc >= 32 && lc < L'0') || (lc > L'9' && lc < L'A') || + (lc > L'Z' && lc < L'a') || (lc > L'z' && lc < 128); + rsym = (rc >= 32 && rc < L'0') || (rc > L'9' && rc < L'A') || + (rc > L'Z' && rc < L'a') || (rc > L'z' && rc < 128); + if (lsym && !rsym) + return -1; + if (!lsym && rsym) + return 1; + if (lsym && rsym) + { + if (lc != rc) + return lc - rc; + else + { // Same symbol advance to next wchar + l++; + r++; + continue; + } + } + if (!g_langInfo.UseLocaleCollation()) + { + // Apply case sensitive accent folding collation to non-ascii chars. + // This mimics utf8_general_ci collation, and provides simple collation of LATIN-1 chars + // for any platformthat doesn't have a language specific collate facet implemented + if (lc > 128) + lc = GetCollationWeight(lc); + if (rc > 128) + rc = GetCollationWeight(rc); + } + // Do case less comparison, convert ascii upper case to lower case + if (lc >= L'A' && lc <= L'Z') + lc += L'a' - L'A'; + if (rc >= L'A' && rc <= L'Z') + rc += L'a' - L'A'; + + if (lc != rc) + { + if (!g_langInfo.UseLocaleCollation()) + { + // Compare unicode (having applied accent folding collation to non-ascii chars). + int i = wcsncmp(&lc, &rc, 1); + return i; + } + else + { + // Fetch collation facet from locale to do comparison of wide char although on some + // platforms this is not langauge specific but just compares unicode + const std::collate& coll = + std::use_facet>(g_langInfo.GetSystemLocale()); + int cmp_res = coll.compare(&lc, &lc + 1, &rc, &rc + 1); + if (cmp_res != 0) + return cmp_res; + } + } + l++; r++; + } + if (*r) + { // r is longer + return -1; + } + else if (*l) + { // l is longer + return 1; + } + return 0; // files are the same +} + +/* + Convert the UTF8 character to which z points into a 31-bit Unicode point. + Return how many bytes (0 to 3) of UTF8 data encode the character. + This only works right if z points to a well-formed UTF8 string. + Byte-0 Byte-1 Byte-2 Byte-3 Value + 0xxxxxxx 00000000 00000000 0xxxxxxx + 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx + 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx + 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx +*/ +static uint32_t UTF8ToUnicode(const unsigned char* z, int nKey, unsigned char& bytes) +{ + // Lookup table used decode the first byte of a multi-byte UTF8 character + // clang-format off + static const unsigned char utf8Trans1[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, + }; + // clang-format on + + uint32_t c; + bytes = 0; + c = z[0]; + if (c >= 0xc0) + { + c = utf8Trans1[c - 0xc0]; + int index = 1; + while (index < nKey && (z[index] & 0xc0) == 0x80) + { + c = (c << 6) + (0x3f & z[index]); + index++; + } + if (c < 0x80 || (c & 0xFFFFF800) == 0xD800 || (c & 0xFFFFFFFE) == 0xFFFE) + c = 0xFFFD; + bytes = static_cast(index - 1); + } + return c; +} + +/* + SQLite collating function, see sqlite3_create_collation + The equivalent of AlphaNumericCompare() but for comparing UTF8 encoded data + + This only processes enough data to find a difference, and avoids expensive data conversions. + When sorting in memory item data is converted once to wstring in advance prior to sorting, the + SQLite callback function can not do that kind of preparation. Instead, in order to use + AlphaNumericCompare(), it would have to repeatedly convert the full input data to wstring for + every pair comparison made. That approach was found to be 10 times slower than using this + separate routine. +*/ +int StringUtils::AlphaNumericCollation(int nKey1, const void* pKey1, int nKey2, const void* pKey2) +{ + // Get exact matches of shorter text to start of larger test fast + int n = std::min(nKey1, nKey2); + int r = memcmp(pKey1, pKey2, n); + if (r == 0) + return nKey1 - nKey2; + + //Not a binary match, so process character at a time + const unsigned char* zA = static_cast(pKey1); + const unsigned char* zB = static_cast(pKey2); + wchar_t lc, rc; + unsigned char bytes; + int64_t lnum, rnum; + bool lsym, rsym; + int ld, rd; + int i = 0; + int j = 0; + // Looping Unicode point at a time through potentially 1 to 4 multi-byte encoded UTF8 data + while (i < nKey1 && j < nKey2) + { + // Check if we have numerical values, compare only up to 15 digits + if (isdigit(zA[i]) && isdigit(zB[j])) + { + lnum = zA[i] - '0'; + ld = i + 1; + while (ld < nKey1 && isdigit(zA[ld]) && ld < i + 15) + { + lnum *= 10; + lnum += zA[ld] - '0'; + ld++; + } + rnum = zB[j] - '0'; + rd = j + 1; + while (rd < nKey2 && isdigit(zB[rd]) && rd < j + 15) + { + rnum *= 10; + rnum += zB[rd] - '0'; + rd++; + } + // do we have numbers? + if (lnum != rnum) + { // yes - and they're different! + return lnum - rnum; + } + // Advance to after digits + i = ld; + j = rd; + continue; + } + // Put ascii punctuation and symbols e.g. !#$&()*+,-./:;<=>?@[\]^_ `{|}~ before the other + // alphanumeric ascii, rather than some being mixed between the numbers and letters, and + // above all other unicode letters, symbols and punctuation. + // (Locale collation of these chars varies across platforms) + lsym = (zA[i] >= 32 && zA[i] < '0') || (zA[i] > '9' && zA[i] < 'A') || + (zA[i] > 'Z' && zA[i] < 'a') || (zA[i] > 'z' && zA[i] < 128); + rsym = (zB[j] >= 32 && zB[j] < '0') || (zB[j] > '9' && zB[j] < 'A') || + (zB[j] > 'Z' && zB[j] < 'a') || (zB[j] > 'z' && zB[j] < 128); + if (lsym && !rsym) + return -1; + if (!lsym && rsym) + return 1; + if (lsym && rsym) + { + if (zA[i] != zB[j]) + return zA[i] - zB[j]; + else + { // Same symbol advance to next + i++; + j++; + continue; + } + } + //Decode single (1 to 4 bytes) UTF8 character to Unicode + lc = UTF8ToUnicode(&zA[i], nKey1 - i, bytes); + i += bytes; + rc = UTF8ToUnicode(&zB[j], nKey2 - j, bytes); + j += bytes; + if (!g_langInfo.UseLocaleCollation()) + { + // Apply case sensitive accent folding collation to non-ascii chars. + // This mimics utf8_general_ci collation, and provides simple collation of LATIN-1 chars + // for any platform that doesn't have a language specific collate facet implemented + if (lc > 128) + lc = GetCollationWeight(lc); + if (rc > 128) + rc = GetCollationWeight(rc); + } + // Caseless comparison so convert ascii upper case to lower case + if (lc >= 'A' && lc <= 'Z') + lc += 'a' - 'A'; + if (rc >= 'A' && rc <= 'Z') + rc += 'a' - 'A'; + + if (lc != rc) + { + if (!g_langInfo.UseLocaleCollation() || (lc <= 128 && rc <= 128)) + // Compare unicode (having applied accent folding collation to non-ascii chars). + return lc - rc; + else + { + // Fetch collation facet from locale to do comparison of wide char although on some + // platforms this is not langauge specific but just compares unicode + const std::collate& coll = + std::use_facet>(g_langInfo.GetSystemLocale()); + int cmp_res = coll.compare(&lc, &lc + 1, &rc, &rc + 1); + if (cmp_res != 0) + return cmp_res; + } + } + i++; + j++; + } + // Compared characters of shortest are the same as longest, length determines order + return (nKey1 - nKey2); +} + +int StringUtils::DateStringToYYYYMMDD(const std::string &dateString) +{ + std::vector days = StringUtils::Split(dateString, '-'); + if (days.size() == 1) + return atoi(days[0].c_str()); + else if (days.size() == 2) + return atoi(days[0].c_str())*100+atoi(days[1].c_str()); + else if (days.size() == 3) + return atoi(days[0].c_str())*10000+atoi(days[1].c_str())*100+atoi(days[2].c_str()); + else + return -1; +} + +std::string StringUtils::ISODateToLocalizedDate(const std::string& strIsoDate) +{ + // Convert ISO8601 date strings YYYY, YYYY-MM, or YYYY-MM-DD to (partial) localized date strings + CDateTime date; + std::string formattedDate = strIsoDate; + if (formattedDate.size() == 10) + { + date.SetFromDBDate(strIsoDate); + formattedDate = date.GetAsLocalizedDate(); + } + else if (formattedDate.size() == 7) + { + std::string strFormat = date.GetAsLocalizedDate(false); + std::string tempdate; + // find which date separator we are using. Can be -./ + size_t pos = strFormat.find_first_of("-./"); + if (pos != std::string::npos) + { + bool yearFirst = strFormat.find("1601") == 0; // true if year comes first + std::string sep = strFormat.substr(pos, 1); + if (yearFirst) + { // build formatted date with year first, then separator and month + tempdate = formattedDate.substr(0, 4); + tempdate += sep; + tempdate += formattedDate.substr(5, 2); + } + else + { + tempdate = formattedDate.substr(5, 2); + tempdate += sep; + tempdate += formattedDate.substr(0, 4); + } + formattedDate = tempdate; + } + // return either just the year or the locally formatted version of the ISO date + } + return formattedDate; +} + +long StringUtils::TimeStringToSeconds(const std::string &timeString) +{ + std::string strCopy(timeString); + StringUtils::Trim(strCopy); + if(StringUtils::EndsWithNoCase(strCopy, " min")) + { + // this is imdb format of "XXX min" + return 60 * atoi(strCopy.c_str()); + } + else + { + std::vector secs = StringUtils::Split(strCopy, ':'); + int timeInSecs = 0; + for (unsigned int i = 0; i < 3 && i < secs.size(); i++) + { + timeInSecs *= 60; + timeInSecs += atoi(secs[i].c_str()); + } + return timeInSecs; + } +} + +std::string StringUtils::SecondsToTimeString(long lSeconds, TIME_FORMAT format) +{ + bool isNegative = lSeconds < 0; + lSeconds = std::abs(lSeconds); + + std::string strHMS; + if (format == TIME_FORMAT_SECS) + strHMS = StringUtils::Format("%i", lSeconds); + else if (format == TIME_FORMAT_MINS) + strHMS = StringUtils::Format("%i", lrintf(static_cast(lSeconds) / 60.0f)); + else if (format == TIME_FORMAT_HOURS) + strHMS = StringUtils::Format("%i", lrintf(static_cast(lSeconds) / 3600.0f)); + else if (format & TIME_FORMAT_M) + strHMS += StringUtils::Format("%i", lSeconds % 3600 / 60); + else + { + int hh = lSeconds / 3600; + lSeconds = lSeconds % 3600; + int mm = lSeconds / 60; + int ss = lSeconds % 60; + + if (format == TIME_FORMAT_GUESS) + format = (hh >= 1) ? TIME_FORMAT_HH_MM_SS : TIME_FORMAT_MM_SS; + if (format & TIME_FORMAT_HH) + strHMS += StringUtils::Format("%2.2i", hh); + else if (format & TIME_FORMAT_H) + strHMS += StringUtils::Format("%i", hh); + if (format & TIME_FORMAT_MM) + strHMS += StringUtils::Format(strHMS.empty() ? "%2.2i" : ":%2.2i", mm); + if (format & TIME_FORMAT_SS) + strHMS += StringUtils::Format(strHMS.empty() ? "%2.2i" : ":%2.2i", ss); + } + + if (isNegative) + strHMS = "-" + strHMS; + + return strHMS; +} + +bool StringUtils::IsNaturalNumber(const std::string& str) +{ + size_t i = 0, n = 0; + // allow whitespace,digits,whitespace + while (i < str.size() && isspace((unsigned char) str[i])) + i++; + while (i < str.size() && isdigit((unsigned char) str[i])) + { + i++; n++; + } + while (i < str.size() && isspace((unsigned char) str[i])) + i++; + return i == str.size() && n > 0; +} + +bool StringUtils::IsInteger(const std::string& str) +{ + size_t i = 0, n = 0; + // allow whitespace,-,digits,whitespace + while (i < str.size() && isspace((unsigned char) str[i])) + i++; + if (i < str.size() && str[i] == '-') + i++; + while (i < str.size() && isdigit((unsigned char) str[i])) + { + i++; n++; + } + while (i < str.size() && isspace((unsigned char) str[i])) + i++; + return i == str.size() && n > 0; +} + +int StringUtils::asciidigitvalue(char chr) +{ + if (!isasciidigit(chr)) + return -1; + + return chr - '0'; +} + +int StringUtils::asciixdigitvalue(char chr) +{ + int v = asciidigitvalue(chr); + if (v >= 0) + return v; + if (chr >= 'a' && chr <= 'f') + return chr - 'a' + 10; + if (chr >= 'A' && chr <= 'F') + return chr - 'A' + 10; + + return -1; +} + + +void StringUtils::RemoveCRLF(std::string& strLine) +{ + StringUtils::TrimRight(strLine, "\n\r"); +} + +std::string StringUtils::SizeToString(int64_t size) +{ + std::string strLabel; + const char prefixes[] = {' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'}; + unsigned int i = 0; + double s = (double)size; + while (i < ARRAY_SIZE(prefixes) && s >= 1000.0) + { + s /= 1024.0; + i++; + } + + if (!i) + strLabel = StringUtils::Format("%.lf B", s); + else if (i == ARRAY_SIZE(prefixes)) + { + if (s >= 1000.0) + strLabel = StringUtils::Format(">999.99 %cB", prefixes[i - 1]); + else + strLabel = StringUtils::Format("%.2lf %cB", s, prefixes[i - 1]); + } + else if (s >= 100.0) + strLabel = StringUtils::Format("%.1lf %cB", s, prefixes[i]); + else + strLabel = StringUtils::Format("%.2lf %cB", s, prefixes[i]); + + return strLabel; +} + +std::string StringUtils::BinaryStringToString(const std::string& in) +{ + std::string out; + out.reserve(in.size() / 2); + for (const char *cur = in.c_str(), *end = cur + in.size(); cur != end; ++cur) { + if (*cur == '\\') { + ++cur; + if (cur == end) { + break; + } + if (isdigit(*cur)) { + char* end; + unsigned long num = strtol(cur, &end, 10); + cur = end - 1; + out.push_back(num); + continue; + } + } + out.push_back(*cur); + } + return out; +} + +std::string StringUtils::ToHexadecimal(const std::string& in) +{ + std::ostringstream ss; + ss << std::hex; + for (unsigned char ch : in) { + ss << std::setw(2) << std::setfill('0') << static_cast (ch); + } + return ss.str(); +} + +// return -1 if not, else return the utf8 char length. +int IsUTF8Letter(const unsigned char *str) +{ + // reference: + // unicode -> utf8 table: http://www.utf8-chartable.de/ + // latin characters in unicode: http://en.wikipedia.org/wiki/Latin_characters_in_Unicode + unsigned char ch = str[0]; + if (!ch) + return -1; + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) + return 1; + if (!(ch & 0x80)) + return -1; + unsigned char ch2 = str[1]; + if (!ch2) + return -1; + // check latin 1 letter table: http://en.wikipedia.org/wiki/C1_Controls_and_Latin-1_Supplement + if (ch == 0xC3 && ch2 >= 0x80 && ch2 <= 0xBF && ch2 != 0x97 && ch2 != 0xB7) + return 2; + // check latin extended A table: http://en.wikipedia.org/wiki/Latin_Extended-A + if (ch >= 0xC4 && ch <= 0xC7 && ch2 >= 0x80 && ch2 <= 0xBF) + return 2; + // check latin extended B table: http://en.wikipedia.org/wiki/Latin_Extended-B + // and International Phonetic Alphabet: http://en.wikipedia.org/wiki/IPA_Extensions_(Unicode_block) + if (((ch == 0xC8 || ch == 0xC9) && ch2 >= 0x80 && ch2 <= 0xBF) + || (ch == 0xCA && ch2 >= 0x80 && ch2 <= 0xAF)) + return 2; + return -1; +} + +size_t StringUtils::FindWords(const char *str, const char *wordLowerCase) +{ + // NOTE: This assumes word is lowercase! + const unsigned char *s = (const unsigned char *)str; + do + { + // start with a compare + const unsigned char *c = s; + const unsigned char *w = (const unsigned char *)wordLowerCase; + bool same = true; + while (same && *c && *w) + { + unsigned char lc = *c++; + if (lc >= 'A' && lc <= 'Z') + lc += 'a'-'A'; + + if (lc != *w++) // different + same = false; + } + if (same && *w == 0) // only the same if word has been exhausted + return (const char *)s - str; + + // otherwise, skip current word (composed by latin letters) or number + int l; + if (*s >= '0' && *s <= '9') + { + ++s; + while (*s >= '0' && *s <= '9') ++s; + } + else if ((l = IsUTF8Letter(s)) > 0) + { + s += l; + while ((l = IsUTF8Letter(s)) > 0) s += l; + } + else + ++s; + while (*s && *s == ' ') s++; + + // and repeat until we're done + } while (*s); + + return std::string::npos; +} + +// assumes it is called from after the first open bracket is found +int StringUtils::FindEndBracket(const std::string &str, char opener, char closer, int startPos) +{ + int blocks = 1; + for (unsigned int i = startPos; i < str.size(); i++) + { + if (str[i] == opener) + blocks++; + else if (str[i] == closer) + { + blocks--; + if (!blocks) + return i; + } + } + + return (int)std::string::npos; +} + +void StringUtils::WordToDigits(std::string &word) +{ + static const char word_to_letter[] = "22233344455566677778889999"; + StringUtils::ToLower(word); + for (unsigned int i = 0; i < word.size(); ++i) + { // NB: This assumes ascii, which probably needs extending at some point. + char letter = word[i]; + if ((letter >= 'a' && letter <= 'z')) // assume contiguous letter range + { + word[i] = word_to_letter[letter-'a']; + } + else if (letter < '0' || letter > '9') // We want to keep 0-9! + { + word[i] = ' '; // replace everything else with a space + } + } +} + +std::string StringUtils::CreateUUID() +{ +#ifdef HAVE_NEW_CROSSGUID + return xg::newGuid().str(); +#else + static GuidGenerator guidGenerator; + auto guid = guidGenerator.newGuid(); + + std::stringstream strGuid; strGuid << guid; + return strGuid.str(); +#endif +} + +bool StringUtils::ValidateUUID(const std::string &uuid) +{ + CRegExp guidRE; + guidRE.RegComp(ADDON_GUID_RE); + return (guidRE.RegFind(uuid.c_str()) == 0); +} + +double StringUtils::CompareFuzzy(const std::string &left, const std::string &right) +{ + return (0.5 + fstrcmp(left.c_str(), right.c_str()) * (left.length() + right.length())) / 2.0; +} + +int StringUtils::FindBestMatch(const std::string &str, const std::vector &strings, double &matchscore) +{ + int best = -1; + matchscore = 0; + + int i = 0; + for (std::vector::const_iterator it = strings.begin(); it != strings.end(); ++it, i++) + { + int maxlength = std::max(str.length(), it->length()); + double score = StringUtils::CompareFuzzy(str, *it) / maxlength; + if (score > matchscore) + { + matchscore = score; + best = i; + } + } + return best; +} + +bool StringUtils::ContainsKeyword(const std::string &str, const std::vector &keywords) +{ + for (std::vector::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + if (str.find(*it) != str.npos) + return true; + } + return false; +} + +size_t StringUtils::utf8_strlen(const char *s) +{ + size_t length = 0; + while (*s) + { + if ((*s++ & 0xC0) != 0x80) + length++; + } + return length; +} + +std::string StringUtils::Paramify(const std::string ¶m) +{ + std::string result = param; + // escape backspaces + StringUtils::Replace(result, "\\", "\\\\"); + // escape double quotes + StringUtils::Replace(result, "\"", "\\\""); + + // add double quotes around the whole string + return "\"" + result + "\""; +} + +std::vector StringUtils::Tokenize(const std::string &input, const std::string &delimiters) +{ + std::vector tokens; + Tokenize(input, tokens, delimiters); + return tokens; +} + +void StringUtils::Tokenize(const std::string& input, std::vector& tokens, const std::string& delimiters) +{ + tokens.clear(); + // Skip delimiters at beginning. + std::string::size_type dataPos = input.find_first_not_of(delimiters); + while (dataPos != std::string::npos) + { + // Find next delimiter + const std::string::size_type nextDelimPos = input.find_first_of(delimiters, dataPos); + // Found a token, add it to the vector. + tokens.push_back(input.substr(dataPos, nextDelimPos - dataPos)); + // Skip delimiters. Note the "not_of" + dataPos = input.find_first_not_of(delimiters, nextDelimPos); + } +} + +std::vector StringUtils::Tokenize(const std::string &input, const char delimiter) +{ + std::vector tokens; + Tokenize(input, tokens, delimiter); + return tokens; +} + +void StringUtils::Tokenize(const std::string& input, std::vector& tokens, const char delimiter) +{ + tokens.clear(); + // Skip delimiters at beginning. + std::string::size_type dataPos = input.find_first_not_of(delimiter); + while (dataPos != std::string::npos) + { + // Find next delimiter + const std::string::size_type nextDelimPos = input.find(delimiter, dataPos); + // Found a token, add it to the vector. + tokens.push_back(input.substr(dataPos, nextDelimPos - dataPos)); + // Skip delimiters. Note the "not_of" + dataPos = input.find_first_not_of(delimiter, nextDelimPos); + } +} + +uint64_t StringUtils::ToUint64(std::string str, uint64_t fallback) noexcept +{ + std::istringstream iss(str); + uint64_t result(fallback); + iss >> result; + return result; +} + +std::string StringUtils::FormatFileSize(uint64_t bytes) +{ + const std::array units{{"B", "kB", "MB", "GB", "TB", "PB"}}; + if (bytes < 1000) + return Format("%" PRIu64 "B", bytes); + + size_t i = 0; + double value = static_cast(bytes); + while (i + 1 < units.size() && value >= 999.5) + { + ++i; + value /= 1024.0; + } + unsigned int decimals = value < 9.995 ? 2 : (value < 99.95 ? 1 : 0); + auto frmt = "%." + Format("%u", decimals) + "f%s"; + return Format(frmt.c_str(), value, units[i].c_str()); +} + +const std::locale& StringUtils::GetOriginalLocale() noexcept +{ + return g_langInfo.GetOriginalLocale(); +} diff --git a/xbmc/utils/StringUtils.h b/xbmc/utils/StringUtils.h new file mode 100644 index 0000000..6aab4cd --- /dev/null +++ b/xbmc/utils/StringUtils.h @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +//----------------------------------------------------------------------- +// +// File: StringUtils.h +// +// Purpose: ATL split string utility +// Author: Paul J. Weiss +// +// Modified to support J O'Leary's std::string class by kraqh3d +// +//------------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include + +// workaround for broken [[depreciated]] in coverity +#if defined(__COVERITY__) +#undef FMT_DEPRECATED +#define FMT_DEPRECATED +#endif +#include + +#if FMT_VERSION >= 40000 +#include +#endif + +#include "XBDateTime.h" +#include "utils/params_check_macros.h" + +/*! \brief C-processor Token stringification + +The following macros can be used to stringify definitions to +C style strings. + +Example: + +#define foo 4 +DEF_TO_STR_NAME(foo) // outputs "foo" +DEF_TO_STR_VALUE(foo) // outputs "4" + +*/ + +#define DEF_TO_STR_NAME(x) #x +#define DEF_TO_STR_VALUE(x) DEF_TO_STR_NAME(x) + +template::value, int> = 0> +constexpr auto&& EnumToInt(T&& arg) noexcept +{ + return arg; +} +template::value, int> = 0> +constexpr auto EnumToInt(T&& arg) noexcept +{ + return static_cast(arg); +} + +class StringUtils +{ +public: + /*! \brief Get a formatted string similar to sprintf + + Beware that this does not support directly passing in + std::string objects. You need to call c_str() to pass + the const char* buffer representing the value of the + std::string object. + + \param fmt Format of the resulting string + \param ... variable number of value type arguments + \return Formatted string + */ + template + static std::string Format(const std::string& fmt, Args&&... args) + { + // coverity[fun_call_w_exception : FALSE] + auto result = ::fmt::format(fmt, EnumToInt(std::forward(args))...); + if (result == fmt) + result = ::fmt::sprintf(fmt, EnumToInt(std::forward(args))...); + + return result; + } + template + static std::wstring Format(const std::wstring& fmt, Args&&... args) + { + // coverity[fun_call_w_exception : FALSE] + auto result = ::fmt::format(fmt, EnumToInt(std::forward(args))...); + if (result == fmt) + result = ::fmt::sprintf(fmt, EnumToInt(std::forward(args))...); + + return result; + } + + static std::string FormatV(PRINTF_FORMAT_STRING const char *fmt, va_list args); + static std::wstring FormatV(PRINTF_FORMAT_STRING const wchar_t *fmt, va_list args); + static void ToUpper(std::string &str); + static void ToUpper(std::wstring &str); + static void ToLower(std::string &str); + static void ToLower(std::wstring &str); + static void ToCapitalize(std::string &str); + static void ToCapitalize(std::wstring &str); + static bool EqualsNoCase(const std::string &str1, const std::string &str2); + static bool EqualsNoCase(const std::string &str1, const char *s2); + static bool EqualsNoCase(const char *s1, const char *s2); + static int CompareNoCase(const std::string& str1, const std::string& str2, size_t n = 0); + static int CompareNoCase(const char* s1, const char* s2, size_t n = 0); + static int ReturnDigits(const std::string &str); + static std::string Left(const std::string &str, size_t count); + static std::string Mid(const std::string &str, size_t first, size_t count = std::string::npos); + static std::string Right(const std::string &str, size_t count); + static std::string& Trim(std::string &str); + static std::string& Trim(std::string &str, const char* const chars); + static std::string& TrimLeft(std::string &str); + static std::string& TrimLeft(std::string &str, const char* const chars); + static std::string& TrimRight(std::string &str); + static std::string& TrimRight(std::string &str, const char* const chars); + static std::string& RemoveDuplicatedSpacesAndTabs(std::string& str); + static int Replace(std::string &str, char oldChar, char newChar); + static int Replace(std::string &str, const std::string &oldStr, const std::string &newStr); + static int Replace(std::wstring &str, const std::wstring &oldStr, const std::wstring &newStr); + static bool StartsWith(const std::string &str1, const std::string &str2); + static bool StartsWith(const std::string &str1, const char *s2); + static bool StartsWith(const char *s1, const char *s2); + static bool StartsWithNoCase(const std::string &str1, const std::string &str2); + static bool StartsWithNoCase(const std::string &str1, const char *s2); + static bool StartsWithNoCase(const char *s1, const char *s2); + static bool EndsWith(const std::string &str1, const std::string &str2); + static bool EndsWith(const std::string &str1, const char *s2); + static bool EndsWithNoCase(const std::string &str1, const std::string &str2); + static bool EndsWithNoCase(const std::string &str1, const char *s2); + + template + static std::string Join(const CONTAINER &strings, const std::string& delimiter) + { + std::string result; + for (const auto& str : strings) + result += str + delimiter; + + if (!result.empty()) + result.erase(result.size() - delimiter.size()); + return result; + } + + /*! \brief Splits the given input string using the given delimiter into separate strings. + + If the given input string is empty the result will be an empty array (not + an array containing an empty string). + + \param input Input string to be split + \param delimiter Delimiter to be used to split the input string + \param iMaxStrings (optional) Maximum number of splitted strings + */ + static std::vector Split(const std::string& input, const std::string& delimiter, unsigned int iMaxStrings = 0); + static std::vector Split(const std::string& input, const char delimiter, size_t iMaxStrings = 0); + static std::vector Split(const std::string& input, const std::vector &delimiters); + /*! \brief Splits the given input string using the given delimiter into separate strings. + + If the given input string is empty nothing will be put into the target iterator. + + \param d_first the beginning of the destination range + \param input Input string to be split + \param delimiter Delimiter to be used to split the input string + \param iMaxStrings (optional) Maximum number of splitted strings + \return output iterator to the element in the destination range, one past the last element + * that was put there + */ + template + static OutputIt SplitTo(OutputIt d_first, const std::string& input, const std::string& delimiter, unsigned int iMaxStrings = 0) + { + OutputIt dest = d_first; + + if (input.empty()) + return dest; + if (delimiter.empty()) + { + *d_first++ = input; + return dest; + } + + const size_t delimLen = delimiter.length(); + size_t nextDelim; + size_t textPos = 0; + do + { + if (--iMaxStrings == 0) + { + *dest++ = input.substr(textPos); + break; + } + nextDelim = input.find(delimiter, textPos); + *dest++ = input.substr(textPos, nextDelim - textPos); + textPos = nextDelim + delimLen; + } while (nextDelim != std::string::npos); + + return dest; + } + template + static OutputIt SplitTo(OutputIt d_first, const std::string& input, const char delimiter, size_t iMaxStrings = 0) + { + return SplitTo(d_first, input, std::string(1, delimiter), iMaxStrings); + } + template + static OutputIt SplitTo(OutputIt d_first, const std::string& input, const std::vector &delimiters) + { + OutputIt dest = d_first; + if (input.empty()) + return dest; + + if (delimiters.empty()) + { + *dest++ = input; + return dest; + } + std::string str = input; + for (size_t di = 1; di < delimiters.size(); di++) + StringUtils::Replace(str, delimiters[di], delimiters[0]); + return SplitTo(dest, str, delimiters[0]); + } + + /*! \brief Splits the given input strings using the given delimiters into further separate strings. + + If the given input string vector is empty the result will be an empty array (not + an array containing an empty string). + + Delimiter strings are applied in order, so once the (optional) maximum number of + items is produced no other delimiters are applied. This produces different results + to applying all delimiters at once e.g. "a/b#c/d" becomes "a", "b#c", "d" rather + than "a", "b", "c/d" + + \param input Input vector of strings each to be split + \param delimiters Delimiter strings to be used to split the input strings + \param iMaxStrings (optional) Maximum number of resulting split strings + */ + static std::vector SplitMulti(const std::vector &input, const std::vector &delimiters, unsigned int iMaxStrings = 0); + static int FindNumber(const std::string& strInput, const std::string &strFind); + static int64_t AlphaNumericCompare(const wchar_t *left, const wchar_t *right); + static int AlphaNumericCollation(int nKey1, const void* pKey1, int nKey2, const void* pKey2); + static long TimeStringToSeconds(const std::string &timeString); + static void RemoveCRLF(std::string& strLine); + + /*! \brief utf8 version of strlen - skips any non-starting bytes in the count, thus returning the number of utf8 characters + \param s c-string to find the length of. + \return the number of utf8 characters in the string. + */ + static size_t utf8_strlen(const char *s); + + /*! \brief convert a time in seconds to a string based on the given time format + \param seconds time in seconds + \param format the format we want the time in. + \return the formatted time + \sa TIME_FORMAT + */ + static std::string SecondsToTimeString(long seconds, TIME_FORMAT format = TIME_FORMAT_GUESS); + + /*! \brief check whether a string is a natural number. + Matches [ \t]*[0-9]+[ \t]* + \param str the string to check + \return true if the string is a natural number, false otherwise. + */ + static bool IsNaturalNumber(const std::string& str); + + /*! \brief check whether a string is an integer. + Matches [ \t]*[\-]*[0-9]+[ \t]* + \param str the string to check + \return true if the string is an integer, false otherwise. + */ + static bool IsInteger(const std::string& str); + + /* The next several isasciiXX and asciiXXvalue functions are locale independent (US-ASCII only), + * as opposed to standard ::isXX (::isalpha, ::isdigit...) which are locale dependent. + * Next functions get parameter as char and don't need double cast ((int)(unsigned char) is required for standard functions). */ + inline static bool isasciidigit(char chr) // locale independent + { + return chr >= '0' && chr <= '9'; + } + inline static bool isasciixdigit(char chr) // locale independent + { + return (chr >= '0' && chr <= '9') || (chr >= 'a' && chr <= 'f') || (chr >= 'A' && chr <= 'F'); + } + static int asciidigitvalue(char chr); // locale independent + static int asciixdigitvalue(char chr); // locale independent + inline static bool isasciiuppercaseletter(char chr) // locale independent + { + return (chr >= 'A' && chr <= 'Z'); + } + inline static bool isasciilowercaseletter(char chr) // locale independent + { + return (chr >= 'a' && chr <= 'z'); + } + inline static bool isasciialphanum(char chr) // locale independent + { + return isasciiuppercaseletter(chr) || isasciilowercaseletter(chr) || isasciidigit(chr); + } + static std::string SizeToString(int64_t size); + static const std::string Empty; + static size_t FindWords(const char *str, const char *wordLowerCase); + static int FindEndBracket(const std::string &str, char opener, char closer, int startPos = 0); + static int DateStringToYYYYMMDD(const std::string &dateString); + static std::string ISODateToLocalizedDate (const std::string& strIsoDate); + static void WordToDigits(std::string &word); + static std::string CreateUUID(); + static bool ValidateUUID(const std::string &uuid); // NB only validates syntax + static double CompareFuzzy(const std::string &left, const std::string &right); + static int FindBestMatch(const std::string &str, const std::vector &strings, double &matchscore); + static bool ContainsKeyword(const std::string &str, const std::vector &keywords); + + /*! \brief Convert the string of binary chars to the actual string. + + Convert the string representation of binary chars to the actual string. + For example \1\2\3 is converted to a string with binary char \1, \2 and \3 + + \param param String to convert + \return Converted string + */ + static std::string BinaryStringToString(const std::string& in); + /** + * Convert each character in the string to its hexadecimal + * representation and return the concatenated result + * + * example: "abc\n" -> "6162630a" + */ + static std::string ToHexadecimal(const std::string& in); + /*! \brief Format the string with locale separators. + + Format the string with locale separators. + For example 10000.57 in en-us is '10,000.57' but in italian is '10.000,57' + + \param param String to format + \return Formatted string + */ + template + static std::string FormatNumber(T num) + { + std::stringstream ss; +// ifdef is needed because when you set _ITERATOR_DEBUG_LEVEL=0 and you use custom numpunct you will get runtime error in debug mode +// for more info https://connect.microsoft.com/VisualStudio/feedback/details/2655363 +#if !(defined(_DEBUG) && defined(TARGET_WINDOWS)) + ss.imbue(GetOriginalLocale()); +#endif + ss.precision(1); + ss << std::fixed << num; + return ss.str(); + } + + /*! \brief Escapes the given string to be able to be used as a parameter. + + Escapes backslashes and double-quotes with an additional backslash and + adds double-quotes around the whole string. + + \param param String to escape/paramify + \return Escaped/Paramified string + */ + static std::string Paramify(const std::string ¶m); + + /*! \brief Split a string by the specified delimiters. + Splits a string using one or more delimiting characters, ignoring empty tokens. + Differs from Split() in two ways: + 1. The delimiters are treated as individual characters, rather than a single delimiting string. + 2. Empty tokens are ignored. + \return a vector of tokens + */ + static std::vector Tokenize(const std::string& input, const std::string& delimiters); + static void Tokenize(const std::string& input, std::vector& tokens, const std::string& delimiters); + static std::vector Tokenize(const std::string& input, const char delimiter); + static void Tokenize(const std::string& input, std::vector& tokens, const char delimiter); + static uint64_t ToUint64(std::string str, uint64_t fallback) noexcept; + + /*! + * Returns bytes in a human readable format using the smallest unit that will fit `bytes` in at + * most three digits. The number of decimals are adjusted with significance such that 'small' + * numbers will have more decimals than larger ones. + * + * For example: 1024 bytes will be formatted as "1.00kB", 10240 bytes as "10.0kB" and + * 102400 bytes as "100kB". See TestStringUtils for more examples. + */ + static std::string FormatFileSize(uint64_t bytes); + +private: + /*! + * Wrapper for CLangInfo::GetOriginalLocale() which allows us to + * avoid including LangInfo.h from this header. + */ + static const std::locale& GetOriginalLocale() noexcept; +}; + +struct sortstringbyname +{ + bool operator()(const std::string& strItem1, const std::string& strItem2) + { + return StringUtils::CompareNoCase(strItem1, strItem2) < 0; + } +}; diff --git a/xbmc/utils/StringValidation.cpp b/xbmc/utils/StringValidation.cpp new file mode 100644 index 0000000..386bfb9 --- /dev/null +++ b/xbmc/utils/StringValidation.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "StringValidation.h" + +#include "utils/StringUtils.h" + +bool StringValidation::IsInteger(const std::string &input, void *data) +{ + return StringUtils::IsInteger(input); +} + +bool StringValidation::IsPositiveInteger(const std::string &input, void *data) +{ + return StringUtils::IsNaturalNumber(input); +} + +bool StringValidation::IsTime(const std::string &input, void *data) +{ + std::string strTime = input; + StringUtils::Trim(strTime); + + if (StringUtils::EndsWithNoCase(strTime, " min")) + { + strTime = StringUtils::Left(strTime, strTime.size() - 4); + StringUtils::TrimRight(strTime); + + return IsPositiveInteger(strTime, NULL); + } + else + { + // support [[HH:]MM:]SS + std::vector bits = StringUtils::Split(input, ":"); + if (bits.size() > 3) + return false; + + for (std::vector::const_iterator i = bits.begin(); i != bits.end(); ++i) + if (!IsPositiveInteger(*i, NULL)) + return false; + + return true; + } + return false; +} diff --git a/xbmc/utils/StringValidation.h b/xbmc/utils/StringValidation.h new file mode 100644 index 0000000..34d54e8 --- /dev/null +++ b/xbmc/utils/StringValidation.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +class StringValidation +{ +public: + typedef bool (*Validator)(const std::string &input, void *data); + + static bool NonEmpty(const std::string &input, void *data) { return !input.empty(); } + static bool IsInteger(const std::string &input, void *data); + static bool IsPositiveInteger(const std::string &input, void *data); + static bool IsTime(const std::string &input, void *data); + +private: + StringValidation() = default; +}; diff --git a/xbmc/utils/SystemInfo.cpp b/xbmc/utils/SystemInfo.cpp new file mode 100644 index 0000000..5b1d89e --- /dev/null +++ b/xbmc/utils/SystemInfo.cpp @@ -0,0 +1,1395 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include + +#include "threads/SystemClock.h" +#include "SystemInfo.h" +#ifndef TARGET_POSIX +#include +#else +#include +#endif +#include "CompileInfo.h" +#include "ServiceBroker.h" +#include "filesystem/CurlFile.h" +#include "filesystem/File.h" +#include "guilib/LocalizeStrings.h" +#include "guilib/guiinfo/GUIInfoLabels.h" +#include "network/Network.h" +#include "platform/Filesystem.h" +#include "rendering/RenderSystem.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/CPUInfo.h" +#include "utils/log.h" + +#ifdef TARGET_WINDOWS +#include +#include "utils/CharsetConverter.h" +#include + +#ifdef TARGET_WINDOWS_STORE +#include +#include + +using namespace winrt::Windows::ApplicationModel; +using namespace winrt::Windows::Security::ExchangeActiveSyncProvisioning; +using namespace winrt::Windows::System; +using namespace winrt::Windows::System::Profile; +#endif +#include +#include "platform/win32/CharsetConverter.h" +#endif +#if defined(TARGET_DARWIN) +#include "platform/darwin/DarwinUtils.h" +#endif +#include "powermanagement/PowerManager.h" +#include "utils/StringUtils.h" +#include "utils/XMLUtils.h" +#if defined(TARGET_ANDROID) +#include +#endif + +/* Platform identification */ +#if defined(TARGET_DARWIN) +#include +#include +#include +#include "utils/auto_buffer.h" +#elif defined(TARGET_ANDROID) +#include +#include +#elif defined(TARGET_FREEBSD) +#include +#elif defined(TARGET_LINUX) +#include "platform/linux/SysfsPath.h" + +#include +#endif + +#include + +/* Expand macro before stringify */ +#define STR_MACRO(x) #x +#define XSTR_MACRO(x) STR_MACRO(x) + +using namespace XFILE; + +#ifdef TARGET_WINDOWS_DESKTOP +static bool sysGetVersionExWByRef(OSVERSIONINFOEXW& osVerInfo) +{ + ZeroMemory(&osVerInfo, sizeof(osVerInfo)); + osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo); + + typedef NTSTATUS(__stdcall *RtlGetVersionPtr)(RTL_OSVERSIONINFOEXW* pOsInfo); + static HMODULE hNtDll = GetModuleHandleW(L"ntdll.dll"); + if (hNtDll != NULL) + { + static RtlGetVersionPtr RtlGetVer = (RtlGetVersionPtr) GetProcAddress(hNtDll, "RtlGetVersion"); + if (RtlGetVer && RtlGetVer(&osVerInfo) == 0) + return true; + } + // failed to get OS information directly from ntdll.dll + // use GetVersionExW() as fallback + // note: starting from Windows 8.1 GetVersionExW() may return unfaithful information + if (GetVersionExW((OSVERSIONINFOW*) &osVerInfo) != 0) + return true; + + ZeroMemory(&osVerInfo, sizeof(osVerInfo)); + return false; +} +#endif // TARGET_WINDOWS_DESKTOP + +#if defined(TARGET_LINUX) && !defined(TARGET_ANDROID) +static std::string getValueFromOs_release(std::string key) +{ + FILE* os_rel = fopen("/etc/os-release", "r"); + if (!os_rel) + return ""; + + char* buf = new char[10 * 1024]; // more than enough + size_t len = fread(buf, 1, 10 * 1024, os_rel); + fclose(os_rel); + if (len == 0) + { + delete[] buf; + return ""; + } + + std::string content(buf, len); + delete[] buf; + + // find begin of value string + size_t valStart = 0, seachPos; + key += '='; + if (content.compare(0, key.length(), key) == 0) + valStart = key.length(); + else + { + key = "\n" + key; + seachPos = 0; + do + { + seachPos = content.find(key, seachPos); + if (seachPos == std::string::npos) + return ""; + if (seachPos == 0 || content[seachPos - 1] != '\\') + valStart = seachPos + key.length(); + else + seachPos++; + } while (valStart == 0); + } + + if (content[valStart] == '\n') + return ""; + + // find end of value string + seachPos = valStart; + do + { + seachPos = content.find('\n', seachPos + 1); + } while (seachPos != std::string::npos && content[seachPos - 1] == '\\'); + size_t const valEnd = seachPos; + + std::string value(content, valStart, valEnd - valStart); + if (value.empty()) + return value; + + // remove quotes + if (value[0] == '\'' || value[0] == '"') + { + if (value.length() < 2) + return value; + size_t qEnd = value.rfind(value[0]); + if (qEnd != std::string::npos) + { + value.erase(qEnd); + value.erase(0, 1); + } + } + + // unescape characters + for (size_t slashPos = value.find('\\'); slashPos < value.length() - 1; slashPos = value.find('\\', slashPos)) + { + if (value[slashPos + 1] == '\n') + value.erase(slashPos, 2); + else + { + value.erase(slashPos, 1); + slashPos++; // skip unescaped character + } + } + + return value; +} + +enum lsb_rel_info_type +{ + lsb_rel_distributor, + lsb_rel_description, + lsb_rel_release, + lsb_rel_codename +}; + +static std::string getValueFromLsb_release(enum lsb_rel_info_type infoType) +{ + std::string key, command("unset PYTHONHOME; unset PYTHONPATH; lsb_release "); + switch (infoType) + { + case lsb_rel_distributor: + command += "-i"; + key = "Distributor ID:\t"; + break; + case lsb_rel_description: + command += "-d"; + key = "Description:\t"; + break; + case lsb_rel_release: + command += "-r"; + key = "Release:\t"; + break; + case lsb_rel_codename: + command += "-c"; + key = "Codename:\t"; + break; + default: + return ""; + } + command += " 2>/dev/null"; + FILE* lsb_rel = popen(command.c_str(), "r"); + if (lsb_rel == NULL) + return ""; + + char buf[300]; // more than enough + if (fgets(buf, 300, lsb_rel) == NULL) + { + pclose(lsb_rel); + return ""; + } + pclose(lsb_rel); + + std::string response(buf); + if (response.compare(0, key.length(), key) != 0) + return ""; + + return response.substr(key.length(), response.find('\n') - key.length()); +} +#endif // TARGET_LINUX && !TARGET_ANDROID + +CSysInfo g_sysinfo; + +CSysInfoJob::CSysInfoJob() = default; + +bool CSysInfoJob::DoWork() +{ + m_info.systemUptime = GetSystemUpTime(false); + m_info.systemTotalUptime = GetSystemUpTime(true); + m_info.internetState = GetInternetState(); + m_info.videoEncoder = GetVideoEncoder(); + m_info.cpuFrequency = + StringUtils::Format("%4.0f MHz", CServiceBroker::GetCPUInfo()->GetCPUFrequency()); + m_info.osVersionInfo = CSysInfo::GetOsPrettyNameWithVersion() + " (kernel: " + CSysInfo::GetKernelName() + " " + CSysInfo::GetKernelVersionFull() + ")"; + m_info.macAddress = GetMACAddress(); + m_info.batteryLevel = GetBatteryLevel(); + return true; +} + +const CSysData &CSysInfoJob::GetData() const +{ + return m_info; +} + +CSysData::INTERNET_STATE CSysInfoJob::GetInternetState() +{ + // Internet connection state! + XFILE::CCurlFile http; + if (http.IsInternet()) + return CSysData::CONNECTED; + return CSysData::DISCONNECTED; +} + +std::string CSysInfoJob::GetMACAddress() +{ + CNetworkInterface* iface = CServiceBroker::GetNetwork().GetFirstConnectedInterface(); + if (iface) + return iface->GetMacAddress(); + + return ""; +} + +std::string CSysInfoJob::GetVideoEncoder() +{ + return "GPU: " + CServiceBroker::GetRenderSystem()->GetRenderRenderer(); +} + +std::string CSysInfoJob::GetBatteryLevel() +{ + return StringUtils::Format("%d%%", CServiceBroker::GetPowerManager().BatteryLevel()); +} + +bool CSysInfoJob::SystemUpTime(int iInputMinutes, int &iMinutes, int &iHours, int &iDays) +{ + iHours = 0; iDays = 0; + iMinutes = iInputMinutes; + if (iMinutes >= 60) // Hour's + { + iHours = iMinutes / 60; + iMinutes = iMinutes - (iHours *60); + } + if (iHours >= 24) // Days + { + iDays = iHours / 24; + iHours = iHours - (iDays * 24); + } + return true; +} + +std::string CSysInfoJob::GetSystemUpTime(bool bTotalUptime) +{ + std::string strSystemUptime; + int iInputMinutes, iMinutes,iHours,iDays; + + if(bTotalUptime) + { + //Total Uptime + iInputMinutes = g_sysinfo.GetTotalUptime() + ((int)(XbmcThreads::SystemClockMillis() / 60000)); + } + else + { + //Current UpTime + iInputMinutes = (int)(XbmcThreads::SystemClockMillis() / 60000); + } + + SystemUpTime(iInputMinutes,iMinutes, iHours, iDays); + if (iDays > 0) + { + strSystemUptime = StringUtils::Format("%i %s, %i %s, %i %s", + iDays, g_localizeStrings.Get(12393).c_str(), + iHours, g_localizeStrings.Get(12392).c_str(), + iMinutes, g_localizeStrings.Get(12391).c_str()); + } + else if (iDays == 0 && iHours >= 1 ) + { + strSystemUptime = StringUtils::Format("%i %s, %i %s", + iHours, g_localizeStrings.Get(12392).c_str(), + iMinutes, g_localizeStrings.Get(12391).c_str()); + } + else if (iDays == 0 && iHours == 0 && iMinutes >= 0) + { + strSystemUptime = StringUtils::Format("%i %s", + iMinutes, g_localizeStrings.Get(12391).c_str()); + } + return strSystemUptime; +} + +std::string CSysInfo::TranslateInfo(int info) const +{ + switch(info) + { + case SYSTEM_VIDEO_ENCODER_INFO: + return m_info.videoEncoder; + case NETWORK_MAC_ADDRESS: + return m_info.macAddress; + case SYSTEM_OS_VERSION_INFO: + return m_info.osVersionInfo; + case SYSTEM_CPUFREQUENCY: + return m_info.cpuFrequency; + case SYSTEM_UPTIME: + return m_info.systemUptime; + case SYSTEM_TOTALUPTIME: + return m_info.systemTotalUptime; + case SYSTEM_INTERNET_STATE: + if (m_info.internetState == CSysData::CONNECTED) + return g_localizeStrings.Get(13296); + else + return g_localizeStrings.Get(13297); + case SYSTEM_BATTERY_LEVEL: + return m_info.batteryLevel; + default: + return ""; + } +} + +void CSysInfo::Reset() +{ + m_info.Reset(); +} + +CSysInfo::CSysInfo(void) : CInfoLoader(15 * 1000) +{ + memset(MD5_Sign, 0, sizeof(MD5_Sign)); + m_iSystemTimeTotalUp = 0; +} + +CSysInfo::~CSysInfo() = default; + +bool CSysInfo::Load(const TiXmlNode *settings) +{ + if (settings == NULL) + return false; + + const TiXmlElement *pElement = settings->FirstChildElement("general"); + if (pElement) + XMLUtils::GetInt(pElement, "systemtotaluptime", m_iSystemTimeTotalUp, 0, INT_MAX); + + return true; +} + +bool CSysInfo::Save(TiXmlNode *settings) const +{ + if (settings == NULL) + return false; + + TiXmlNode *generalNode = settings->FirstChild("general"); + if (generalNode == NULL) + { + TiXmlElement generalNodeNew("general"); + generalNode = settings->InsertEndChild(generalNodeNew); + if (generalNode == NULL) + return false; + } + XMLUtils::SetInt(generalNode, "systemtotaluptime", m_iSystemTimeTotalUp); + + return true; +} + +const std::string& CSysInfo::GetAppName(void) +{ + assert(CCompileInfo::GetAppName() != NULL); + static const std::string appName(CCompileInfo::GetAppName()); + + return appName; +} + +bool CSysInfo::GetDiskSpace(std::string drive,int& iTotal, int& iTotalFree, int& iTotalUsed, int& iPercentFree, int& iPercentUsed) +{ + using namespace KODI::PLATFORM::FILESYSTEM; + + space_info total = { 0 }; + std::error_code ec; + + // None of this makes sense but the idea of total space + // makes no sense on any system really. + // Return space for / or for C: as it's correct in a sense + // and not much worse than trying to count a total for different + // drives/mounts + if (drive.empty() || drive == "*") + { +#if defined(TARGET_WINDOWS) + drive = "C"; +#elif defined(TARGET_POSIX) + drive = "/"; +#endif + } + +#ifdef TARGET_WINDOWS_DESKTOP + using KODI::PLATFORM::WINDOWS::ToW; + UINT uidriveType = GetDriveType(ToW(drive + ":\\").c_str()); + if (uidriveType != DRIVE_UNKNOWN && uidriveType != DRIVE_NO_ROOT_DIR) + total = space(drive + ":\\", ec); +#elif defined(TARGET_POSIX) + total = space(drive, ec); +#endif + if (ec.value() != 0) + return false; + + iTotal = static_cast(total.capacity / MB); + iTotalFree = static_cast(total.free / MB); + iTotalUsed = iTotal - iTotalFree; + if (total.capacity > 0) + iPercentUsed = static_cast(100.0f * (total.capacity - total.free) / total.capacity + 0.5f); + else + iPercentUsed = 0; + + iPercentFree = 100 - iPercentUsed; + + return true; +} + +std::string CSysInfo::GetKernelName(bool emptyIfUnknown /*= false*/) +{ + static std::string kernelName; + if (kernelName.empty()) + { +#if defined(TARGET_WINDOWS_DESKTOP) + OSVERSIONINFOEXW osvi; + if (sysGetVersionExWByRef(osvi) && osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) + kernelName = "Windows NT"; +#elif defined(TARGET_WINDOWS_STORE) + auto e = EasClientDeviceInformation(); + auto os = e.OperatingSystem(); + g_charsetConverter.wToUTF8(std::wstring(os.c_str()), kernelName); +#elif defined(TARGET_POSIX) + struct utsname un; + if (uname(&un) == 0) + kernelName.assign(un.sysname); +#endif // defined(TARGET_POSIX) + + if (kernelName.empty()) + kernelName = "Unknown kernel"; // can't detect + } + + if (emptyIfUnknown && kernelName == "Unknown kernel") + return ""; + + return kernelName; +} + +std::string CSysInfo::GetKernelVersionFull(void) +{ + static std::string kernelVersionFull; + if (!kernelVersionFull.empty()) + return kernelVersionFull; + +#if defined(TARGET_WINDOWS_DESKTOP) + OSVERSIONINFOEXW osvi; + if (sysGetVersionExWByRef(osvi)) + kernelVersionFull = StringUtils::Format("%d.%d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber); +#elif defined(TARGET_WINDOWS_STORE) + // get the system version number + auto sv = AnalyticsInfo::VersionInfo().DeviceFamilyVersion(); + wchar_t* end; + unsigned long long v = wcstoull(sv.c_str(), &end, 10); + unsigned long long v1 = (v & 0xFFFF000000000000L) >> 48; + unsigned long long v2 = (v & 0x0000FFFF00000000L) >> 32; + unsigned long long v3 = (v & 0x00000000FFFF0000L) >> 16; + kernelVersionFull = StringUtils::Format("%lld.%lld.%lld", v1, v2, v3); + +#elif defined(TARGET_POSIX) + struct utsname un; + if (uname(&un) == 0) + kernelVersionFull.assign(un.release); +#endif // defined(TARGET_POSIX) + + if (kernelVersionFull.empty()) + kernelVersionFull = "0.0.0"; // can't detect + + return kernelVersionFull; +} + +std::string CSysInfo::GetKernelVersion(void) +{ + static std::string kernelVersionClear; + if (kernelVersionClear.empty()) + { + kernelVersionClear = GetKernelVersionFull(); + const size_t erasePos = kernelVersionClear.find_first_not_of("0123456789."); + if (erasePos != std::string::npos) + kernelVersionClear.erase(erasePos); + } + + return kernelVersionClear; +} + +std::string CSysInfo::GetOsName(bool emptyIfUnknown /* = false*/) +{ + static std::string osName; + if (osName.empty()) + { +#if defined (TARGET_WINDOWS) + osName = GetKernelName() + "-based OS"; +#elif defined(TARGET_FREEBSD) + osName = GetKernelName(true); // FIXME: for FreeBSD OS name is a kernel name +#elif defined(TARGET_DARWIN_IOS) + osName = "iOS"; +#elif defined(TARGET_DARWIN_TVOS) + osName = "tvOS"; +#elif defined(TARGET_DARWIN_OSX) + osName = "OS X"; +#elif defined (TARGET_ANDROID) + osName = "Android"; +#elif defined(TARGET_LINUX) + osName = getValueFromOs_release("NAME"); + if (osName.empty()) + osName = getValueFromLsb_release(lsb_rel_distributor); + if (osName.empty()) + osName = getValueFromOs_release("ID"); +#endif // defined(TARGET_LINUX) + + if (osName.empty()) + osName = "Unknown OS"; + } + + if (emptyIfUnknown && osName == "Unknown OS") + return ""; + + return osName; +} + +std::string CSysInfo::GetOsVersion(void) +{ + static std::string osVersion; + if (!osVersion.empty()) + return osVersion; + +#if defined(TARGET_WINDOWS) || defined(TARGET_FREEBSD) + osVersion = GetKernelVersion(); // FIXME: for Win32 and FreeBSD OS version is a kernel version +#elif defined(TARGET_DARWIN) + osVersion = CDarwinUtils::GetVersionString(); +#elif defined(TARGET_ANDROID) + char versionCStr[PROP_VALUE_MAX]; + int propLen = __system_property_get("ro.build.version.release", versionCStr); + osVersion.assign(versionCStr, (propLen > 0 && propLen <= PROP_VALUE_MAX) ? propLen : 0); + + if (osVersion.empty() || std::string("0123456789").find(versionCStr[0]) == std::string::npos) + osVersion.clear(); // can't correctly detect Android version + else + { + size_t pointPos = osVersion.find('.'); + if (pointPos == std::string::npos) + osVersion += ".0.0"; + else if (osVersion.find('.', pointPos + 1) == std::string::npos) + osVersion += ".0"; + } +#elif defined(TARGET_LINUX) + osVersion = getValueFromOs_release("VERSION_ID"); + if (osVersion.empty()) + osVersion = getValueFromLsb_release(lsb_rel_release); +#endif // defined(TARGET_LINUX) + + if (osVersion.empty()) + osVersion = "0.0"; + + return osVersion; +} + +std::string CSysInfo::GetOsPrettyNameWithVersion(void) +{ + static std::string osNameVer; + if (!osNameVer.empty()) + return osNameVer; + +#if defined (TARGET_WINDOWS_DESKTOP) + OSVERSIONINFOEXW osvi = {}; + + osNameVer = "Windows "; + if (sysGetVersionExWByRef(osvi)) + { + switch (GetWindowsVersion()) + { + case WindowsVersionWin7: + if (osvi.wProductType == VER_NT_WORKSTATION) + osNameVer.append("7"); + else + osNameVer.append("Server 2008 R2"); + break; + case WindowsVersionWin8: + if (osvi.wProductType == VER_NT_WORKSTATION) + osNameVer.append("8"); + else + osNameVer.append("Server 2012"); + break; + case WindowsVersionWin8_1: + if (osvi.wProductType == VER_NT_WORKSTATION) + osNameVer.append("8.1"); + else + osNameVer.append("Server 2012 R2"); + break; + case WindowsVersionWin10: + case WindowsVersionWin10_FCU: + if (osvi.wProductType == VER_NT_WORKSTATION) + osNameVer.append("10"); + else + osNameVer.append("Unknown future server version"); + break; + case WindowsVersionFuture: + osNameVer.append("Unknown future version"); + break; + default: + osNameVer.append("Unknown version"); + break; + } + + // Append Service Pack version if any + if (osvi.wServicePackMajor > 0 || osvi.wServicePackMinor > 0) + { + osNameVer.append(StringUtils::Format(" SP%d", osvi.wServicePackMajor)); + if (osvi.wServicePackMinor > 0) + { + osNameVer.append(StringUtils::Format(".%d", osvi.wServicePackMinor)); + } + } + } + else + osNameVer.append(" unknown"); +#elif defined(TARGET_WINDOWS_STORE) + osNameVer = GetKernelName() + " " + GetOsVersion(); +#elif defined(TARGET_FREEBSD) || defined(TARGET_DARWIN) + osNameVer = GetOsName() + " " + GetOsVersion(); +#elif defined(TARGET_ANDROID) + osNameVer = GetOsName() + " " + GetOsVersion() + " API level " + StringUtils::Format("%d", CJNIBuild::SDK_INT); +#elif defined(TARGET_LINUX) + osNameVer = getValueFromOs_release("PRETTY_NAME"); + if (osNameVer.empty()) + { + osNameVer = getValueFromLsb_release(lsb_rel_description); + std::string osName(GetOsName(true)); + if (!osName.empty() && osNameVer.find(osName) == std::string::npos) + osNameVer = osName + osNameVer; + if (osNameVer.empty()) + osNameVer = "Unknown Linux Distribution"; + } + + if (osNameVer.find(GetOsVersion()) == std::string::npos) + osNameVer += " " + GetOsVersion(); +#endif // defined(TARGET_LINUX) + + if (osNameVer.empty()) + osNameVer = "Unknown OS Unknown version"; + + return osNameVer; + +} + +std::string CSysInfo::GetManufacturerName(void) +{ + static std::string manufName; + static bool inited = false; + if (!inited) + { +#if defined(TARGET_ANDROID) + char deviceCStr[PROP_VALUE_MAX]; + int propLen = __system_property_get("ro.product.manufacturer", deviceCStr); + manufName.assign(deviceCStr, (propLen > 0 && propLen <= PROP_VALUE_MAX) ? propLen : 0); +#elif defined(TARGET_DARWIN) + manufName = CDarwinUtils::GetManufacturer(); +#elif defined(TARGET_WINDOWS_STORE) + auto eas = EasClientDeviceInformation(); + auto manufacturer = eas.SystemManufacturer(); + g_charsetConverter.wToUTF8(std::wstring(manufacturer.c_str()), manufName); +#elif defined(TARGET_LINUX) + + auto cpuInfo = CServiceBroker::GetCPUInfo(); + manufName = cpuInfo->GetCPUSoC(); + +#elif defined(TARGET_WINDOWS) + // We just don't care, might be useful on embedded +#endif + inited = true; + } + + return manufName; +} + +std::string CSysInfo::GetModelName(void) +{ + static std::string modelName; + static bool inited = false; + if (!inited) + { +#if defined(TARGET_ANDROID) + char deviceCStr[PROP_VALUE_MAX]; + int propLen = __system_property_get("ro.product.model", deviceCStr); + modelName.assign(deviceCStr, (propLen > 0 && propLen <= PROP_VALUE_MAX) ? propLen : 0); +#elif defined(TARGET_DARWIN_EMBEDDED) + modelName = CDarwinUtils::getIosPlatformString(); +#elif defined(TARGET_DARWIN_OSX) + size_t nameLen = 0; // 'nameLen' should include terminating null + if (sysctlbyname("hw.model", NULL, &nameLen, NULL, 0) == 0 && nameLen > 1) + { + XUTILS::auto_buffer buf(nameLen); + if (sysctlbyname("hw.model", buf.get(), &nameLen, NULL, 0) == 0 && nameLen == buf.size()) + modelName.assign(buf.get(), nameLen - 1); // assign exactly 'nameLen-1' characters to 'modelName' + } +#elif defined(TARGET_WINDOWS_STORE) + auto eas = EasClientDeviceInformation(); + auto manufacturer = eas.SystemProductName(); + g_charsetConverter.wToUTF8(std::wstring(manufacturer.c_str()), modelName); +#elif defined(TARGET_LINUX) + auto cpuInfo = CServiceBroker::GetCPUInfo(); + modelName = cpuInfo->GetCPUHardware(); +#elif defined(TARGET_WINDOWS) + // We just don't care, might be useful on embedded +#endif + inited = true; + } + + return modelName; +} + +bool CSysInfo::IsAeroDisabled() +{ +#ifdef TARGET_WINDOWS_STORE + return true; // need to review https://msdn.microsoft.com/en-us/library/windows/desktop/aa969518(v=vs.85).aspx +#elif defined(TARGET_WINDOWS) + BOOL aeroEnabled = FALSE; + HRESULT res = DwmIsCompositionEnabled(&aeroEnabled); + if (SUCCEEDED(res)) + return !aeroEnabled; +#endif + return false; +} + +CSysInfo::WindowsVersion CSysInfo::m_WinVer = WindowsVersionUnknown; + +bool CSysInfo::IsWindowsVersion(WindowsVersion ver) +{ + if (ver == WindowsVersionUnknown) + return false; + return GetWindowsVersion() == ver; +} + +bool CSysInfo::IsWindowsVersionAtLeast(WindowsVersion ver) +{ + if (ver == WindowsVersionUnknown) + return false; + return GetWindowsVersion() >= ver; +} + +CSysInfo::WindowsVersion CSysInfo::GetWindowsVersion() +{ +#ifdef TARGET_WINDOWS_DESKTOP + if (m_WinVer == WindowsVersionUnknown) + { + OSVERSIONINFOEXW osvi = {}; + if (sysGetVersionExWByRef(osvi)) + { + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) + m_WinVer = WindowsVersionWin7; + else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2) + m_WinVer = WindowsVersionWin8; + else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3) + m_WinVer = WindowsVersionWin8_1; + else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber < 16299) + m_WinVer = WindowsVersionWin10; + else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= 16299) + m_WinVer = WindowsVersionWin10_FCU; + /* Insert checks for new Windows versions here */ + else if ( (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion > 3) || osvi.dwMajorVersion > 10) + m_WinVer = WindowsVersionFuture; + } + } +#elif defined(TARGET_WINDOWS_STORE) + m_WinVer = WindowsVersionWin10; +#endif // TARGET_WINDOWS + return m_WinVer; +} + +int CSysInfo::GetKernelBitness(void) +{ + static int kernelBitness = -1; + if (kernelBitness == -1) + { +#ifdef TARGET_WINDOWS_STORE + Package package = Package::Current(); + auto arch = package.Id().Architecture(); + switch (arch) + { + case ProcessorArchitecture::X86: + kernelBitness = 32; + break; + case ProcessorArchitecture::X64: + kernelBitness = 64; + break; + case ProcessorArchitecture::Arm: + kernelBitness = 32; + break; + case ProcessorArchitecture::Unknown: // not sure what to do here. guess 32 for now + case ProcessorArchitecture::Neutral: + kernelBitness = 32; + break; + } +#elif defined(TARGET_WINDOWS_DESKTOP) + SYSTEM_INFO si; + GetNativeSystemInfo(&si); + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL || si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM) + kernelBitness = 32; + else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + kernelBitness = 64; + else + { + BOOL isWow64 = FALSE; + if (IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64) // fallback + kernelBitness = 64; + } +#elif defined(TARGET_DARWIN_EMBEDDED) + // Note: OS X return x86 CPU type without CPU_ARCH_ABI64 flag + const NXArchInfo* archInfo = NXGetLocalArchInfo(); + if (archInfo) + kernelBitness = ((archInfo->cputype & CPU_ARCH_ABI64) != 0) ? 64 : 32; +#elif defined(TARGET_POSIX) + struct utsname un; + if (uname(&un) == 0) + { + std::string machine(un.machine); + if (machine == "x86_64" || machine == "amd64" || machine == "arm64" || machine == "aarch64" || machine == "ppc64" || + machine == "ia64" || machine == "mips64" || machine == "s390x") + kernelBitness = 64; + else + kernelBitness = 32; + } +#endif + if (kernelBitness == -1) + kernelBitness = 0; // can't detect + } + + return kernelBitness; +} + +const std::string& CSysInfo::GetKernelCpuFamily(void) +{ + static std::string kernelCpuFamily; + if (kernelCpuFamily.empty()) + { +#ifdef TARGET_WINDOWS + SYSTEM_INFO si; + GetNativeSystemInfo(&si); + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL || + si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + kernelCpuFamily = "x86"; + else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM) + kernelCpuFamily = "ARM"; +#elif defined(TARGET_DARWIN) + const NXArchInfo* archInfo = NXGetLocalArchInfo(); + if (archInfo) + { + const cpu_type_t cpuType = (archInfo->cputype & ~CPU_ARCH_ABI64); // get CPU family without 64-bit ABI flag + if (cpuType == CPU_TYPE_I386) + kernelCpuFamily = "x86"; + else if (cpuType == CPU_TYPE_ARM) + kernelCpuFamily = "ARM"; +#ifdef CPU_TYPE_MIPS + else if (cpuType == CPU_TYPE_MIPS) + kernelCpuFamily = "MIPS"; +#endif // CPU_TYPE_MIPS + } +#elif defined(TARGET_POSIX) + struct utsname un; + if (uname(&un) == 0) + { + std::string machine(un.machine); + if (machine.compare(0, 3, "arm", 3) == 0 || machine.compare(0, 7, "aarch64", 7) == 0) + kernelCpuFamily = "ARM"; + else if (machine.compare(0, 4, "mips", 4) == 0) + kernelCpuFamily = "MIPS"; + else if (machine.compare(0, 4, "i686", 4) == 0 || machine == "i386" || machine == "amd64" || machine.compare(0, 3, "x86", 3) == 0) + kernelCpuFamily = "x86"; + else if (machine.compare(0, 4, "s390", 4) == 0) + kernelCpuFamily = "s390"; + else if (machine.compare(0, 3, "ppc", 3) == 0 || machine.compare(0, 5, "power", 5) == 0) + kernelCpuFamily = "PowerPC"; + } +#endif + if (kernelCpuFamily.empty()) + kernelCpuFamily = "unknown CPU family"; + } + return kernelCpuFamily; +} + +int CSysInfo::GetXbmcBitness(void) +{ + return static_cast(sizeof(void*) * 8); +} + +bool CSysInfo::HasInternet() +{ + if (m_info.internetState != CSysData::UNKNOWN) + return m_info.internetState == CSysData::CONNECTED; + return (m_info.internetState = CSysInfoJob::GetInternetState()) == CSysData::CONNECTED; +} + +std::string CSysInfo::GetHddSpaceInfo(int drive, bool shortText) +{ + int percent; + return GetHddSpaceInfo( percent, drive, shortText); +} + +std::string CSysInfo::GetHddSpaceInfo(int& percent, int drive, bool shortText) +{ + int total, totalFree, totalUsed, percentFree, percentused; + std::string strRet; + percent = 0; + if (g_sysinfo.GetDiskSpace("", total, totalFree, totalUsed, percentFree, percentused)) + { + if (shortText) + { + switch(drive) + { + case SYSTEM_FREE_SPACE: + percent = percentFree; + break; + case SYSTEM_USED_SPACE: + percent = percentused; + break; + } + } + else + { + switch(drive) + { + case SYSTEM_FREE_SPACE: + strRet = StringUtils::Format("%i MB %s", totalFree, g_localizeStrings.Get(160).c_str()); + break; + case SYSTEM_USED_SPACE: + strRet = StringUtils::Format("%i MB %s", totalUsed, g_localizeStrings.Get(20162).c_str()); + break; + case SYSTEM_TOTAL_SPACE: + strRet = StringUtils::Format("%i MB %s", total, g_localizeStrings.Get(20161).c_str()); + break; + case SYSTEM_FREE_SPACE_PERCENT: + strRet = StringUtils::Format("%i %% %s", percentFree, g_localizeStrings.Get(160).c_str()); + break; + case SYSTEM_USED_SPACE_PERCENT: + strRet = StringUtils::Format("%i %% %s", percentused, g_localizeStrings.Get(20162).c_str()); + break; + } + } + } + else + { + if (shortText) + strRet = g_localizeStrings.Get(10006); // N/A + else + strRet = g_localizeStrings.Get(10005); // Not available + } + return strRet; +} + +std::string CSysInfo::GetUserAgent() +{ + static std::string result; + if (!result.empty()) + return result; + + result = GetAppName() + "/" + CSysInfo::GetVersionShort() + " ("; +#if defined(TARGET_WINDOWS) + result += GetKernelName() + " " + GetKernelVersion(); +#ifndef TARGET_WINDOWS_STORE + BOOL bIsWow = FALSE; + if (IsWow64Process(GetCurrentProcess(), &bIsWow) && bIsWow) + result.append("; WOW64"); + else +#endif + { + SYSTEM_INFO si = {}; + GetSystemInfo(&si); + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + result.append("; Win64; x64"); + else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) + result.append("; Win64; IA64"); + else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM) + result.append("; ARM"); + } +#elif defined(TARGET_DARWIN) +#if defined(TARGET_DARWIN_EMBEDDED) + std::string iDevStr(GetModelName()); // device model name with number of model version + size_t iDevStrDigit = iDevStr.find_first_of("0123456789"); + std::string iDev(iDevStr, 0, iDevStrDigit); // device model name without number + if (iDevStrDigit == 0) + iDev = "unknown"; + result += iDev + "; "; + std::string iOSVersion(GetOsVersion()); + size_t lastDotPos = iOSVersion.rfind('.'); + if (lastDotPos != std::string::npos && iOSVersion.find('.') != lastDotPos + && iOSVersion.find_first_not_of('0', lastDotPos + 1) == std::string::npos) + iOSVersion.erase(lastDotPos); + StringUtils::Replace(iOSVersion, '.', '_'); + if (iDev == "AppleTV") + { + // check if it's ATV4 (AppleTV5,3) or later + auto modelMajorNumberEndPos = iDevStr.find_first_of(',', iDevStrDigit); + std::string s{iDevStr, iDevStrDigit, modelMajorNumberEndPos - iDevStrDigit}; + if (stoi(s) >= 5) + result += "CPU TVOS"; + else + result += "CPU OS"; + } + else if (iDev == "iPad") + result += "CPU OS"; + else + result += "CPU iPhone OS "; + result += iOSVersion + " like Mac OS X"; +#else + result += "Macintosh; "; + std::string cpuFam(GetBuildTargetCpuFamily()); + if (cpuFam == "x86") + result += "Intel "; + result += "Mac OS X "; + std::string OSXVersion(GetOsVersion()); + StringUtils::Replace(OSXVersion, '.', '_'); + result += OSXVersion; +#endif +#elif defined(TARGET_ANDROID) + result += "Linux; Android "; + std::string versionStr(GetOsVersion()); + const size_t verLen = versionStr.length(); + if (verLen >= 2 && versionStr.compare(verLen - 2, 2, ".0", 2) == 0) + versionStr.erase(verLen - 2); // remove last ".0" if any + result += versionStr; + std::string deviceInfo(GetModelName()); + + char buildId[PROP_VALUE_MAX]; + int propLen = __system_property_get("ro.build.id", buildId); + if (propLen > 0 && propLen <= PROP_VALUE_MAX) + { + if (!deviceInfo.empty()) + deviceInfo += " "; + deviceInfo += "Build/"; + deviceInfo.append(buildId, propLen); + } + + if (!deviceInfo.empty()) + result += "; " + deviceInfo; +#elif defined(TARGET_POSIX) + result += "X11; "; + struct utsname un; + if (uname(&un) == 0) + { + std::string cpuStr(un.machine); + if (cpuStr == "x86_64" && GetXbmcBitness() == 32) + cpuStr = "i686 (x86_64)"; + result += un.sysname; + result += " "; + result += cpuStr; + } + else + result += "Unknown"; +#else + result += "Unknown"; +#endif + result += ")"; + + if (GetAppName() != "Kodi") + result += " Kodi_Fork_" + GetAppName() + "/1.0"; // default fork number is '1.0', replace it with actual number if necessary + +#ifdef TARGET_LINUX + // Add distribution name + std::string linuxOSName(GetOsName(true)); + if (!linuxOSName.empty()) + result += " " + linuxOSName + "/" + GetOsVersion(); +#endif + +#ifdef TARGET_RASPBERRY_PI + result += " HW_RaspberryPi/1.0"; +#elif defined (TARGET_DARWIN_EMBEDDED) + std::string iDevVer; + if (iDevStrDigit == std::string::npos) + iDevVer = "0.0"; + else + iDevVer.assign(iDevStr, iDevStrDigit, std::string::npos); + StringUtils::Replace(iDevVer, ',', '.'); + result += " HW_" + iDev + "/" + iDevVer; +#endif + // add more device IDs here if needed. + // keep only one device ID in result! Form: + // result += " HW_" + "deviceID" + "/" + "1.0"; // '1.0' if device has no version + +#if defined(TARGET_ANDROID) + // Android has no CPU string by default, so add it as additional parameter + struct utsname un1; + if (uname(&un1) == 0) + { + std::string cpuStr(un1.machine); + StringUtils::Replace(cpuStr, ' ', '_'); + result += " Sys_CPU/" + cpuStr; + } +#endif + + result += " App_Bitness/" + StringUtils::Format("%d", GetXbmcBitness()); + + std::string fullVer(CSysInfo::GetVersion()); + StringUtils::Replace(fullVer, ' ', '-'); + result += " Version/" + fullVer; + + return result; +} + +std::string CSysInfo::GetDeviceName() +{ + std::string friendlyName = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_SERVICES_DEVICENAME); + if (StringUtils::EqualsNoCase(friendlyName, CCompileInfo::GetAppName())) + { + std::string hostname("[unknown]"); + CServiceBroker::GetNetwork().GetHostName(hostname); + return StringUtils::Format("%s (%s)", friendlyName.c_str(), hostname.c_str()); + } + + return friendlyName; +} + +// Version string MUST NOT contain spaces. It is used +// in the HTTP request user agent. +std::string CSysInfo::GetVersionShort() +{ + if (strlen(CCompileInfo::GetSuffix()) == 0) + return StringUtils::Format("%d.%d", CCompileInfo::GetMajor(), CCompileInfo::GetMinor()); + else + return StringUtils::Format("%d.%d-%s", CCompileInfo::GetMajor(), CCompileInfo::GetMinor(), CCompileInfo::GetSuffix()); +} + +std::string CSysInfo::GetVersion() +{ + return GetVersionShort() + " (" + CCompileInfo::GetVersionCode() + ")" + + " Git:" + CCompileInfo::GetSCMID(); +} + +std::string CSysInfo::GetVersionCode() +{ + return CCompileInfo::GetVersionCode(); +} + +std::string CSysInfo::GetVersionGit() +{ + return CCompileInfo::GetSCMID(); +} + +std::string CSysInfo::GetBuildDate() +{ + return CCompileInfo::GetBuildDate(); +} + +std::string CSysInfo::GetBuildTargetPlatformName(void) +{ +#if defined(TARGET_DARWIN_OSX) + return "OS X"; +#elif defined(TARGET_DARWIN_IOS) + return "iOS"; +#elif defined(TARGET_DARWIN_TVOS) + return "tvOS"; +#elif defined(TARGET_FREEBSD) + return "FreeBSD"; +#elif defined(TARGET_ANDROID) + return "Android"; +#elif defined(TARGET_LINUX) + return "Linux"; +#elif defined(TARGET_WINDOWS) +#ifdef NTDDI_VERSION + return "Windows NT"; +#else // !NTDDI_VERSION + return "unknown Win32 platform"; +#endif // !NTDDI_VERSION +#else + return "unknown platform"; +#endif +} + +std::string CSysInfo::GetBuildTargetPlatformVersion(void) +{ +#if defined(TARGET_DARWIN_OSX) + return XSTR_MACRO(__MAC_OS_X_VERSION_MIN_REQUIRED); +#elif defined(TARGET_DARWIN_IOS) + return XSTR_MACRO(__IPHONE_OS_VERSION_MIN_REQUIRED); +#elif defined(TARGET_DARWIN_TVOS) + return XSTR_MACRO(__TV_OS_VERSION_MIN_REQUIRED); +#elif defined(TARGET_FREEBSD) + return XSTR_MACRO(__FreeBSD_version); +#elif defined(TARGET_ANDROID) + return "API level " XSTR_MACRO(__ANDROID_API__); +#elif defined(TARGET_LINUX) + return XSTR_MACRO(LINUX_VERSION_CODE); +#elif defined(TARGET_WINDOWS) +#ifdef NTDDI_VERSION + return XSTR_MACRO(NTDDI_VERSION); +#else // !NTDDI_VERSION + return "(unknown Win32 platform)"; +#endif // !NTDDI_VERSION +#else + return "(unknown platform)"; +#endif +} + +std::string CSysInfo::GetBuildTargetPlatformVersionDecoded(void) +{ +#if defined(TARGET_DARWIN_OSX) + if (__MAC_OS_X_VERSION_MIN_REQUIRED % 100) + return StringUtils::Format("version %d.%d.%d", __MAC_OS_X_VERSION_MIN_REQUIRED / 10000, + (__MAC_OS_X_VERSION_MIN_REQUIRED / 100) % 100, + __MAC_OS_X_VERSION_MIN_REQUIRED % 100); + else + return StringUtils::Format("version %d.%d", __MAC_OS_X_VERSION_MIN_REQUIRED / 10000, + (__MAC_OS_X_VERSION_MIN_REQUIRED / 100) % 100); +#elif defined(TARGET_DARWIN_EMBEDDED) + std::string versionStr = GetBuildTargetPlatformVersion(); + static const int major = (std::stoi(versionStr) / 10000) % 100; + static const int minor = (std::stoi(versionStr) / 100) % 100; + static const int rev = std::stoi(versionStr) % 100; + return StringUtils::Format("version %d.%d.%d", major, minor, rev); +#elif defined(TARGET_FREEBSD) + // FIXME: should works well starting from FreeBSD 8.1 + static const int major = (__FreeBSD_version / 100000) % 100; + static const int minor = (__FreeBSD_version / 1000) % 100; + static const int Rxx = __FreeBSD_version % 1000; + if ((major < 9 && Rxx == 0)) + return StringUtils::Format("version %d.%d-RELEASE", major, minor); + if (Rxx >= 500) + return StringUtils::Format("version %d.%d-STABLE", major, minor); + + return StringUtils::Format("version %d.%d-CURRENT", major, minor); +#elif defined(TARGET_ANDROID) + return "API level " XSTR_MACRO(__ANDROID_API__); +#elif defined(TARGET_LINUX) + return StringUtils::Format("version %d.%d.%d", (LINUX_VERSION_CODE >> 16) & 0xFF , (LINUX_VERSION_CODE >> 8) & 0xFF, LINUX_VERSION_CODE & 0xFF); +#elif defined(TARGET_WINDOWS) +#ifdef NTDDI_VERSION + std::string version(StringUtils::Format("version %d.%d", int(NTDDI_VERSION >> 24) & 0xFF, int(NTDDI_VERSION >> 16) & 0xFF)); + if (SPVER(NTDDI_VERSION)) + version += StringUtils::Format(" SP%d", int(SPVER(NTDDI_VERSION))); + return version; +#else // !NTDDI_VERSION + return "(unknown Win32 platform)"; +#endif // !NTDDI_VERSION +#else + return "(unknown platform)"; +#endif +} + +std::string CSysInfo::GetBuildTargetCpuFamily(void) +{ +#if defined(__thumb__) || defined(_M_ARMT) + return "ARM (Thumb)"; +#elif defined(__arm__) || defined(_M_ARM) || defined (__aarch64__) + return "ARM"; +#elif defined(__mips__) || defined(mips) || defined(__mips) + return "MIPS"; +#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) || \ + defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(_X86_) + return "x86"; +#elif defined(__s390x__) + return "s390"; +#elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) + return "PowerPC"; +#else + return "unknown CPU family"; +#endif +} + +std::string CSysInfo::GetUsedCompilerNameAndVer(void) +{ +#if defined(__clang__) +#ifdef __clang_version__ + return "Clang " __clang_version__; +#else // ! __clang_version__ + return "Clang " XSTR_MACRO(__clang_major__) "." XSTR_MACRO(__clang_minor__) "." XSTR_MACRO(__clang_patchlevel__); +#endif //! __clang_version__ +#elif defined (__INTEL_COMPILER) + return "Intel Compiler " XSTR_MACRO(__INTEL_COMPILER); +#elif defined (__GNUC__) + std::string compilerStr; +#ifdef __llvm__ + /* Note: this will not detect GCC + DragonEgg */ + compilerStr = "llvm-gcc "; +#else // __llvm__ + compilerStr = "GCC "; +#endif // !__llvm__ + compilerStr += XSTR_MACRO(__GNUC__) "." XSTR_MACRO(__GNUC_MINOR__) "." XSTR_MACRO(__GNUC_PATCHLEVEL__); + return compilerStr; +#elif defined (_MSC_VER) + return "MSVC " XSTR_MACRO(_MSC_FULL_VER); +#else + return "unknown compiler"; +#endif +} + +std::string CSysInfo::GetPrivacyPolicy() +{ + if (m_privacyPolicy.empty()) + { + CFile file; + XFILE::auto_buffer buf; + if (file.LoadFile("special://xbmc/privacy-policy.txt", buf) > 0) + { + std::string strBuf(buf.get(), buf.length()); + m_privacyPolicy = strBuf; + } + else + m_privacyPolicy = g_localizeStrings.Get(19055); + } + return m_privacyPolicy; +} + +CSysInfo::WindowsDeviceFamily CSysInfo::GetWindowsDeviceFamily() +{ +#ifdef TARGET_WINDOWS_STORE + auto familyName = AnalyticsInfo::VersionInfo().DeviceFamily(); + if (familyName == L"Windows.Desktop") + return WindowsDeviceFamily::Desktop; + else if (familyName == L"Windows.Mobile") + return WindowsDeviceFamily::Mobile; + else if (familyName == L"Windows.Universal") + return WindowsDeviceFamily::IoT; + else if (familyName == L"Windows.Team") + return WindowsDeviceFamily::Surface; + else if (familyName == L"Windows.Xbox") + return WindowsDeviceFamily::Xbox; + else + return WindowsDeviceFamily::Other; +#endif // TARGET_WINDOWS_STORE + return WindowsDeviceFamily::Desktop; +} + +CJob *CSysInfo::GetJob() const +{ + return new CSysInfoJob(); +} + +void CSysInfo::OnJobComplete(unsigned int jobID, bool success, CJob *job) +{ + m_info = static_cast(job)->GetData(); + CInfoLoader::OnJobComplete(jobID, success, job); +} diff --git a/xbmc/utils/SystemInfo.h b/xbmc/utils/SystemInfo.h new file mode 100644 index 0000000..c853192 --- /dev/null +++ b/xbmc/utils/SystemInfo.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "InfoLoader.h" +#include "settings/ISubSettings.h" + +#include + +#define KB (1024) // 1 KiloByte (1KB) 1024 Byte (2^10 Byte) +#define MB (1024*KB) // 1 MegaByte (1MB) 1024 KB (2^10 KB) +#define GB (1024*MB) // 1 GigaByte (1GB) 1024 MB (2^10 MB) +#define TB (1024*GB) // 1 TerraByte (1TB) 1024 GB (2^10 GB) + +#define MAX_KNOWN_ATTRIBUTES 46 + + +class CSysData +{ +public: + enum INTERNET_STATE { UNKNOWN, CONNECTED, DISCONNECTED }; + CSysData() + { + Reset(); + }; + + void Reset() + { + internetState = UNKNOWN; + }; + + std::string systemUptime; + std::string systemTotalUptime; + INTERNET_STATE internetState; + std::string videoEncoder; + std::string cpuFrequency; + std::string osVersionInfo; + std::string macAddress; + std::string batteryLevel; +}; + +class CSysInfoJob : public CJob +{ +public: + CSysInfoJob(); + + bool DoWork() override; + const CSysData &GetData() const; + + static CSysData::INTERNET_STATE GetInternetState(); +private: + static bool SystemUpTime(int iInputMinutes, int &iMinutes, int &iHours, int &iDays); + static std::string GetSystemUpTime(bool bTotalUptime); + static std::string GetMACAddress(); + static std::string GetVideoEncoder(); + static std::string GetBatteryLevel(); + + CSysData m_info; +}; + +class CSysInfo : public CInfoLoader, public ISubSettings +{ +public: + enum WindowsVersion + { + WindowsVersionUnknown = -1, // Undetected, unsupported Windows version or OS in not Windows + WindowsVersionWin7, // Windows 7, Windows Server 2008 R2 + WindowsVersionWin8, // Windows 8, Windows Server 2012 + WindowsVersionWin8_1, // Windows 8.1 + WindowsVersionWin10, // Windows 10 + WindowsVersionWin10_FCU, // Windows 10 Fall Creators Update + /* Insert new Windows versions here, when they'll be known */ + WindowsVersionFuture = 100 // Future Windows version, not known to code + }; + enum WindowsDeviceFamily + { + Mobile = 1, + Desktop = 2, + IoT = 3, + Xbox = 4, + Surface = 5, + Other = 100 + }; + + CSysInfo(void); + ~CSysInfo() override; + + bool Load(const TiXmlNode *settings) override; + bool Save(TiXmlNode *settings) const override; + + char MD5_Sign[32 + 1]; + + static const std::string& GetAppName(void); // the same name as CCompileInfo::GetAppName(), but const ref to std::string + + static std::string GetKernelName(bool emptyIfUnknown = false); + static std::string GetKernelVersionFull(void); // full version string, including "-generic", "-RELEASE" etc. + static std::string GetKernelVersion(void); // only digits with dots + static std::string GetOsName(bool emptyIfUnknown = false); + static std::string GetOsVersion(void); + static std::string GetOsPrettyNameWithVersion(void); + static std::string GetUserAgent(); + static std::string GetDeviceName(); + static std::string GetVersion(); + static std::string GetVersionShort(); + static std::string GetVersionCode(); + static std::string GetVersionGit(); + static std::string GetBuildDate(); + + bool HasInternet(); + bool IsAeroDisabled(); + static bool IsWindowsVersion(WindowsVersion ver); + static bool IsWindowsVersionAtLeast(WindowsVersion ver); + static WindowsVersion GetWindowsVersion(); + static int GetKernelBitness(void); + static int GetXbmcBitness(void); + static const std::string& GetKernelCpuFamily(void); + static std::string GetManufacturerName(void); + static std::string GetModelName(void); + bool GetDiskSpace(std::string drive,int& iTotal, int& iTotalFree, int& iTotalUsed, int& iPercentFree, int& iPercentUsed); + std::string GetHddSpaceInfo(int& percent, int drive, bool shortText=false); + std::string GetHddSpaceInfo(int drive, bool shortText=false); + + int GetTotalUptime() const { return m_iSystemTimeTotalUp; } + void SetTotalUptime(int uptime) { m_iSystemTimeTotalUp = uptime; } + + static std::string GetBuildTargetPlatformName(void); + static std::string GetBuildTargetPlatformVersion(void); + static std::string GetBuildTargetPlatformVersionDecoded(void); + static std::string GetBuildTargetCpuFamily(void); + + static std::string GetUsedCompilerNameAndVer(void); + std::string GetPrivacyPolicy(); + + static WindowsDeviceFamily GetWindowsDeviceFamily(); + +protected: + CJob *GetJob() const override; + std::string TranslateInfo(int info) const override; + void OnJobComplete(unsigned int jobID, bool success, CJob *job) override; + +private: + CSysData m_info; + std::string m_privacyPolicy; + static WindowsVersion m_WinVer; + int m_iSystemTimeTotalUp; // Uptime in minutes! + void Reset(); +}; + +extern CSysInfo g_sysinfo; + diff --git a/xbmc/utils/Temperature.cpp b/xbmc/utils/Temperature.cpp new file mode 100644 index 0000000..cc6d510 --- /dev/null +++ b/xbmc/utils/Temperature.cpp @@ -0,0 +1,481 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Temperature.h" + +#include "utils/Archive.h" +#include "utils/StringUtils.h" + +#include + +CTemperature::CTemperature() +{ + m_value=0.0f; + m_valid=false; +} + +CTemperature::CTemperature(const CTemperature& temperature) +{ + m_value=temperature.m_value; + m_valid=temperature.m_valid; +} + +CTemperature::CTemperature(double value) +{ + m_value=value; + m_valid=true; +} + +bool CTemperature::operator >(const CTemperature& right) const +{ + assert(IsValid()); + assert(right.IsValid()); + + if (!IsValid() || !right.IsValid()) + return false; + + if (this==&right) + return false; + + return (m_value>right.m_value); +} + +bool CTemperature::operator >=(const CTemperature& right) const +{ + return operator >(right) || operator ==(right); +} + +bool CTemperature::operator <(const CTemperature& right) const +{ + assert(IsValid()); + assert(right.IsValid()); + + if (!IsValid() || !right.IsValid()) + return false; + + if (this==&right) + return false; + + return (m_value(double right) const +{ + assert(IsValid()); + + if (!IsValid()) + return false; + + return (m_value>right); +} + +bool CTemperature::operator >=(double right) const +{ + return operator >(right) || operator ==(right); +} + +bool CTemperature::operator <(double right) const +{ + assert(IsValid()); + + if (!IsValid()) + return false; + + return (m_value>m_value; + ar>>m_valid; + } +} + +bool CTemperature::IsValid() const +{ + return m_valid; +} + +double CTemperature::ToFahrenheit() const +{ + return m_value; +} + +double CTemperature::ToKelvin() const +{ + return (m_value+459.67F)/1.8f; +} + +double CTemperature::ToCelsius() const +{ + return (m_value-32.0f)/1.8f; +} + +double CTemperature::ToReaumur() const +{ + return (m_value-32.0f)/2.25f; +} + +double CTemperature::ToRankine() const +{ + return m_value+459.67f; +} + +double CTemperature::ToRomer() const +{ + return (m_value-32.0f)*7.0f/24.0f+7.5f; +} + +double CTemperature::ToDelisle() const +{ + return (212.f-m_value)*5.0f/6.0f; +} + +double CTemperature::ToNewton() const +{ + return (m_value-32.0f)*11.0f/60.0f; +} + +double CTemperature::To(Unit temperatureUnit) const +{ + if (!IsValid()) + return 0; + + double value = 0.0; + + switch (temperatureUnit) + { + case UnitFahrenheit: + value=ToFahrenheit(); + break; + case UnitKelvin: + value=ToKelvin(); + break; + case UnitCelsius: + value=ToCelsius(); + break; + case UnitReaumur: + value=ToReaumur(); + break; + case UnitRankine: + value=ToRankine(); + break; + case UnitRomer: + value=ToRomer(); + break; + case UnitDelisle: + value=ToDelisle(); + break; + case UnitNewton: + value=ToNewton(); + break; + default: + assert(false); + break; + } + return value; +} + +// Returns temperature as localized string +std::string CTemperature::ToString(Unit temperatureUnit) const +{ + if (!IsValid()) + return ""; + + return StringUtils::Format("%2.0f", To(temperatureUnit)); +} diff --git a/xbmc/utils/Temperature.h b/xbmc/utils/Temperature.h new file mode 100644 index 0000000..9d2a019 --- /dev/null +++ b/xbmc/utils/Temperature.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/IArchivable.h" + +#include + +class CTemperature : public IArchivable +{ +public: + CTemperature(); + CTemperature(const CTemperature& temperature); + + typedef enum Unit + { + UnitFahrenheit = 0, + UnitKelvin, + UnitCelsius, + UnitReaumur, + UnitRankine, + UnitRomer, + UnitDelisle, + UnitNewton + } Unit; + + static CTemperature CreateFromFahrenheit(double value); + static CTemperature CreateFromKelvin(double value); + static CTemperature CreateFromCelsius(double value); + static CTemperature CreateFromReaumur(double value); + static CTemperature CreateFromRankine(double value); + static CTemperature CreateFromRomer(double value); + static CTemperature CreateFromDelisle(double value); + static CTemperature CreateFromNewton(double value); + + bool operator >(const CTemperature& right) const; + bool operator >=(const CTemperature& right) const; + bool operator <(const CTemperature& right) const; + bool operator <=(const CTemperature& right) const; + bool operator ==(const CTemperature& right) const; + bool operator !=(const CTemperature& right) const; + + CTemperature& operator =(const CTemperature& right); + const CTemperature& operator +=(const CTemperature& right); + const CTemperature& operator -=(const CTemperature& right); + const CTemperature& operator *=(const CTemperature& right); + const CTemperature& operator /=(const CTemperature& right); + CTemperature operator +(const CTemperature& right) const; + CTemperature operator -(const CTemperature& right) const; + CTemperature operator *(const CTemperature& right) const; + CTemperature operator /(const CTemperature& right) const; + + bool operator >(double right) const; + bool operator >=(double right) const; + bool operator <(double right) const; + bool operator <=(double right) const; + bool operator ==(double right) const; + bool operator !=(double right) const; + + const CTemperature& operator +=(double right); + const CTemperature& operator -=(double right); + const CTemperature& operator *=(double right); + const CTemperature& operator /=(double right); + CTemperature operator +(double right) const; + CTemperature operator -(double right) const; + CTemperature operator *(double right) const; + CTemperature operator /(double right) const; + + CTemperature& operator ++(); + CTemperature& operator --(); + CTemperature operator ++(int); + CTemperature operator --(int); + + void Archive(CArchive& ar) override; + + bool IsValid() const; + void SetValid(bool valid) { m_valid = valid; } + + double ToFahrenheit() const; + double ToKelvin() const; + double ToCelsius() const; + double ToReaumur() const; + double ToRankine() const; + double ToRomer() const; + double ToDelisle() const; + double ToNewton() const; + + double To(Unit temperatureUnit) const; + std::string ToString(Unit temperatureUnit) const; + +protected: + explicit CTemperature(double value); + + double m_value; // we store as fahrenheit + bool m_valid; +}; + diff --git a/xbmc/utils/TextSearch.cpp b/xbmc/utils/TextSearch.cpp new file mode 100644 index 0000000..1ada61d --- /dev/null +++ b/xbmc/utils/TextSearch.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "TextSearch.h" + +#include "StringUtils.h" + +CTextSearch::CTextSearch(const std::string &strSearchTerms, bool bCaseSensitive /* = false */, TextSearchDefault defaultSearchMode /* = SEARCH_DEFAULT_OR */) +{ + m_bCaseSensitive = bCaseSensitive; + ExtractSearchTerms(strSearchTerms, defaultSearchMode); +} + +bool CTextSearch::IsValid(void) const +{ + return m_AND.size() > 0 || m_OR.size() > 0 || m_NOT.size() > 0; +} + +bool CTextSearch::Search(const std::string &strHaystack) const +{ + if (strHaystack.empty() || !IsValid()) + return false; + + std::string strSearch(strHaystack); + if (!m_bCaseSensitive) + StringUtils::ToLower(strSearch); + + /* check whether any of the NOT terms matches and return false if there's a match */ + for (unsigned int iNotPtr = 0; iNotPtr < m_NOT.size(); iNotPtr++) + { + if (strSearch.find(m_NOT.at(iNotPtr)) != std::string::npos) + return false; + } + + /* check whether at least one of the OR terms matches and return false if there's no match found */ + bool bFound(m_OR.empty()); + for (unsigned int iOrPtr = 0; iOrPtr < m_OR.size(); iOrPtr++) + { + if (strSearch.find(m_OR.at(iOrPtr)) != std::string::npos) + { + bFound = true; + break; + } + } + if (!bFound) + return false; + + /* check whether all of the AND terms match and return false if one of them wasn't found */ + for (unsigned int iAndPtr = 0; iAndPtr < m_AND.size(); iAndPtr++) + { + if (strSearch.find(m_AND[iAndPtr]) == std::string::npos) + return false; + } + + /* all ok, return true */ + return true; +} + +void CTextSearch::GetAndCutNextTerm(std::string &strSearchTerm, std::string &strNextTerm) +{ + std::string strFindNext(" "); + + if (StringUtils::EndsWith(strSearchTerm, "\"")) + { + strSearchTerm.erase(0, 1); + strFindNext = "\""; + } + + size_t iNextPos = strSearchTerm.find(strFindNext); + if (iNextPos != std::string::npos) + { + strNextTerm = strSearchTerm.substr(0, iNextPos); + strSearchTerm.erase(0, iNextPos + 1); + } + else + { + strNextTerm = strSearchTerm; + strSearchTerm.clear(); + } +} + +void CTextSearch::ExtractSearchTerms(const std::string &strSearchTerm, TextSearchDefault defaultSearchMode) +{ + std::string strParsedSearchTerm(strSearchTerm); + StringUtils::Trim(strParsedSearchTerm); + + if (!m_bCaseSensitive) + StringUtils::ToLower(strParsedSearchTerm); + + bool bNextAND(defaultSearchMode == SEARCH_DEFAULT_AND); + bool bNextOR(defaultSearchMode == SEARCH_DEFAULT_OR); + bool bNextNOT(defaultSearchMode == SEARCH_DEFAULT_NOT); + + while (strParsedSearchTerm.length() > 0) + { + StringUtils::TrimLeft(strParsedSearchTerm); + + if (StringUtils::StartsWith(strParsedSearchTerm, "!") || StringUtils::StartsWithNoCase(strParsedSearchTerm, "not")) + { + std::string strDummy; + GetAndCutNextTerm(strParsedSearchTerm, strDummy); + bNextNOT = true; + } + else if (StringUtils::StartsWith(strParsedSearchTerm, "+") || StringUtils::StartsWithNoCase(strParsedSearchTerm, "and")) + { + std::string strDummy; + GetAndCutNextTerm(strParsedSearchTerm, strDummy); + bNextAND = true; + } + else if (StringUtils::StartsWith(strParsedSearchTerm, "|") || StringUtils::StartsWithNoCase(strParsedSearchTerm, "or")) + { + std::string strDummy; + GetAndCutNextTerm(strParsedSearchTerm, strDummy); + bNextOR = true; + } + else + { + std::string strTerm; + GetAndCutNextTerm(strParsedSearchTerm, strTerm); + if (strTerm.length() > 0) + { + if (bNextAND) + m_AND.push_back(strTerm); + else if (bNextOR) + m_OR.push_back(strTerm); + else if (bNextNOT) + m_NOT.push_back(strTerm); + } + else + { + break; + } + + bNextAND = (defaultSearchMode == SEARCH_DEFAULT_AND); + bNextOR = (defaultSearchMode == SEARCH_DEFAULT_OR); + bNextNOT = (defaultSearchMode == SEARCH_DEFAULT_NOT); + } + + StringUtils::TrimLeft(strParsedSearchTerm); + } +} diff --git a/xbmc/utils/TextSearch.h b/xbmc/utils/TextSearch.h new file mode 100644 index 0000000..f2d1fdb --- /dev/null +++ b/xbmc/utils/TextSearch.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include + +typedef enum TextSearchDefault +{ + SEARCH_DEFAULT_AND = 0, + SEARCH_DEFAULT_OR, + SEARCH_DEFAULT_NOT +} TextSearchDefault; + +class CTextSearch final +{ +public: + CTextSearch(const std::string &strSearchTerms, bool bCaseSensitive = false, TextSearchDefault defaultSearchMode = SEARCH_DEFAULT_OR); + + bool Search(const std::string &strHaystack) const; + bool IsValid(void) const; + +private: + static void GetAndCutNextTerm(std::string &strSearchTerm, std::string &strNextTerm); + void ExtractSearchTerms(const std::string &strSearchTerm, TextSearchDefault defaultSearchMode); + + bool m_bCaseSensitive; + std::vector m_AND; + std::vector m_OR; + std::vector m_NOT; +}; diff --git a/xbmc/utils/TimeUtils.cpp b/xbmc/utils/TimeUtils.cpp new file mode 100644 index 0000000..16d75b9 --- /dev/null +++ b/xbmc/utils/TimeUtils.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "TimeUtils.h" +#include "XBDateTime.h" +#include "threads/SystemClock.h" +#include "windowing/GraphicContext.h" + +#if defined(TARGET_DARWIN) +#include +#include +#elif defined(TARGET_WINDOWS) +#include +#else +#include +#endif + +int64_t CurrentHostCounter(void) +{ +#if defined(TARGET_DARWIN) + return( (int64_t)CVGetCurrentHostTime() ); +#elif defined(TARGET_WINDOWS) + LARGE_INTEGER PerformanceCount; + QueryPerformanceCounter(&PerformanceCount); + return( (int64_t)PerformanceCount.QuadPart ); +#else + struct timespec now; +#if defined(CLOCK_MONOTONIC_RAW) && !defined(TARGET_ANDROID) + clock_gettime(CLOCK_MONOTONIC_RAW, &now); +#else + clock_gettime(CLOCK_MONOTONIC, &now); +#endif // CLOCK_MONOTONIC_RAW && !TARGET_ANDROID + return( ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec ); +#endif +} + +int64_t CurrentHostFrequency(void) +{ +#if defined(TARGET_DARWIN) + return( (int64_t)CVGetHostClockFrequency() ); +#elif defined(TARGET_WINDOWS) + LARGE_INTEGER Frequency; + QueryPerformanceFrequency(&Frequency); + return( (int64_t)Frequency.QuadPart ); +#else + return( (int64_t)1000000000L ); +#endif +} + +unsigned int CTimeUtils::frameTime = 0; + +void CTimeUtils::UpdateFrameTime(bool flip) +{ + unsigned int currentTime = XbmcThreads::SystemClockMillis(); + unsigned int last = frameTime; + while (frameTime < currentTime) + { + frameTime += (unsigned int)(1000 / CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS()); + // observe wrap around + if (frameTime < last) + break; + } +} + +unsigned int CTimeUtils::GetFrameTime() +{ + return frameTime; +} + +CDateTime CTimeUtils::GetLocalTime(time_t time) +{ + CDateTime result; + + tm *local; +#ifdef HAVE_LOCALTIME_R + tm res = {}; + local = localtime_r(&time, &res); // Conversion to local time +#else + local = localtime(&time); // Conversion to local time +#endif + /* + * Microsoft implementation of localtime returns NULL if on or before epoch. + * http://msdn.microsoft.com/en-us/library/bf12f0hc(VS.80).aspx + */ + if (local) + result = *local; + else + result = time; // Use the original time as close enough. + + return result; +} + +std::string CTimeUtils::WithoutSeconds(const std::string hhmmss) +{ + return hhmmss.substr(0, 5); +} diff --git a/xbmc/utils/TimeUtils.h b/xbmc/utils/TimeUtils.h new file mode 100644 index 0000000..078753e --- /dev/null +++ b/xbmc/utils/TimeUtils.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include + +class CDateTime; + +int64_t CurrentHostCounter(void); +int64_t CurrentHostFrequency(void); + +class CTimeUtils +{ +public: + + /*! + * @brief Update the time frame + * @note Not threadsafe + */ + static void UpdateFrameTime(bool flip); + + /*! + * @brief Returns the frame time in MS + * @note Not threadsafe + */ + static unsigned int GetFrameTime(); + static CDateTime GetLocalTime(time_t time); + + /*! + * @brief Returns a time string without seconds, i.e: HH:MM + * @param hhmmss Time string in the format HH:MM:SS + */ + static std::string WithoutSeconds(const std::string hhmmss); +private: + static unsigned int frameTime; +}; + diff --git a/xbmc/utils/TransformMatrix.h b/xbmc/utils/TransformMatrix.h new file mode 100644 index 0000000..34c2092 --- /dev/null +++ b/xbmc/utils/TransformMatrix.h @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/Color.h" + +#include +#include +#include +#include + +#ifdef __GNUC__ +// under gcc, inline will only take place if optimizations are applied (-O). this will force inline even with optimizations. +#define XBMC_FORCE_INLINE __attribute__((always_inline)) +#else +#define XBMC_FORCE_INLINE +#endif + +class TransformMatrix +{ +public: + TransformMatrix() + { + Reset(); + }; + void Reset() + { + m[0][0] = 1.0f; m[0][1] = m[0][2] = m[0][3] = 0.0f; + m[1][0] = m[1][2] = m[1][3] = 0.0f; m[1][1] = 1.0f; + m[2][0] = m[2][1] = m[2][3] = 0.0f; m[2][2] = 1.0f; + alpha = 1.0f; + identity = true; + }; + static TransformMatrix CreateTranslation(float transX, float transY, float transZ = 0) + { + TransformMatrix translation; + translation.SetTranslation(transX, transY, transZ); + return translation; + } + void SetTranslation(float transX, float transY, float transZ) + { + m[0][1] = m[0][2] = 0.0f; m[0][0] = 1.0f; m[0][3] = transX; + m[1][0] = m[1][2] = 0.0f; m[1][1] = 1.0f; m[1][3] = transY; + m[2][0] = m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = transZ; + alpha = 1.0f; + identity = (transX == 0 && transY == 0 && transZ == 0); + } + static TransformMatrix CreateScaler(float scaleX, float scaleY, float scaleZ = 1.0f) + { + TransformMatrix scaler; + scaler.m[0][0] = scaleX; + scaler.m[1][1] = scaleY; + scaler.m[2][2] = scaleZ; + scaler.identity = (scaleX == 1 && scaleY == 1 && scaleZ == 1); + return scaler; + }; + void SetScaler(float scaleX, float scaleY, float centerX, float centerY) + { + // Trans(centerX,centerY,centerZ)*Scale(scaleX,scaleY,scaleZ)*Trans(-centerX,-centerY,-centerZ) + float centerZ = 0.0f, scaleZ = 1.0f; + m[0][0] = scaleX; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = centerX*(1-scaleX); + m[1][0] = 0.0f; m[1][1] = scaleY; m[1][2] = 0.0f; m[1][3] = centerY*(1-scaleY); + m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = scaleZ; m[2][3] = centerZ*(1-scaleZ); + alpha = 1.0f; + identity = (scaleX == 1 && scaleY == 1); + }; + void SetXRotation(float angle, float y, float z, float ar = 1.0f) + { // angle about the X axis, centered at y,z where our coordinate system has aspect ratio ar. + // Trans(0,y,z)*Scale(1,1/ar,1)*RotateX(angle)*Scale(ar,1,1)*Trans(0,-y,-z); + float c = cos(angle); float s = sin(angle); + m[0][0] = ar; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = 0.0f; + m[1][0] = 0.0f; m[1][1] = c/ar; m[1][2] = -s/ar; m[1][3] = (-y*c+s*z)/ar + y; + m[2][0] = 0.0f; m[2][1] = s; m[2][2] = c; m[2][3] = (-y*s-c*z) + z; + alpha = 1.0f; + identity = (angle == 0); + } + void SetYRotation(float angle, float x, float z, float ar = 1.0f) + { // angle about the Y axis, centered at x,z where our coordinate system has aspect ratio ar. + // Trans(x,0,z)*Scale(1/ar,1,1)*RotateY(angle)*Scale(ar,1,1)*Trans(-x,0,-z); + float c = cos(angle); float s = sin(angle); + m[0][0] = c; m[0][1] = 0.0f; m[0][2] = -s/ar; m[0][3] = -x*c + s*z/ar + x; + m[1][0] = 0.0f; m[1][1] = 1.0f; m[1][2] = 0.0f; m[1][3] = 0.0f; + m[2][0] = ar*s; m[2][1] = 0.0f; m[2][2] = c; m[2][3] = -ar*x*s - c*z + z; + alpha = 1.0f; + identity = (angle == 0); + } + static TransformMatrix CreateZRotation(float angle, float x, float y, float ar = 1.0f) + { // angle about the Z axis, centered at x,y where our coordinate system has aspect ratio ar. + // Trans(x,y,0)*Scale(1/ar,1,1)*RotateZ(angle)*Scale(ar,1,1)*Trans(-x,-y,0) + TransformMatrix rot; + rot.SetZRotation(angle, x, y, ar); + return rot; + } + void SetZRotation(float angle, float x, float y, float ar = 1.0f) + { // angle about the Z axis, centered at x,y where our coordinate system has aspect ratio ar. + // Trans(x,y,0)*Scale(1/ar,1,1)*RotateZ(angle)*Scale(ar,1,1)*Trans(-x,-y,0) + float c = cos(angle); float s = sin(angle); + m[0][0] = c; m[0][1] = -s/ar; m[0][2] = 0.0f; m[0][3] = -x*c + s*y/ar + x; + m[1][0] = s*ar; m[1][1] = c; m[1][2] = 0.0f; m[1][3] = -ar*x*s - c*y + y; + m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = 0.0f; + alpha = 1.0f; + identity = (angle == 0); + } + static TransformMatrix CreateFader(float a) + { + TransformMatrix fader; + fader.SetFader(a); + return fader; + } + void SetFader(float a) + { + m[0][0] = 1.0f; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = 0.0f; + m[1][0] = 0.0f; m[1][1] = 1.0f; m[1][2] = 0.0f; m[1][3] = 0.0f; + m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = 0.0f; + alpha = a; + identity = (a == 1.0f); + } + + // multiplication operators + const TransformMatrix &operator *=(const TransformMatrix &right) + { + if (right.identity) + return *this; + if (identity) + { + *this = right; + return *this; + } + float t00 = m[0][0] * right.m[0][0] + m[0][1] * right.m[1][0] + m[0][2] * right.m[2][0]; + float t01 = m[0][0] * right.m[0][1] + m[0][1] * right.m[1][1] + m[0][2] * right.m[2][1]; + float t02 = m[0][0] * right.m[0][2] + m[0][1] * right.m[1][2] + m[0][2] * right.m[2][2]; + m[0][3] = m[0][0] * right.m[0][3] + m[0][1] * right.m[1][3] + m[0][2] * right.m[2][3] + m[0][3]; + m[0][0] = t00; m[0][1] = t01; m[0][2] = t02; + t00 = m[1][0] * right.m[0][0] + m[1][1] * right.m[1][0] + m[1][2] * right.m[2][0]; + t01 = m[1][0] * right.m[0][1] + m[1][1] * right.m[1][1] + m[1][2] * right.m[2][1]; + t02 = m[1][0] * right.m[0][2] + m[1][1] * right.m[1][2] + m[1][2] * right.m[2][2]; + m[1][3] = m[1][0] * right.m[0][3] + m[1][1] * right.m[1][3] + m[1][2] * right.m[2][3] + m[1][3]; + m[1][0] = t00; m[1][1] = t01; m[1][2] = t02; + t00 = m[2][0] * right.m[0][0] + m[2][1] * right.m[1][0] + m[2][2] * right.m[2][0]; + t01 = m[2][0] * right.m[0][1] + m[2][1] * right.m[1][1] + m[2][2] * right.m[2][1]; + t02 = m[2][0] * right.m[0][2] + m[2][1] * right.m[1][2] + m[2][2] * right.m[2][2]; + m[2][3] = m[2][0] * right.m[0][3] + m[2][1] * right.m[1][3] + m[2][2] * right.m[2][3] + m[2][3]; + m[2][0] = t00; m[2][1] = t01; m[2][2] = t02; + alpha *= right.alpha; + identity = false; + return *this; + } + + TransformMatrix operator *(const TransformMatrix &right) const + { + if (right.identity) + return *this; + if (identity) + return right; + TransformMatrix result; + result.m[0][0] = m[0][0] * right.m[0][0] + m[0][1] * right.m[1][0] + m[0][2] * right.m[2][0]; + result.m[0][1] = m[0][0] * right.m[0][1] + m[0][1] * right.m[1][1] + m[0][2] * right.m[2][1]; + result.m[0][2] = m[0][0] * right.m[0][2] + m[0][1] * right.m[1][2] + m[0][2] * right.m[2][2]; + result.m[0][3] = m[0][0] * right.m[0][3] + m[0][1] * right.m[1][3] + m[0][2] * right.m[2][3] + m[0][3]; + result.m[1][0] = m[1][0] * right.m[0][0] + m[1][1] * right.m[1][0] + m[1][2] * right.m[2][0]; + result.m[1][1] = m[1][0] * right.m[0][1] + m[1][1] * right.m[1][1] + m[1][2] * right.m[2][1]; + result.m[1][2] = m[1][0] * right.m[0][2] + m[1][1] * right.m[1][2] + m[1][2] * right.m[2][2]; + result.m[1][3] = m[1][0] * right.m[0][3] + m[1][1] * right.m[1][3] + m[1][2] * right.m[2][3] + m[1][3]; + result.m[2][0] = m[2][0] * right.m[0][0] + m[2][1] * right.m[1][0] + m[2][2] * right.m[2][0]; + result.m[2][1] = m[2][0] * right.m[0][1] + m[2][1] * right.m[1][1] + m[2][2] * right.m[2][1]; + result.m[2][2] = m[2][0] * right.m[0][2] + m[2][1] * right.m[1][2] + m[2][2] * right.m[2][2]; + result.m[2][3] = m[2][0] * right.m[0][3] + m[2][1] * right.m[1][3] + m[2][2] * right.m[2][3] + m[2][3]; + result.alpha = alpha * right.alpha; + result.identity = false; + return result; + } + + inline void TransformPosition(float &x, float &y, float &z) const XBMC_FORCE_INLINE + { + float newX = m[0][0] * x + m[0][1] * y + m[0][2] * z + m[0][3]; + float newY = m[1][0] * x + m[1][1] * y + m[1][2] * z + m[1][3]; + z = m[2][0] * x + m[2][1] * y + m[2][2] * z + m[2][3]; + y = newY; + x = newX; + } + + inline void TransformPositionUnscaled(float &x, float &y, float &z) const XBMC_FORCE_INLINE + { + float n; + // calculate the norm of the transformed (but not translated) vectors involved + n = sqrt(m[0][0]*m[0][0] + m[0][1]*m[0][1] + m[0][2]*m[0][2]); + float newX = (m[0][0] * x + m[0][1] * y + m[0][2] * z)/n + m[0][3]; + n = sqrt(m[1][0]*m[1][0] + m[1][1]*m[1][1] + m[1][2]*m[1][2]); + float newY = (m[1][0] * x + m[1][1] * y + m[1][2] * z)/n + m[1][3]; + n = sqrt(m[2][0]*m[2][0] + m[2][1]*m[2][1] + m[2][2]*m[2][2]); + float newZ = (m[2][0] * x + m[2][1] * y + m[2][2] * z)/n + m[2][3]; + z = newZ; + y = newY; + x = newX; + } + + inline void InverseTransformPosition(float &x, float &y) const XBMC_FORCE_INLINE + { // used for mouse - no way to find z + x -= m[0][3]; y -= m[1][3]; + float detM = m[0][0]*m[1][1] - m[0][1]*m[1][0]; + float newX = (m[1][1] * x - m[0][1] * y)/detM; + y = (-m[1][0] * x + m[0][0] * y)/detM; + x = newX; + } + + inline float TransformXCoord(float x, float y, float z) const XBMC_FORCE_INLINE + { + return m[0][0] * x + m[0][1] * y + m[0][2] * z + m[0][3]; + } + + inline float TransformYCoord(float x, float y, float z) const XBMC_FORCE_INLINE + { + return m[1][0] * x + m[1][1] * y + m[1][2] * z + m[1][3]; + } + + inline float TransformZCoord(float x, float y, float z) const XBMC_FORCE_INLINE + { + return m[2][0] * x + m[2][1] * y + m[2][2] * z + m[2][3]; + } + + inline UTILS::Color TransformAlpha(UTILS::Color color) const XBMC_FORCE_INLINE + { + return static_cast(color * alpha); + } + + float m[3][4]; + float alpha; + bool identity; +}; + +inline bool operator==(const TransformMatrix &a, const TransformMatrix &b) +{ + return a.alpha == b.alpha && ((a.identity && b.identity) || + (!a.identity && !b.identity && std::equal(&a.m[0][0], &a.m[0][0] + sizeof (a.m) / sizeof (a.m[0][0]), &b.m[0][0]))); +} + +inline bool operator!=(const TransformMatrix &a, const TransformMatrix &b) +{ + return !operator==(a, b); +} diff --git a/xbmc/utils/UDMABufferObject.cpp b/xbmc/utils/UDMABufferObject.cpp new file mode 100644 index 0000000..b488d78 --- /dev/null +++ b/xbmc/utils/UDMABufferObject.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "UDMABufferObject.h" + +#include "utils/BufferObjectFactory.h" +#include "utils/log.h" + +#include +#include +#include +#include + +namespace +{ + +const auto PAGESIZE = getpagesize(); + +int RoundUp(int num, int factor) +{ + return num + factor - 1 - (num - 1) % factor; +} + +} // namespace + +std::unique_ptr CUDMABufferObject::Create() +{ + return std::make_unique(); +} + +void CUDMABufferObject::Register() +{ + int fd = open("/dev/udmabuf", O_RDWR); + if (fd < 0) + { + CLog::Log(LOGDEBUG, "CUDMABufferObject::{} - unable to open /dev/udmabuf: {}", __FUNCTION__, + strerror(errno)); + return; + } + + close(fd); + + CBufferObjectFactory::RegisterBufferObject(CUDMABufferObject::Create); +} + +CUDMABufferObject::~CUDMABufferObject() +{ + ReleaseMemory(); + DestroyBufferObject(); + + int ret = close(m_udmafd); + if (ret < 0) + CLog::Log(LOGERROR, "CUDMABufferObject::{} - close /dev/udmabuf failed, errno={}", __FUNCTION__, + strerror(errno)); + + m_udmafd = -1; +} + +bool CUDMABufferObject::CreateBufferObject(uint32_t format, uint32_t width, uint32_t height) +{ + if (m_fd >= 0) + return true; + + uint32_t bpp{1}; + + switch (format) + { + case DRM_FORMAT_ARGB8888: + bpp = 4; + break; + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_RGB565: + bpp = 2; + break; + default: + throw std::runtime_error("CUDMABufferObject: pixel format not implemented"); + } + + m_stride = width * bpp; + + return CreateBufferObject(width * height * bpp); +} + +bool CUDMABufferObject::CreateBufferObject(uint64_t size) +{ + // Must be rounded to the system page size + m_size = RoundUp(size, PAGESIZE); + + m_memfd = memfd_create("kodi", MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (m_memfd < 0) + { + CLog::Log(LOGERROR, "CUDMABufferObject::{} - memfd_create failed: {}", __FUNCTION__, + strerror(errno)); + return false; + } + + if (ftruncate(m_memfd, m_size) < 0) + { + CLog::Log(LOGERROR, "CUDMABufferObject::{} - ftruncate failed: {}", __FUNCTION__, + strerror(errno)); + return false; + } + + if (fcntl(m_memfd, F_ADD_SEALS, F_SEAL_SHRINK) < 0) + { + CLog::Log(LOGERROR, "CUDMABufferObject::{} - fcntl failed: {}", __FUNCTION__, strerror(errno)); + close(m_memfd); + return false; + } + + if (m_udmafd < 0) + { + m_udmafd = open("/dev/udmabuf", O_RDWR); + if (m_udmafd < 0) + { + CLog::Log(LOGERROR, "CUDMABufferObject::{} - unable to open /dev/udmabuf: {}", __FUNCTION__, + strerror(errno)); + close(m_memfd); + return false; + } + } + + struct udmabuf_create_item create = { + .memfd = static_cast(m_memfd), + .offset = 0, + .size = m_size, + }; + + m_fd = ioctl(m_udmafd, UDMABUF_CREATE, &create); + if (m_fd < 0) + { + CLog::Log(LOGERROR, "CUDMABufferObject::{} - ioctl UDMABUF_CREATE failed: {}", __FUNCTION__, + strerror(errno)); + close(m_memfd); + return false; + } + + return true; +} + +void CUDMABufferObject::DestroyBufferObject() +{ + if (m_fd < 0) + return; + + int ret = close(m_fd); + if (ret < 0) + CLog::Log(LOGERROR, "CUDMABufferObject::{} - close fd failed, errno={}", __FUNCTION__, + strerror(errno)); + + ret = close(m_memfd); + if (ret < 0) + CLog::Log(LOGERROR, "CUDMABufferObject::{} - close memfd failed, errno={}", __FUNCTION__, + strerror(errno)); + + m_memfd = -1; + m_fd = -1; + m_stride = 0; + m_size = 0; +} + +uint8_t* CUDMABufferObject::GetMemory() +{ + if (m_fd < 0) + return nullptr; + + if (m_map) + { + CLog::Log(LOGDEBUG, "CUDMABufferObject::{} - already mapped fd={} map={}", __FUNCTION__, m_fd, + fmt::ptr(m_map)); + return m_map; + } + + m_map = static_cast(mmap(nullptr, m_size, PROT_WRITE, MAP_SHARED, m_memfd, 0)); + if (m_map == MAP_FAILED) + { + CLog::Log(LOGERROR, "CUDMABufferObject::{} - mmap failed, errno={}", __FUNCTION__, + strerror(errno)); + return nullptr; + } + + return m_map; +} + +void CUDMABufferObject::ReleaseMemory() +{ + if (!m_map) + return; + + int ret = munmap(m_map, m_size); + if (ret < 0) + CLog::Log(LOGERROR, "CUDMABufferObject::{} - munmap failed, errno={}", __FUNCTION__, + strerror(errno)); + + m_map = nullptr; +} diff --git a/xbmc/utils/UDMABufferObject.h b/xbmc/utils/UDMABufferObject.h new file mode 100644 index 0000000..a842560 --- /dev/null +++ b/xbmc/utils/UDMABufferObject.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/BufferObject.h" + +#include +#include + +class CUDMABufferObject : public CBufferObject +{ +public: + CUDMABufferObject() = default; + virtual ~CUDMABufferObject() override; + + // Registration + static std::unique_ptr Create(); + static void Register(); + + // IBufferObject overrides via CBufferObject + bool CreateBufferObject(uint32_t format, uint32_t width, uint32_t height) override; + bool CreateBufferObject(uint64_t size) override; + void DestroyBufferObject() override; + uint8_t* GetMemory() override; + void ReleaseMemory() override; + std::string GetName() const override { return "CUDMABufferObject"; } + +private: + int m_memfd{-1}; + int m_udmafd{-1}; + uint64_t m_size{0}; + uint8_t* m_map{nullptr}; +}; diff --git a/xbmc/utils/URIUtils.cpp b/xbmc/utils/URIUtils.cpp new file mode 100644 index 0000000..738c946 --- /dev/null +++ b/xbmc/utils/URIUtils.cpp @@ -0,0 +1,1441 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "network/Network.h" +#include "URIUtils.h" +#include "FileItem.h" +#include "filesystem/MultiPathDirectory.h" +#include "filesystem/SpecialProtocol.h" +#include "filesystem/StackDirectory.h" +#include "network/DNSNameCache.h" +#include "pvr/channels/PVRChannelsPath.h" +#include "settings/AdvancedSettings.h" +#include "URL.h" +#include "utils/FileExtensionProvider.h" +#include "ServiceBroker.h" +#include "StringUtils.h" +#include "utils/log.h" + +#if defined(TARGET_WINDOWS) +#include "platform/win32/CharsetConverter.h" +#endif + +#include +#include +#include +#include + +using namespace PVR; +using namespace XFILE; + +const CAdvancedSettings* URIUtils::m_advancedSettings = nullptr; + +void URIUtils::RegisterAdvancedSettings(const CAdvancedSettings& advancedSettings) +{ + m_advancedSettings = &advancedSettings; +} + +void URIUtils::UnregisterAdvancedSettings() +{ + m_advancedSettings = nullptr; +} + +/* returns filename extension including period of filename */ +std::string URIUtils::GetExtension(const CURL& url) +{ + return URIUtils::GetExtension(url.GetFileName()); +} + +std::string URIUtils::GetExtension(const std::string& strFileName) +{ + if (IsURL(strFileName)) + { + CURL url(strFileName); + return GetExtension(url.GetFileName()); + } + + size_t period = strFileName.find_last_of("./\\"); + if (period == std::string::npos || strFileName[period] != '.') + return std::string(); + + return strFileName.substr(period); +} + +bool URIUtils::HasExtension(const std::string& strFileName) +{ + if (IsURL(strFileName)) + { + CURL url(strFileName); + return HasExtension(url.GetFileName()); + } + + size_t iPeriod = strFileName.find_last_of("./\\"); + return iPeriod != std::string::npos && strFileName[iPeriod] == '.'; +} + +bool URIUtils::HasExtension(const CURL& url, const std::string& strExtensions) +{ + return HasExtension(url.GetFileName(), strExtensions); +} + +bool URIUtils::HasExtension(const std::string& strFileName, const std::string& strExtensions) +{ + if (IsURL(strFileName)) + { + CURL url(strFileName); + return HasExtension(url.GetFileName(), strExtensions); + } + + // Search backwards so that '.' can be used as a search terminator. + std::string::const_reverse_iterator itExtensions = strExtensions.rbegin(); + while (itExtensions != strExtensions.rend()) + { + // Iterate backwards over strFileName untill we hit a '.' or a mismatch + for (std::string::const_reverse_iterator itFileName = strFileName.rbegin(); + itFileName != strFileName.rend() && itExtensions != strExtensions.rend() && + tolower(*itFileName) == *itExtensions; + ++itFileName, ++itExtensions) + { + if (*itExtensions == '.') + return true; // Match + } + + // No match. Look for more extensions to try. + while (itExtensions != strExtensions.rend() && *itExtensions != '|') + ++itExtensions; + + while (itExtensions != strExtensions.rend() && *itExtensions == '|') + ++itExtensions; + } + + return false; +} + +void URIUtils::RemoveExtension(std::string& strFileName) +{ + if(IsURL(strFileName)) + { + CURL url(strFileName); + strFileName = url.GetFileName(); + RemoveExtension(strFileName); + url.SetFileName(strFileName); + strFileName = url.Get(); + return; + } + + size_t period = strFileName.find_last_of("./\\"); + if (period != std::string::npos && strFileName[period] == '.') + { + std::string strExtension = strFileName.substr(period); + StringUtils::ToLower(strExtension); + strExtension += "|"; + + std::string strFileMask; + strFileMask = CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(); + strFileMask += "|" + CServiceBroker::GetFileExtensionProvider().GetMusicExtensions(); + strFileMask += "|" + CServiceBroker::GetFileExtensionProvider().GetVideoExtensions(); + strFileMask += "|" + CServiceBroker::GetFileExtensionProvider().GetSubtitleExtensions(); +#if defined(TARGET_DARWIN) + strFileMask += "|.py|.xml|.milk|.xbt|.cdg|.app|.applescript|.workflow"; +#else + strFileMask += "|.py|.xml|.milk|.xbt|.cdg"; +#endif + strFileMask += "|"; + + if (strFileMask.find(strExtension) != std::string::npos) + strFileName.erase(period); + } +} + +std::string URIUtils::ReplaceExtension(const std::string& strFile, + const std::string& strNewExtension) +{ + if(IsURL(strFile)) + { + CURL url(strFile); + url.SetFileName(ReplaceExtension(url.GetFileName(), strNewExtension)); + return url.Get(); + } + + std::string strChangedFile; + std::string strExtension = GetExtension(strFile); + if ( strExtension.size() ) + { + strChangedFile = strFile.substr(0, strFile.size() - strExtension.size()) ; + strChangedFile += strNewExtension; + } + else + { + strChangedFile = strFile; + strChangedFile += strNewExtension; + } + return strChangedFile; +} + +std::string URIUtils::GetFileName(const CURL& url) +{ + return GetFileName(url.GetFileName()); +} + +/* returns a filename given an url */ +/* handles both / and \, and options in urls*/ +std::string URIUtils::GetFileName(const std::string& strFileNameAndPath) +{ + if(IsURL(strFileNameAndPath)) + { + CURL url(strFileNameAndPath); + return GetFileName(url.GetFileName()); + } + + /* find the last slash */ + const size_t slash = strFileNameAndPath.find_last_of("/\\"); + return strFileNameAndPath.substr(slash+1); +} + +void URIUtils::Split(const std::string& strFileNameAndPath, + std::string& strPath, std::string& strFileName) +{ + //Splits a full filename in path and file. + //ex. smb://computer/share/directory/filename.ext -> strPath:smb://computer/share/directory/ and strFileName:filename.ext + //Trailing slash will be preserved + strFileName = ""; + strPath = ""; + int i = strFileNameAndPath.size() - 1; + while (i > 0) + { + char ch = strFileNameAndPath[i]; + // Only break on ':' if it's a drive separator for DOS (ie d:foo) + if (ch == '/' || ch == '\\' || (ch == ':' && i == 1)) break; + else i--; + } + if (i == 0) + i--; + + // take left including the directory separator + strPath = strFileNameAndPath.substr(0, i+1); + // everything to the right of the directory separator + strFileName = strFileNameAndPath.substr(i+1); + + // if actual uri, ignore options + if (IsURL(strFileNameAndPath)) + { + i = strFileName.size() - 1; + while (i > 0) + { + char ch = strFileName[i]; + if (ch == '?' || ch == '|') break; + else i--; + } + if (i > 0) + strFileName = strFileName.substr(0, i); + } +} + +std::vector URIUtils::SplitPath(const std::string& strPath) +{ + CURL url(strPath); + + // silly std::string can't take a char in the constructor + std::string sep(1, url.GetDirectorySeparator()); + + // split the filename portion of the URL up into separate dirs + std::vector dirs = StringUtils::Split(url.GetFileName(), sep); + + // we start with the root path + std::string dir = url.GetWithoutFilename(); + + if (!dir.empty()) + dirs.insert(dirs.begin(), dir); + + // we don't need empty token on the end + if (dirs.size() > 1 && dirs.back().empty()) + dirs.erase(dirs.end() - 1); + + return dirs; +} + +void URIUtils::GetCommonPath(std::string& strParent, const std::string& strPath) +{ + // find the common path of parent and path + unsigned int j = 1; + while (j <= std::min(strParent.size(), strPath.size()) && + StringUtils::CompareNoCase(strParent, strPath, j) == 0) + j++; + strParent.erase(j - 1); + // they should at least share a / at the end, though for things such as path/cd1 and path/cd2 there won't be + if (!HasSlashAtEnd(strParent)) + { + strParent = GetDirectory(strParent); + AddSlashAtEnd(strParent); + } +} + +bool URIUtils::HasParentInHostname(const CURL& url) +{ + return url.IsProtocol("zip") || url.IsProtocol("apk") || url.IsProtocol("bluray") || + url.IsProtocol("udf") || url.IsProtocol("iso9660") || url.IsProtocol("xbt") || + (CServiceBroker::IsBinaryAddonCacheUp() && + CServiceBroker::GetFileExtensionProvider().EncodedHostName(url.GetProtocol())); +} + +bool URIUtils::HasEncodedHostname(const CURL& url) +{ + return HasParentInHostname(url) + || url.IsProtocol("musicsearch") + || url.IsProtocol( "image"); +} + +bool URIUtils::HasEncodedFilename(const CURL& url) +{ + const std::string prot2 = url.GetTranslatedProtocol(); + + // For now assume only (quasi) http internet streams use URL encoding + return CURL::IsProtocolEqual(prot2, "http") || + CURL::IsProtocolEqual(prot2, "https"); +} + +std::string URIUtils::GetParentPath(const std::string& strPath) +{ + std::string strReturn; + GetParentPath(strPath, strReturn); + return strReturn; +} + +bool URIUtils::GetParentPath(const std::string& strPath, std::string& strParent) +{ + strParent.clear(); + + CURL url(strPath); + std::string strFile = url.GetFileName(); + if ( URIUtils::HasParentInHostname(url) && strFile.empty()) + { + strFile = url.GetHostName(); + return GetParentPath(strFile, strParent); + } + else if (url.IsProtocol("stack")) + { + CStackDirectory dir; + CFileItemList items; + if (!dir.GetDirectory(url, items)) + return false; + CURL url2(GetDirectory(items[0]->GetPath())); + if (HasParentInHostname(url2)) + GetParentPath(url2.Get(), strParent); + else + strParent = url2.Get(); + for( int i=1;im_strDVDLabel = GetDirectory(items[i]->GetPath()); + if (HasParentInHostname(url2)) + items[i]->SetPath(GetParentPath(items[i]->m_strDVDLabel)); + else + items[i]->SetPath(items[i]->m_strDVDLabel); + + GetCommonPath(strParent,items[i]->GetPath()); + } + return true; + } + else if (url.IsProtocol("multipath")) + { + // get the parent path of the first item + return GetParentPath(CMultiPathDirectory::GetFirstPath(strPath), strParent); + } + else if (url.IsProtocol("plugin")) + { + if (!url.GetOptions().empty()) + { + //! @todo Make a new python call to get the plugin content type and remove this temporary hack + // When a plugin provides multiple types, it has "plugin://addon.id/?content_type=xxx" root URL + if (url.GetFileName().empty() && url.HasOption("content_type") && url.GetOptions().find('&') == std::string::npos) + url.SetHostName(""); + // + url.SetOptions(""); + strParent = url.Get(); + return true; + } + if (!url.GetFileName().empty()) + { + url.SetFileName(""); + strParent = url.Get(); + return true; + } + if (!url.GetHostName().empty()) + { + url.SetHostName(""); + strParent = url.Get(); + return true; + } + return true; // already at root + } + else if (url.IsProtocol("special")) + { + if (HasSlashAtEnd(strFile)) + strFile.erase(strFile.size() - 1); + if(strFile.rfind('/') == std::string::npos) + return false; + } + else if (strFile.empty()) + { + if (!url.GetHostName().empty()) + { + // we have an share with only server or workgroup name + // set hostname to "" and return true to get back to root + url.SetHostName(""); + strParent = url.Get(); + return true; + } + return false; + } + + if (HasSlashAtEnd(strFile) ) + { + strFile.erase(strFile.size() - 1); + } + + size_t iPos = strFile.rfind('/'); +#ifndef TARGET_POSIX + if (iPos == std::string::npos) + { + iPos = strFile.rfind('\\'); + } +#endif + if (iPos == std::string::npos) + { + url.SetFileName(""); + strParent = url.Get(); + return true; + } + + strFile.erase(iPos); + + AddSlashAtEnd(strFile); + + url.SetFileName(strFile); + strParent = url.Get(); + return true; +} + +std::string URIUtils::GetBasePath(const std::string& strPath) +{ + std::string strCheck(strPath); + if (IsStack(strPath)) + strCheck = CStackDirectory::GetFirstStackedFile(strPath); + + std::string strDirectory = GetDirectory(strCheck); + if (IsInRAR(strCheck)) + { + std::string strPath=strDirectory; + GetParentPath(strPath, strDirectory); + } + if (IsStack(strPath)) + { + strCheck = strDirectory; + RemoveSlashAtEnd(strCheck); + if (GetFileName(strCheck).size() == 3 && StringUtils::StartsWithNoCase(GetFileName(strCheck), "cd")) + strDirectory = GetDirectory(strCheck); + } + return strDirectory; +} + +std::string URLEncodePath(const std::string& strPath) +{ + std::vector segments = StringUtils::Split(strPath, "/"); + for (std::vector::iterator i = segments.begin(); i != segments.end(); ++i) + *i = CURL::Encode(*i); + + return StringUtils::Join(segments, "/"); +} + +std::string URLDecodePath(const std::string& strPath) +{ + std::vector segments = StringUtils::Split(strPath, "/"); + for (std::vector::iterator i = segments.begin(); i != segments.end(); ++i) + *i = CURL::Decode(*i); + + return StringUtils::Join(segments, "/"); +} + +std::string URIUtils::ChangeBasePath(const std::string &fromPath, const std::string &fromFile, const std::string &toPath, const bool &bAddPath /* = true */) +{ + std::string toFile = fromFile; + + // Convert back slashes to forward slashes, if required + if (IsDOSPath(fromPath) && !IsDOSPath(toPath)) + StringUtils::Replace(toFile, "\\", "/"); + + // Handle difference in URL encoded vs. not encoded + if ( HasEncodedFilename(CURL(fromPath)) + && !HasEncodedFilename(CURL(toPath)) ) + { + toFile = URLDecodePath(toFile); // Decode path + } + else if (!HasEncodedFilename(CURL(fromPath)) + && HasEncodedFilename(CURL(toPath)) ) + { + toFile = URLEncodePath(toFile); // Encode path + } + + // Convert forward slashes to back slashes, if required + if (!IsDOSPath(fromPath) && IsDOSPath(toPath)) + StringUtils::Replace(toFile, "/", "\\"); + + if (bAddPath) + return AddFileToFolder(toPath, toFile); + + return toFile; +} + +CURL URIUtils::SubstitutePath(const CURL& url, bool reverse /* = false */) +{ + const std::string pathToUrl = url.Get(); + return CURL(SubstitutePath(pathToUrl, reverse)); +} + +std::string URIUtils::SubstitutePath(const std::string& strPath, bool reverse /* = false */) +{ + if (!m_advancedSettings) + { + // path substitution not needed / not working during Kodi bootstrap. + return strPath; + } + + for (const auto& pathPair : m_advancedSettings->m_pathSubstitutions) + { + const std::string fromPath = reverse ? pathPair.second : pathPair.first; + const std::string toPath = reverse ? pathPair.first : pathPair.second; + + if (strncmp(strPath.c_str(), fromPath.c_str(), HasSlashAtEnd(fromPath) ? fromPath.size() - 1 : fromPath.size()) == 0) + { + if (strPath.size() > fromPath.size()) + { + std::string strSubPathAndFileName = strPath.substr(fromPath.size()); + return ChangeBasePath(fromPath, strSubPathAndFileName, toPath); // Fix encoding + slash direction + } + else + { + return toPath; + } + } + } + return strPath; +} + +bool URIUtils::IsProtocol(const std::string& url, const std::string &type) +{ + return StringUtils::StartsWithNoCase(url, type + "://"); +} + +bool URIUtils::PathHasParent(std::string path, std::string parent, bool translate /* = false */) +{ + if (translate) + { + path = CSpecialProtocol::TranslatePath(path); + parent = CSpecialProtocol::TranslatePath(parent); + } + + if (parent.empty()) + return false; + + if (path == parent) + return true; + + // Make sure parent has a trailing slash + AddSlashAtEnd(parent); + + return StringUtils::StartsWith(path, parent); +} + +bool URIUtils::PathEquals(std::string path1, std::string path2, bool ignoreTrailingSlash /* = false */, bool ignoreURLOptions /* = false */) +{ + if (ignoreURLOptions) + { + path1 = CURL(path1).GetWithoutOptions(); + path2 = CURL(path2).GetWithoutOptions(); + } + + if (ignoreTrailingSlash) + { + RemoveSlashAtEnd(path1); + RemoveSlashAtEnd(path2); + } + + return (path1 == path2); +} + +bool URIUtils::IsRemote(const std::string& strFile) +{ + if (IsCDDA(strFile) || IsISO9660(strFile)) + return false; + + if (IsStack(strFile)) + return IsRemote(CStackDirectory::GetFirstStackedFile(strFile)); + + if (IsSpecial(strFile)) + return IsRemote(CSpecialProtocol::TranslatePath(strFile)); + + if(IsMultiPath(strFile)) + { // virtual paths need to be checked separately + std::vector paths; + if (CMultiPathDirectory::GetPaths(strFile, paths)) + { + for (unsigned int i = 0; i < paths.size(); i++) + if (IsRemote(paths[i])) return true; + } + return false; + } + + CURL url(strFile); + if(HasParentInHostname(url)) + return IsRemote(url.GetHostName()); + + if (IsAddonsPath(strFile)) + return false; + + if (IsSourcesPath(strFile)) + return false; + + if (IsVideoDb(strFile) || IsMusicDb(strFile)) + return false; + + if (IsLibraryFolder(strFile)) + return false; + + if (IsPlugin(strFile)) + return false; + + if (IsAndroidApp(strFile)) + return false; + + if (!url.IsLocal()) + return true; + + return false; +} + +bool URIUtils::IsOnDVD(const std::string& strFile) +{ + if (IsProtocol(strFile, "dvd")) + return true; + + if (IsProtocol(strFile, "udf")) + return true; + + if (IsProtocol(strFile, "iso9660")) + return true; + + if (IsProtocol(strFile, "cdda")) + return true; + +#if defined(TARGET_WINDOWS_STORE) + CLog::Log(LOGDEBUG, "%s is not implemented", __FUNCTION__); +#elif defined(TARGET_WINDOWS_DESKTOP) + using KODI::PLATFORM::WINDOWS::ToW; + if (strFile.size() >= 2 && strFile.substr(1, 1) == ":") + return (GetDriveType(ToW(strFile.substr(0, 3)).c_str()) == DRIVE_CDROM); +#endif + return false; +} + +bool URIUtils::IsOnLAN(const std::string& strPath) +{ + if(IsMultiPath(strPath)) + return IsOnLAN(CMultiPathDirectory::GetFirstPath(strPath)); + + if(IsStack(strPath)) + return IsOnLAN(CStackDirectory::GetFirstStackedFile(strPath)); + + if(IsSpecial(strPath)) + return IsOnLAN(CSpecialProtocol::TranslatePath(strPath)); + + if(IsPlugin(strPath)) + return false; + + if(IsUPnP(strPath)) + return true; + + CURL url(strPath); + if (HasParentInHostname(url)) + return IsOnLAN(url.GetHostName()); + + if(!IsRemote(strPath)) + return false; + + std::string host = url.GetHostName(); + + return IsHostOnLAN(host); +} + +static bool addr_match(uint32_t addr, const char* target, const char* submask) +{ + uint32_t addr2 = ntohl(inet_addr(target)); + uint32_t mask = ntohl(inet_addr(submask)); + return (addr & mask) == (addr2 & mask); +} + +bool URIUtils::IsHostOnLAN(const std::string& host, bool offLineCheck) +{ + if(host.length() == 0) + return false; + + // assume a hostname without dot's + // is local (smb netbios hostnames) + if(host.find('.') == std::string::npos) + return true; + + uint32_t address = ntohl(inet_addr(host.c_str())); + if(address == INADDR_NONE) + { + std::string ip; + if(CDNSNameCache::Lookup(host, ip)) + address = ntohl(inet_addr(ip.c_str())); + } + + if(address != INADDR_NONE) + { + if (offLineCheck) // check if in private range, ref https://en.wikipedia.org/wiki/Private_network + { + if ( + addr_match(address, "192.168.0.0", "255.255.0.0") || + addr_match(address, "10.0.0.0", "255.0.0.0") || + addr_match(address, "172.16.0.0", "255.240.0.0") + ) + return true; + } + // check if we are on the local subnet + if (!CServiceBroker::GetNetwork().GetFirstConnectedInterface()) + return false; + + if (CServiceBroker::GetNetwork().HasInterfaceForIP(address)) + return true; + } + + return false; +} + +bool URIUtils::IsMultiPath(const std::string& strPath) +{ + return IsProtocol(strPath, "multipath"); +} + +bool URIUtils::IsHD(const std::string& strFileName) +{ + CURL url(strFileName); + + if (IsStack(strFileName)) + return IsHD(CStackDirectory::GetFirstStackedFile(strFileName)); + + if (IsSpecial(strFileName)) + return IsHD(CSpecialProtocol::TranslatePath(strFileName)); + + if (HasParentInHostname(url)) + return IsHD(url.GetHostName()); + + return url.GetProtocol().empty() || url.IsProtocol("file") || url.IsProtocol("win-lib"); +} + +bool URIUtils::IsDVD(const std::string& strFile) +{ + std::string strFileLow = strFile; + StringUtils::ToLower(strFileLow); + if (strFileLow.find("video_ts.ifo") != std::string::npos && IsOnDVD(strFile)) + return true; + +#if defined(TARGET_WINDOWS) + if (IsProtocol(strFile, "dvd")) + return true; + + if(strFile.size() < 2 || (strFile.substr(1) != ":\\" && strFile.substr(1) != ":")) + return false; + +#ifndef TARGET_WINDOWS_STORE + if(GetDriveType(KODI::PLATFORM::WINDOWS::ToW(strFile).c_str()) == DRIVE_CDROM) + return true; +#endif +#else + if (strFileLow == "iso9660://" || strFileLow == "udf://" || strFileLow == "dvd://1" ) + return true; +#endif + + return false; +} + +bool URIUtils::IsStack(const std::string& strFile) +{ + return IsProtocol(strFile, "stack"); +} + +bool URIUtils::IsRAR(const std::string& strFile) +{ + std::string strExtension = GetExtension(strFile); + + if (strExtension == ".001" && !StringUtils::EndsWithNoCase(strFile, ".ts.001")) + return true; + + if (StringUtils::EqualsNoCase(strExtension, ".cbr")) + return true; + + if (StringUtils::EqualsNoCase(strExtension, ".rar")) + return true; + + return false; +} + +bool URIUtils::IsInArchive(const std::string &strFile) +{ + CURL url(strFile); + + bool archiveProto = url.IsProtocol("archive") && !url.GetFileName().empty(); + return archiveProto || IsInZIP(strFile) || IsInRAR(strFile) || IsInAPK(strFile); +} + +bool URIUtils::IsInAPK(const std::string& strFile) +{ + CURL url(strFile); + + return url.IsProtocol("apk") && !url.GetFileName().empty(); +} + +bool URIUtils::IsInZIP(const std::string& strFile) +{ + CURL url(strFile); + + if (url.GetFileName().empty()) + return false; + + if (url.IsProtocol("archive")) + return IsZIP(url.GetHostName()); + + return url.IsProtocol("zip"); +} + +bool URIUtils::IsInRAR(const std::string& strFile) +{ + CURL url(strFile); + + if (url.GetFileName().empty()) + return false; + + if (url.IsProtocol("archive")) + return IsRAR(url.GetHostName()); + + return url.IsProtocol("rar"); +} + +bool URIUtils::IsAPK(const std::string& strFile) +{ + return HasExtension(strFile, ".apk"); +} + +bool URIUtils::IsZIP(const std::string& strFile) // also checks for comic books! +{ + return HasExtension(strFile, ".zip|.cbz"); +} + +bool URIUtils::IsArchive(const std::string& strFile) +{ + return HasExtension(strFile, ".zip|.rar|.apk|.cbz|.cbr"); +} + +bool URIUtils::IsSpecial(const std::string& strFile) +{ + if (IsStack(strFile)) + return IsSpecial(CStackDirectory::GetFirstStackedFile(strFile)); + + return IsProtocol(strFile, "special"); +} + +bool URIUtils::IsPlugin(const std::string& strFile) +{ + CURL url(strFile); + return url.IsProtocol("plugin"); +} + +bool URIUtils::IsScript(const std::string& strFile) +{ + CURL url(strFile); + return url.IsProtocol("script"); +} + +bool URIUtils::IsAddonsPath(const std::string& strFile) +{ + CURL url(strFile); + return url.IsProtocol("addons"); +} + +bool URIUtils::IsSourcesPath(const std::string& strPath) +{ + CURL url(strPath); + return url.IsProtocol("sources"); +} + +bool URIUtils::IsCDDA(const std::string& strFile) +{ + return IsProtocol(strFile, "cdda"); +} + +bool URIUtils::IsISO9660(const std::string& strFile) +{ + return IsProtocol(strFile, "iso9660"); +} + +bool URIUtils::IsSmb(const std::string& strFile) +{ + if (IsStack(strFile)) + return IsSmb(CStackDirectory::GetFirstStackedFile(strFile)); + + if (IsSpecial(strFile)) + return IsSmb(CSpecialProtocol::TranslatePath(strFile)); + + CURL url(strFile); + if (HasParentInHostname(url)) + return IsSmb(url.GetHostName()); + + return IsProtocol(strFile, "smb"); +} + +bool URIUtils::IsURL(const std::string& strFile) +{ + return strFile.find("://") != std::string::npos; +} + +bool URIUtils::IsFTP(const std::string& strFile) +{ + if (IsStack(strFile)) + return IsFTP(CStackDirectory::GetFirstStackedFile(strFile)); + + if (IsSpecial(strFile)) + return IsFTP(CSpecialProtocol::TranslatePath(strFile)); + + CURL url(strFile); + if (HasParentInHostname(url)) + return IsFTP(url.GetHostName()); + + return IsProtocol(strFile, "ftp") || + IsProtocol(strFile, "ftps"); +} + +bool URIUtils::IsHTTP(const std::string& strFile) +{ + if (IsStack(strFile)) + return IsHTTP(CStackDirectory::GetFirstStackedFile(strFile)); + + if (IsSpecial(strFile)) + return IsHTTP(CSpecialProtocol::TranslatePath(strFile)); + + CURL url(strFile); + if (HasParentInHostname(url)) + return IsHTTP(url.GetHostName()); + + return IsProtocol(strFile, "http") || + IsProtocol(strFile, "https"); +} + +bool URIUtils::IsUDP(const std::string& strFile) +{ + if (IsStack(strFile)) + return IsUDP(CStackDirectory::GetFirstStackedFile(strFile)); + + return IsProtocol(strFile, "udp"); +} + +bool URIUtils::IsTCP(const std::string& strFile) +{ + if (IsStack(strFile)) + return IsTCP(CStackDirectory::GetFirstStackedFile(strFile)); + + return IsProtocol(strFile, "tcp"); +} + +bool URIUtils::IsPVR(const std::string& strFile) +{ + if (IsStack(strFile)) + return IsPVR(CStackDirectory::GetFirstStackedFile(strFile)); + + return IsProtocol(strFile, "pvr"); +} + +bool URIUtils::IsPVRChannel(const std::string& strFile) +{ + if (IsStack(strFile)) + return IsPVRChannel(CStackDirectory::GetFirstStackedFile(strFile)); + + return IsProtocol(strFile, "pvr") && CPVRChannelsPath(strFile).IsChannel(); +} + +bool URIUtils::IsPVRChannelGroup(const std::string& strFile) +{ + if (IsStack(strFile)) + return IsPVRChannelGroup(CStackDirectory::GetFirstStackedFile(strFile)); + + return IsProtocol(strFile, "pvr") && CPVRChannelsPath(strFile).IsChannelGroup(); +} + +bool URIUtils::IsPVRGuideItem(const std::string& strFile) +{ + if (IsStack(strFile)) + return IsPVRGuideItem(CStackDirectory::GetFirstStackedFile(strFile)); + + return StringUtils::StartsWithNoCase(strFile, "pvr://guide"); +} + +bool URIUtils::IsDAV(const std::string& strFile) +{ + if (IsStack(strFile)) + return IsDAV(CStackDirectory::GetFirstStackedFile(strFile)); + + if (IsSpecial(strFile)) + return IsDAV(CSpecialProtocol::TranslatePath(strFile)); + + CURL url(strFile); + if (HasParentInHostname(url)) + return IsDAV(url.GetHostName()); + + return IsProtocol(strFile, "dav") || + IsProtocol(strFile, "davs"); +} + +bool URIUtils::IsInternetStream(const std::string &path, bool bStrictCheck /* = false */) +{ + const CURL pathToUrl(path); + return IsInternetStream(pathToUrl, bStrictCheck); +} + +bool URIUtils::IsInternetStream(const CURL& url, bool bStrictCheck /* = false */) +{ + if (url.GetProtocol().empty()) + return false; + + // there's nothing to stop internet streams from being stacked + if (url.IsProtocol("stack")) + return IsInternetStream(CStackDirectory::GetFirstStackedFile(url.Get())); + + // Special case these + //! @todo sftp special case has to be handled by vfs addon + if (url.IsProtocol("ftp") || url.IsProtocol("ftps") || + url.IsProtocol("dav") || url.IsProtocol("davs") || + url.IsProtocol("sftp")) + return bStrictCheck; + + std::string protocol = url.GetTranslatedProtocol(); + if (CURL::IsProtocolEqual(protocol, "http") || CURL::IsProtocolEqual(protocol, "https") || + CURL::IsProtocolEqual(protocol, "tcp") || CURL::IsProtocolEqual(protocol, "udp") || + CURL::IsProtocolEqual(protocol, "rtp") || CURL::IsProtocolEqual(protocol, "sdp") || + CURL::IsProtocolEqual(protocol, "mms") || CURL::IsProtocolEqual(protocol, "mmst") || + CURL::IsProtocolEqual(protocol, "mmsh") || CURL::IsProtocolEqual(protocol, "rtsp") || + CURL::IsProtocolEqual(protocol, "rtmp") || CURL::IsProtocolEqual(protocol, "rtmpt") || + CURL::IsProtocolEqual(protocol, "rtmpe") || CURL::IsProtocolEqual(protocol, "rtmpte") || + CURL::IsProtocolEqual(protocol, "rtmps")) + return true; + + return false; +} + +bool URIUtils::IsUPnP(const std::string& strFile) +{ + return IsProtocol(strFile, "upnp"); +} + +bool URIUtils::IsLiveTV(const std::string& strFile) +{ + std::string strFileWithoutSlash(strFile); + RemoveSlashAtEnd(strFileWithoutSlash); + + if (StringUtils::EndsWithNoCase(strFileWithoutSlash, ".pvr") && + !StringUtils::StartsWith(strFileWithoutSlash, "pvr://recordings")) + return true; + + return false; +} + +bool URIUtils::IsPVRRecording(const std::string& strFile) +{ + std::string strFileWithoutSlash(strFile); + RemoveSlashAtEnd(strFileWithoutSlash); + + return StringUtils::EndsWithNoCase(strFileWithoutSlash, ".pvr") && + StringUtils::StartsWith(strFile, "pvr://recordings"); +} + +bool URIUtils::IsPVRRecordingFileOrFolder(const std::string& strFile) +{ + return StringUtils::StartsWith(strFile, "pvr://recordings"); +} + +bool URIUtils::IsMusicDb(const std::string& strFile) +{ + return IsProtocol(strFile, "musicdb"); +} + +bool URIUtils::IsNfs(const std::string& strFile) +{ + if (IsStack(strFile)) + return IsNfs(CStackDirectory::GetFirstStackedFile(strFile)); + + if (IsSpecial(strFile)) + return IsNfs(CSpecialProtocol::TranslatePath(strFile)); + + CURL url(strFile); + if (HasParentInHostname(url)) + return IsNfs(url.GetHostName()); + + return IsProtocol(strFile, "nfs"); +} + +bool URIUtils::IsVideoDb(const std::string& strFile) +{ + return IsProtocol(strFile, "videodb"); +} + +bool URIUtils::IsBluray(const std::string& strFile) +{ + return IsProtocol(strFile, "bluray"); +} + +bool URIUtils::IsAndroidApp(const std::string &path) +{ + return IsProtocol(path, "androidapp"); +} + +bool URIUtils::IsLibraryFolder(const std::string& strFile) +{ + CURL url(strFile); + return url.IsProtocol("library"); +} + +bool URIUtils::IsLibraryContent(const std::string &strFile) +{ + return (IsProtocol(strFile, "library") || + IsProtocol(strFile, "videodb") || + IsProtocol(strFile, "musicdb") || + StringUtils::EndsWith(strFile, ".xsp")); +} + +bool URIUtils::IsDOSPath(const std::string &path) +{ + if (path.size() > 1 && path[1] == ':' && isalpha(path[0])) + return true; + + // windows network drives + if (path.size() > 1 && path[0] == '\\' && path[1] == '\\') + return true; + + return false; +} + +std::string URIUtils::AppendSlash(std::string strFolder) +{ + AddSlashAtEnd(strFolder); + return strFolder; +} + +void URIUtils::AddSlashAtEnd(std::string& strFolder) +{ + if (IsURL(strFolder)) + { + CURL url(strFolder); + std::string file = url.GetFileName(); + if(!file.empty() && file != strFolder) + { + AddSlashAtEnd(file); + url.SetFileName(file); + strFolder = url.Get(); + } + return; + } + + if (!HasSlashAtEnd(strFolder)) + { + if (IsDOSPath(strFolder)) + strFolder += '\\'; + else + strFolder += '/'; + } +} + +bool URIUtils::HasSlashAtEnd(const std::string& strFile, bool checkURL /* = false */) +{ + if (strFile.empty()) return false; + if (checkURL && IsURL(strFile)) + { + CURL url(strFile); + std::string file = url.GetFileName(); + return file.empty() || HasSlashAtEnd(file, false); + } + char kar = strFile.c_str()[strFile.size() - 1]; + + if (kar == '/' || kar == '\\') + return true; + + return false; +} + +void URIUtils::RemoveSlashAtEnd(std::string& strFolder) +{ + // performance optimization. pvr guide items are mass objects, uri never has a slash at end, and this method is quite expensive... + if (IsPVRGuideItem(strFolder)) + return; + + if (IsURL(strFolder)) + { + CURL url(strFolder); + std::string file = url.GetFileName(); + if (!file.empty() && file != strFolder) + { + RemoveSlashAtEnd(file); + url.SetFileName(file); + strFolder = url.Get(); + return; + } + if(url.GetHostName().empty()) + return; + } + + while (HasSlashAtEnd(strFolder)) + strFolder.erase(strFolder.size()-1, 1); +} + +bool URIUtils::CompareWithoutSlashAtEnd(const std::string& strPath1, const std::string& strPath2) +{ + std::string strc1 = strPath1, strc2 = strPath2; + RemoveSlashAtEnd(strc1); + RemoveSlashAtEnd(strc2); + return StringUtils::EqualsNoCase(strc1, strc2); +} + + +std::string URIUtils::FixSlashesAndDups(const std::string& path, const char slashCharacter /* = '/' */, const size_t startFrom /*= 0*/) +{ + const size_t len = path.length(); + if (startFrom >= len) + return path; + + std::string result(path, 0, startFrom); + result.reserve(len); + + const char* const str = path.c_str(); + size_t pos = startFrom; + do + { + if (str[pos] == '\\' || str[pos] == '/') + { + result.push_back(slashCharacter); // append one slash + pos++; + // skip any following slashes + while (str[pos] == '\\' || str[pos] == '/') // str is null-terminated, no need to check for buffer overrun + pos++; + } + else + result.push_back(str[pos++]); // append current char and advance pos to next char + + } while (pos < len); + + return result; +} + + +std::string URIUtils::CanonicalizePath(const std::string& path, const char slashCharacter /*= '\\'*/) +{ + assert(slashCharacter == '\\' || slashCharacter == '/'); + + if (path.empty()) + return path; + + const std::string slashStr(1, slashCharacter); + std::vector pathVec, resultVec; + StringUtils::Tokenize(path, pathVec, slashStr); + + for (std::vector::const_iterator it = pathVec.begin(); it != pathVec.end(); ++it) + { + if (*it == ".") + { /* skip - do nothing */ } + else if (*it == ".." && !resultVec.empty() && resultVec.back() != "..") + resultVec.pop_back(); + else + resultVec.push_back(*it); + } + + std::string result; + if (path[0] == slashCharacter) + result.push_back(slashCharacter); // add slash at the begin + + result += StringUtils::Join(resultVec, slashStr); + + if (path[path.length() - 1] == slashCharacter && !result.empty() && result[result.length() - 1] != slashCharacter) + result.push_back(slashCharacter); // add slash at the end if result isn't empty and result isn't "/" + + return result; +} + +std::string URIUtils::AddFileToFolder(const std::string& strFolder, + const std::string& strFile) +{ + if (IsURL(strFolder)) + { + CURL url(strFolder); + if (url.GetFileName() != strFolder) + { + url.SetFileName(AddFileToFolder(url.GetFileName(), strFile)); + return url.Get(); + } + } + + std::string strResult = strFolder; + if (!strResult.empty()) + AddSlashAtEnd(strResult); + + // Remove any slash at the start of the file + if (strFile.size() && (strFile[0] == '/' || strFile[0] == '\\')) + strResult += strFile.substr(1); + else + strResult += strFile; + + // correct any slash directions + if (!IsDOSPath(strFolder)) + StringUtils::Replace(strResult, '\\', '/'); + else + StringUtils::Replace(strResult, '/', '\\'); + + return strResult; +} + +std::string URIUtils::GetDirectory(const std::string &strFilePath) +{ + // Will from a full filename return the directory the file resides in. + // Keeps the final slash at end and possible |option=foo options. + + size_t iPosSlash = strFilePath.find_last_of("/\\"); + if (iPosSlash == std::string::npos) + return ""; // No slash, so no path (ignore any options) + + size_t iPosBar = strFilePath.rfind('|'); + if (iPosBar == std::string::npos) + return strFilePath.substr(0, iPosSlash + 1); // Only path + + return strFilePath.substr(0, iPosSlash + 1) + strFilePath.substr(iPosBar); // Path + options +} + +CURL URIUtils::CreateArchivePath(const std::string& type, + const CURL& archiveUrl, + const std::string& pathInArchive, + const std::string& password) +{ + CURL url; + url.SetProtocol(type); + if (!password.empty()) + url.SetUserName(password); + url.SetHostName(archiveUrl.Get()); + + /* NOTE: on posix systems, the replacement of \ with / is incorrect. + Ideally this would not be done. We need to check that the ZipManager + code (and elsewhere) doesn't pass in non-posix paths. + */ + std::string strBuffer(pathInArchive); + StringUtils::Replace(strBuffer, '\\', '/'); + StringUtils::TrimLeft(strBuffer, "/"); + url.SetFileName(strBuffer); + + return url; +} + +std::string URIUtils::GetRealPath(const std::string &path) +{ + if (path.empty()) + return path; + + CURL url(path); + url.SetHostName(GetRealPath(url.GetHostName())); + url.SetFileName(resolvePath(url.GetFileName())); + + return url.Get(); +} + +std::string URIUtils::resolvePath(const std::string &path) +{ + if (path.empty()) + return path; + + size_t posSlash = path.find('/'); + size_t posBackslash = path.find('\\'); + std::string delim = posSlash < posBackslash ? "/" : "\\"; + std::vector parts = StringUtils::Split(path, delim); + std::vector realParts; + + for (std::vector::const_iterator part = parts.begin(); part != parts.end(); ++part) + { + if (part->empty() || part->compare(".") == 0) + continue; + + // go one level back up + if (part->compare("..") == 0) + { + if (!realParts.empty()) + realParts.pop_back(); + continue; + } + + realParts.push_back(*part); + } + + std::string realPath; + // re-add any / or \ at the beginning + for (std::string::const_iterator itPath = path.begin(); itPath != path.end(); ++itPath) + { + if (*itPath != delim.at(0)) + break; + + realPath += delim; + } + // put together the path + realPath += StringUtils::Join(realParts, delim); + // re-add any / or \ at the end + if (path.at(path.size() - 1) == delim.at(0) && + realPath.size() > 0 && realPath.at(realPath.size() - 1) != delim.at(0)) + realPath += delim; + + return realPath; +} + +bool URIUtils::UpdateUrlEncoding(std::string &strFilename) +{ + if (strFilename.empty()) + return false; + + CURL url(strFilename); + // if this is a stack:// URL we need to work with its filename + if (URIUtils::IsStack(strFilename)) + { + std::vector files; + if (!CStackDirectory::GetPaths(strFilename, files)) + return false; + + for (std::vector::iterator file = files.begin(); file != files.end(); ++file) + UpdateUrlEncoding(*file); + + std::string stackPath; + if (!CStackDirectory::ConstructStackPath(files, stackPath)) + return false; + + url.Parse(stackPath); + } + // if the protocol has an encoded hostname we need to work with its hostname + else if (URIUtils::HasEncodedHostname(url)) + { + std::string hostname = url.GetHostName(); + UpdateUrlEncoding(hostname); + url.SetHostName(hostname); + } + else + return false; + + std::string newFilename = url.Get(); + if (newFilename == strFilename) + return false; + + strFilename = newFilename; + return true; +} diff --git a/xbmc/utils/URIUtils.h b/xbmc/utils/URIUtils.h new file mode 100644 index 0000000..31db0ec --- /dev/null +++ b/xbmc/utils/URIUtils.h @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include + +class CURL; +class CAdvancedSettings; + +class URIUtils +{ +public: + static void RegisterAdvancedSettings(const CAdvancedSettings& advancedSettings); + static void UnregisterAdvancedSettings(); + + static std::string GetDirectory(const std::string &strFilePath); + + static std::string GetFileName(const CURL& url); + static std::string GetFileName(const std::string& strFileNameAndPath); + + static std::string GetExtension(const CURL& url); + static std::string GetExtension(const std::string& strFileName); + + /*! + \brief Check if there is a file extension + \param strFileName Path or URL to check + \return \e true if strFileName have an extension. + \note Returns false when strFileName is empty. + \sa GetExtension + */ + static bool HasExtension(const std::string& strFileName); + + /*! + \brief Check if filename have any of the listed extensions + \param strFileName Path or URL to check + \param strExtensions List of '.' prefixed lowercase extensions separated with '|' + \return \e true if strFileName have any one of the extensions. + \note The check is case insensitive for strFileName, but requires + strExtensions to be lowercase. Returns false when strFileName or + strExtensions is empty. + \sa GetExtension + */ + static bool HasExtension(const std::string& strFileName, const std::string& strExtensions); + static bool HasExtension(const CURL& url, const std::string& strExtensions); + + static void RemoveExtension(std::string& strFileName); + static std::string ReplaceExtension(const std::string& strFile, + const std::string& strNewExtension); + static void Split(const std::string& strFileNameAndPath, + std::string& strPath, std::string& strFileName); + static std::vector SplitPath(const std::string& strPath); + + static void GetCommonPath(std::string& strPath, const std::string& strPath2); + static std::string GetParentPath(const std::string& strPath); + static bool GetParentPath(const std::string& strPath, std::string& strParent); + + /*! \brief Retrieve the base path, accounting for stacks and files in rars. + \param strPath path. + \return the folder that contains the item. + */ + static std::string GetBasePath(const std::string& strPath); + + /* \brief Change the base path of a URL: fromPath/fromFile -> toPath/toFile + Handles changes in path separator and filename URL encoding if necessary to derive toFile. + \param fromPath the base path of the original URL + \param fromFile the filename portion of the original URL + \param toPath the base path of the resulting URL + \return the full path. + */ + static std::string ChangeBasePath(const std::string &fromPath, const std::string &fromFile, const std::string &toPath, const bool &bAddPath = true); + + static CURL SubstitutePath(const CURL& url, bool reverse = false); + static std::string SubstitutePath(const std::string& strPath, bool reverse = false); + + /*! \brief Check whether a URL is a given URL scheme. + Comparison is case-insensitive as per RFC1738 + \param url a std::string path. + \param type a lower-case scheme name, e.g. "smb". + \return true if the url is of the given scheme, false otherwise. + \sa PathHasParent, PathEquals + */ + static bool IsProtocol(const std::string& url, const std::string& type); + + /*! \brief Check whether a path has a given parent. + Comparison is case-sensitive. + Use IsProtocol() to compare the protocol portion only. + \param path a std::string path. + \param parent the string the parent of the path should be compared against. + \param translate whether to translate any special paths into real paths + \return true if the path has the given parent string, false otherwise. + \sa IsProtocol, PathEquals + */ + static bool PathHasParent(std::string path, std::string parent, bool translate = false); + + /*! \brief Check whether a path equals another path. + Comparison is case-sensitive. + \param path1 a std::string path. + \param path2 the second path the path should be compared against. + \param ignoreTrailingSlash ignore any trailing slashes in both paths + \return true if the paths are equal, false otherwise. + \sa IsProtocol, PathHasParent + */ + static bool PathEquals(std::string path1, std::string path2, bool ignoreTrailingSlash = false, bool ignoreURLOptions = false); + + static bool IsAddonsPath(const std::string& strFile); + static bool IsSourcesPath(const std::string& strFile); + static bool IsCDDA(const std::string& strFile); + static bool IsDAV(const std::string& strFile); + static bool IsDOSPath(const std::string &path); + static bool IsDVD(const std::string& strFile); + static bool IsFTP(const std::string& strFile); + static bool IsHTTP(const std::string& strFile); + static bool IsUDP(const std::string& strFile); + static bool IsTCP(const std::string& strFile); + static bool IsHD(const std::string& strFileName); + static bool IsInArchive(const std::string& strFile); + static bool IsInRAR(const std::string& strFile); + static bool IsInternetStream(const std::string& path, bool bStrictCheck = false); + static bool IsInternetStream(const CURL& url, bool bStrictCheck = false); + static bool IsInAPK(const std::string& strFile); + static bool IsInZIP(const std::string& strFile); + static bool IsISO9660(const std::string& strFile); + static bool IsLiveTV(const std::string& strFile); + static bool IsPVRRecording(const std::string& strFile); + static bool IsPVRRecordingFileOrFolder(const std::string& strFile); + static bool IsMultiPath(const std::string& strPath); + static bool IsMusicDb(const std::string& strFile); + static bool IsNfs(const std::string& strFile); + static bool IsOnDVD(const std::string& strFile); + static bool IsOnLAN(const std::string& strFile); + static bool IsHostOnLAN(const std::string& hostName, bool offLineCheck = false); + static bool IsPlugin(const std::string& strFile); + static bool IsScript(const std::string& strFile); + static bool IsRAR(const std::string& strFile); + static bool IsRemote(const std::string& strFile); + static bool IsSmb(const std::string& strFile); + static bool IsSpecial(const std::string& strFile); + static bool IsStack(const std::string& strFile); + static bool IsUPnP(const std::string& strFile); + static bool IsURL(const std::string& strFile); + static bool IsVideoDb(const std::string& strFile); + static bool IsAPK(const std::string& strFile); + static bool IsZIP(const std::string& strFile); + static bool IsArchive(const std::string& strFile); + static bool IsBluray(const std::string& strFile); + static bool IsAndroidApp(const std::string& strFile); + static bool IsLibraryFolder(const std::string& strFile); + static bool IsLibraryContent(const std::string& strFile); + static bool IsPVR(const std::string& strFile); + static bool IsPVRChannel(const std::string& strFile); + static bool IsPVRChannelGroup(const std::string& strFile); + static bool IsPVRGuideItem(const std::string& strFile); + + static std::string AppendSlash(std::string strFolder); + static void AddSlashAtEnd(std::string& strFolder); + static bool HasSlashAtEnd(const std::string& strFile, bool checkURL = false); + static void RemoveSlashAtEnd(std::string& strFolder); + static bool CompareWithoutSlashAtEnd(const std::string& strPath1, const std::string& strPath2); + static std::string FixSlashesAndDups(const std::string& path, const char slashCharacter = '/', const size_t startFrom = 0); + /** + * Convert path to form without duplicated slashes and without relative directories + * Strip duplicated slashes + * Resolve and remove relative directories ("/../" and "/./") + * Will ignore slashes with other direction than specified + * Will not resolve path starting from relative directory + * @warning Don't use with "protocol://path"-style URLs + * @param path string to process + * @param slashCharacter character to use as directory delimiter + * @return transformed path + */ + static std::string CanonicalizePath(const std::string& path, const char slashCharacter = '\\'); + + static CURL CreateArchivePath(const std::string& type, + const CURL& archiveUrl, + const std::string& pathInArchive = "", + const std::string& password = ""); + + static std::string AddFileToFolder(const std::string& strFolder, const std::string& strFile); + template + static std::string AddFileToFolder(const std::string& strFolder, const std::string& strFile, T... args) + { + auto newPath = AddFileToFolder(strFolder, strFile); + return AddFileToFolder(newPath, args...); + } + + static bool HasParentInHostname(const CURL& url); + static bool HasEncodedHostname(const CURL& url); + static bool HasEncodedFilename(const CURL& url); + + /*! + \brief Cleans up the given path by resolving "." and ".." + and returns it. + + This methods goes through the given path and removes any "." + (as it states "this directory") and resolves any ".." by + removing the previous directory from the path. This is done + for file paths and host names (in case of VFS paths). + + \param path Path to be cleaned up + \return Actual path without any "." or ".." + */ + static std::string GetRealPath(const std::string &path); + + /*! + \brief Updates the URL encoded hostname of the given path + + This method must only be used to update paths encoded with + the old (Eden) URL encoding implementation to the new (Frodo) + URL encoding implementation (which does not URL encode -_.!(). + + \param strFilename Path to update + \return True if the path has been updated/changed otherwise false + */ + static bool UpdateUrlEncoding(std::string &strFilename); + +private: + static std::string resolvePath(const std::string &path); + + static const CAdvancedSettings* m_advancedSettings; +}; + diff --git a/xbmc/utils/UrlOptions.cpp b/xbmc/utils/UrlOptions.cpp new file mode 100644 index 0000000..2aa304b --- /dev/null +++ b/xbmc/utils/UrlOptions.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "UrlOptions.h" + +#include "URL.h" +#include "utils/StringUtils.h" +#include "utils/log.h" + +CUrlOptions::CUrlOptions() = default; + +CUrlOptions::CUrlOptions(const std::string &options, const char *strLead /* = "" */) + : m_strLead(strLead) +{ + AddOptions(options); +} + +CUrlOptions::~CUrlOptions() = default; + +std::string CUrlOptions::GetOptionsString(bool withLeadingSeparator /* = false */) const +{ + std::string options; + for (const auto &opt : m_options) + { + if (!options.empty()) + options += "&"; + + options += CURL::Encode(opt.first); + if (!opt.second.empty()) + options += "=" + CURL::Encode(opt.second.asString()); + } + + if (withLeadingSeparator && !options.empty()) + { + if (m_strLead.empty()) + options = "?" + options; + else + options = m_strLead + options; + } + + return options; +} + +void CUrlOptions::AddOption(const std::string &key, const char *value) +{ + if (key.empty() || value == NULL) + return; + + return AddOption(key, std::string(value)); +} + +void CUrlOptions::AddOption(const std::string &key, const std::string &value) +{ + if (key.empty()) + return; + + m_options[key] = value; +} + +void CUrlOptions::AddOption(const std::string &key, int value) +{ + if (key.empty()) + return; + + m_options[key] = value; +} + +void CUrlOptions::AddOption(const std::string &key, float value) +{ + if (key.empty()) + return; + + m_options[key] = value; +} + +void CUrlOptions::AddOption(const std::string &key, double value) +{ + if (key.empty()) + return; + + m_options[key] = value; +} + +void CUrlOptions::AddOption(const std::string &key, bool value) +{ + if (key.empty()) + return; + + m_options[key] = value; +} + +void CUrlOptions::AddOptions(const std::string &options) +{ + if (options.empty()) + return; + + std::string strOptions = options; + + // if matching the preset leading str, remove from options. + if (!m_strLead.empty() && strOptions.compare(0, m_strLead.length(), m_strLead) == 0) + strOptions.erase(0, m_strLead.length()); + else if (strOptions.at(0) == '?' || strOptions.at(0) == '#' || strOptions.at(0) == ';' || strOptions.at(0) == '|') + { + // remove leading ?, #, ; or | if present + if (!m_strLead.empty()) + CLog::Log(LOGWARNING, "%s: original leading str %s overridden by %c", __FUNCTION__, m_strLead.c_str(), strOptions.at(0)); + m_strLead = strOptions.at(0); + strOptions.erase(0, 1); + } + + // split the options by & and process them one by one + for (const auto &option : StringUtils::Split(strOptions, "&")) + { + if (option.empty()) + continue; + + std::string key, value; + + size_t pos = option.find('='); + key = CURL::Decode(option.substr(0, pos)); + if (pos != std::string::npos) + value = CURL::Decode(option.substr(pos + 1)); + + // the key cannot be empty + if (!key.empty()) + AddOption(key, value); + } +} + +void CUrlOptions::AddOptions(const CUrlOptions &options) +{ + m_options.insert(options.m_options.begin(), options.m_options.end()); +} + +void CUrlOptions::RemoveOption(const std::string &key) +{ + if (key.empty()) + return; + + auto option = m_options.find(key); + if (option != m_options.end()) + m_options.erase(option); +} + +bool CUrlOptions::HasOption(const std::string &key) const +{ + if (key.empty()) + return false; + + return m_options.find(key) != m_options.end(); +} + +bool CUrlOptions::GetOption(const std::string &key, CVariant &value) const +{ + if (key.empty()) + return false; + + auto option = m_options.find(key); + if (option == m_options.end()) + return false; + + value = option->second; + return true; +} diff --git a/xbmc/utils/UrlOptions.h b/xbmc/utils/UrlOptions.h new file mode 100644 index 0000000..1fa7ac6 --- /dev/null +++ b/xbmc/utils/UrlOptions.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/Variant.h" + +#include +#include + +class CUrlOptions +{ +public: + typedef std::map UrlOptions; + + CUrlOptions(); + CUrlOptions(const std::string &options, const char *strLead = ""); + virtual ~CUrlOptions(); + + void Clear() { m_options.clear(); m_strLead.clear(); } + + const UrlOptions& GetOptions() const { return m_options; } + std::string GetOptionsString(bool withLeadingSeparator = false) const; + + virtual void AddOption(const std::string &key, const char *value); + virtual void AddOption(const std::string &key, const std::string &value); + virtual void AddOption(const std::string &key, int value); + virtual void AddOption(const std::string &key, float value); + virtual void AddOption(const std::string &key, double value); + virtual void AddOption(const std::string &key, bool value); + virtual void AddOptions(const std::string &options); + virtual void AddOptions(const CUrlOptions &options); + virtual void RemoveOption(const std::string &key); + + bool HasOption(const std::string &key) const; + bool GetOption(const std::string &key, CVariant &value) const; + +protected: + UrlOptions m_options; + std::string m_strLead; +}; diff --git a/xbmc/utils/Utf8Utils.cpp b/xbmc/utils/Utf8Utils.cpp new file mode 100644 index 0000000..a45002a --- /dev/null +++ b/xbmc/utils/Utf8Utils.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2013-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Utf8Utils.h" + + +CUtf8Utils::utf8CheckResult CUtf8Utils::checkStrForUtf8(const std::string& str) +{ + const char* const strC = str.c_str(); + const size_t len = str.length(); + size_t pos = 0; + bool isPlainAscii = true; + + while (pos < len) + { + const size_t chrLen = SizeOfUtf8Char(strC + pos); + if (chrLen == 0) + return hiAscii; // non valid UTF-8 sequence + else if (chrLen > 1) + isPlainAscii = false; + + pos += chrLen; + } + + if (isPlainAscii) + return plainAscii; // only single-byte characters (valid for US-ASCII and for UTF-8) + + return utf8string; // valid UTF-8 with at least one valid UTF-8 multi-byte sequence +} + + + +size_t CUtf8Utils::FindValidUtf8Char(const std::string& str, const size_t startPos /*= 0*/) +{ + const char* strC = str.c_str(); + const size_t len = str.length(); + + size_t pos = startPos; + while (pos < len) + { + if (SizeOfUtf8Char(strC + pos)) + return pos; + + pos++; + } + + return std::string::npos; +} + +size_t CUtf8Utils::RFindValidUtf8Char(const std::string& str, const size_t startPos) +{ + const size_t len = str.length(); + if (!len) + return std::string::npos; + + const char* strC = str.c_str(); + size_t pos = (startPos >= len) ? len - 1 : startPos; + while (pos < len) // pos is unsigned, after zero pos becomes large then len + { + if (SizeOfUtf8Char(strC + pos)) + return pos; + + pos--; + } + + return std::string::npos; +} + +inline size_t CUtf8Utils::SizeOfUtf8Char(const std::string& str, const size_t charStart /*= 0*/) +{ + if (charStart >= str.length()) + return std::string::npos; + + return SizeOfUtf8Char(str.c_str() + charStart); +} + +// must be used only internally in class! +// str must be null-terminated +inline size_t CUtf8Utils::SizeOfUtf8Char(const char* const str) +{ + if (!str) + return 0; + + const unsigned char* const strU = (const unsigned char*)str; + const unsigned char chr = strU[0]; + + /* this is an implementation of http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf#G27506 */ + + /* U+0000 - U+007F in UTF-8 */ + if (chr <= 0x7F) + return 1; + + /* U+0080 - U+07FF in UTF-8 */ /* binary representation and range */ + if (chr >= 0xC2 && chr <= 0xDF /* C2=1100 0010 - DF=1101 1111 */ + // as str is null terminated, + && ((strU[1] & 0xC0) == 0x80)) /* C0=1100 0000, 80=1000 0000 - BF=1011 1111 */ + return 2; // valid UTF-8 2 bytes sequence + + /* U+0800 - U+0FFF in UTF-8 */ + if (chr == 0xE0 /* E0=1110 0000 */ + && (strU[1] & 0xE0) == 0xA0 /* E0=1110 0000, A0=1010 0000 - BF=1011 1111 */ + && (strU[2] & 0xC0) == 0x80) /* C0=1100 0000, 80=1000 0000 - BF=1011 1111 */ + return 3; // valid UTF-8 3 bytes sequence + + /* U+1000 - U+CFFF in UTF-8 */ + /* skip U+D000 - U+DFFF (handled later) */ + /* U+E000 - U+FFFF in UTF-8 */ + if (((chr >= 0xE1 && chr <= 0xEC) /* E1=1110 0001 - EC=1110 1100 */ + || chr == 0xEE || chr == 0xEF) /* EE=1110 1110 - EF=1110 1111 */ + && (strU[1] & 0xC0) == 0x80 /* C0=1100 0000, 80=1000 0000 - BF=1011 1111 */ + && (strU[2] & 0xC0) == 0x80) /* C0=1100 0000, 80=1000 0000 - BF=1011 1111 */ + return 3; // valid UTF-8 3 bytes sequence + + /* U+D000 - U+D7FF in UTF-8 */ + /* note: range U+D800 - U+DFFF is reserved and invalid */ + if (chr == 0xED /* ED=1110 1101 */ + && (strU[1] & 0xE0) == 0x80 /* E0=1110 0000, 80=1000 0000 - 9F=1001 1111 */ + && (strU[2] & 0xC0) == 0x80) /* C0=1100 0000, 80=1000 0000 - BF=1011 1111 */ + return 3; // valid UTF-8 3 bytes sequence + + /* U+10000 - U+3FFFF in UTF-8 */ + if (chr == 0xF0 /* F0=1111 0000 */ + && (strU[1] & 0xE0) == 0x80 /* E0=1110 0000, 80=1000 0000 - 9F=1001 1111 */ + && strU[2] >= 0x90 && strU[2] <= 0xBF /* 90=1001 0000 - BF=1011 1111 */ + && (strU[3] & 0xC0) == 0x80) /* C0=1100 0000, 80=1000 0000 - BF=1011 1111 */ + return 4; // valid UTF-8 4 bytes sequence + + /* U+40000 - U+FFFFF in UTF-8 */ + if (chr >= 0xF1 && chr <= 0xF3 /* F1=1111 0001 - F3=1111 0011 */ + && (strU[1] & 0xC0) == 0x80 /* C0=1100 0000, 80=1000 0000 - BF=1011 1111 */ + && (strU[2] & 0xC0) == 0x80 /* C0=1100 0000, 80=1000 0000 - BF=1011 1111 */ + && (strU[3] & 0xC0) == 0x80) /* C0=1100 0000, 80=1000 0000 - BF=1011 1111 */ + return 4; // valid UTF-8 4 bytes sequence + + /* U+100000 - U+10FFFF in UTF-8 */ + if (chr == 0xF4 /* F4=1111 0100 */ + && (strU[1] & 0xF0) == 0x80 /* F0=1111 0000, 80=1000 0000 - 8F=1000 1111 */ + && (strU[2] & 0xC0) == 0x80 /* C0=1100 0000, 80=1000 0000 - BF=1011 1111 */ + && (strU[3] & 0xC0) == 0x80) /* C0=1100 0000, 80=1000 0000 - BF=1011 1111 */ + return 4; // valid UTF-8 4 bytes sequence + + return 0; // invalid UTF-8 char sequence +} diff --git a/xbmc/utils/Utf8Utils.h b/xbmc/utils/Utf8Utils.h new file mode 100644 index 0000000..a29f64a --- /dev/null +++ b/xbmc/utils/Utf8Utils.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +class CUtf8Utils +{ +public: + enum utf8CheckResult + { + plainAscii = -1, // only US-ASCII characters (valid for UTF-8 too) + hiAscii = 0, // non-UTF-8 sequence with high ASCII characters + // (possible single-byte national encoding like WINDOWS-1251, multi-byte encoding like UTF-32 or invalid UTF-8) + utf8string = 1 // valid UTF-8 sequences, but not US-ASCII only + }; + + /** + * Check given string for valid UTF-8 sequences + * @param str string to check + * @return result of check, "plainAscii" for empty string + */ + static utf8CheckResult checkStrForUtf8(const std::string& str); + + static inline bool isValidUtf8(const std::string& str) + { + return checkStrForUtf8(str) != hiAscii; + } + + static size_t FindValidUtf8Char(const std::string& str, const size_t startPos = 0); + static size_t RFindValidUtf8Char(const std::string& str, const size_t startPos); + + static size_t SizeOfUtf8Char(const std::string& str, const size_t charStart = 0); +private: + static size_t SizeOfUtf8Char(const char* const str); +}; diff --git a/xbmc/utils/VC1BitstreamParser.cpp b/xbmc/utils/VC1BitstreamParser.cpp new file mode 100644 index 0000000..8ac1b6e --- /dev/null +++ b/xbmc/utils/VC1BitstreamParser.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "VC1BitstreamParser.h" + +#include "BitstreamReader.h" + +enum +{ + VC1_PROFILE_SIMPLE, + VC1_PROFILE_MAIN, + VC1_PROFILE_RESERVED, + VC1_PROFILE_ADVANCED, + VC1_PROFILE_NOPROFILE +}; + +enum +{ + VC1_END_OF_SEQ = 0x0A, + VC1_SLICE = 0x0B, + VC1_FIELD = 0x0C, + VC1_FRAME = 0x0D, + VC1_ENTRYPOINT = 0x0E, + VC1_SEQUENCE = 0x0F, + VC1_SLICE_USER = 0x1B, + VC1_FIELD_USER = 0x1C, + VC1_FRAME_USER = 0x1D, + VC1_ENTRY_POINT_USER = 0x1E, + VC1_SEQUENCE_USER = 0x1F +}; + +enum +{ + VC1_FRAME_PROGRESSIVE = 0x0, + VC1_FRAME_INTERLACE = 0x10, + VC1_FIELD_INTERLACE = 0x11 +}; + +CVC1BitstreamParser::CVC1BitstreamParser() +{ + Reset(); +} + +void CVC1BitstreamParser::Reset() +{ + m_Profile = VC1_PROFILE_NOPROFILE; +} + +bool CVC1BitstreamParser::IsRecoveryPoint(const uint8_t *buf, int buf_size) +{ + return vc1_parse_frame(buf, buf + buf_size, true); +}; + +bool CVC1BitstreamParser::IsIFrame(const uint8_t *buf, int buf_size) +{ + return vc1_parse_frame(buf, buf + buf_size, false); +}; + +bool CVC1BitstreamParser::vc1_parse_frame(const uint8_t *buf, const uint8_t *buf_end, bool sequence_only) +{ + uint32_t state = -1; + for (;;) + { + buf = find_start_code(buf, buf_end, &state); + if (buf >= buf_end) + break; + if (buf[-1] == VC1_SEQUENCE) + { + if (m_Profile != VC1_PROFILE_NOPROFILE) + return false; + CBitstreamReader br(buf, buf_end - buf); + // Read the profile + m_Profile = static_cast(br.ReadBits(2)); + if (m_Profile == VC1_PROFILE_ADVANCED) + { + br.SkipBits(39); + m_AdvInterlace = br.ReadBits(1); + } + else + { + br.SkipBits(22); + + m_SimpleSkipBits = 2; + if (br.ReadBits(1)) //rangered + ++m_SimpleSkipBits; + + m_MaxBFrames = br.ReadBits(3); + + br.SkipBits(2); // quantizer + if (br.ReadBits(1)) //finterpflag + ++m_SimpleSkipBits; + } + if (sequence_only) + return true; + } + else if (buf[-1] == VC1_FRAME) + { + CBitstreamReader br(buf, buf_end - buf); + + if (sequence_only) + return false; + if (m_Profile == VC1_PROFILE_ADVANCED) + { + uint8_t fcm; + if (m_AdvInterlace) { + fcm = br.ReadBits(1); + if (fcm) + fcm = br.ReadBits(1) + 1; + } + else + fcm = VC1_FRAME_PROGRESSIVE; + if (fcm == VC1_FIELD_INTERLACE) { + uint8_t pic = br.ReadBits(3); + return pic == 0x00 || pic == 0x01; + } + else + { + uint8_t pic(0); + while (pic < 4 && br.ReadBits(1))++pic; + return pic == 2; + } + return false; + } + else if (m_Profile != VC1_PROFILE_NOPROFILE) + { + br.SkipBits(m_SimpleSkipBits); // quantizer + uint8_t pic(br.ReadBits(1)); + if (m_MaxBFrames) { + if (!pic) { + pic = br.ReadBits(1); + return pic != 0; + } + else + return false; + } + else + return pic != 0; + } + else + break; + } + } + return false; +} diff --git a/xbmc/utils/VC1BitstreamParser.h b/xbmc/utils/VC1BitstreamParser.h new file mode 100644 index 0000000..882160c --- /dev/null +++ b/xbmc/utils/VC1BitstreamParser.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +class CVC1BitstreamParser +{ +public: + CVC1BitstreamParser(); + ~CVC1BitstreamParser() = default; + + void Reset(); + + inline bool IsRecoveryPoint(const uint8_t *buf, int buf_size); + inline bool IsIFrame(const uint8_t *buf, int buf_size); + +protected: + bool vc1_parse_frame(const uint8_t *buf, const uint8_t *buf_end, bool sequenceOnly); +private: + uint8_t m_Profile; + uint8_t m_MaxBFrames; + uint8_t m_SimpleSkipBits; + uint8_t m_AdvInterlace; +}; diff --git a/xbmc/utils/Variant.cpp b/xbmc/utils/Variant.cpp new file mode 100644 index 0000000..97676f6 --- /dev/null +++ b/xbmc/utils/Variant.cpp @@ -0,0 +1,885 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Variant.h" + +#include +#include +#include + +#ifndef strtoll +#ifdef TARGET_WINDOWS +#define strtoll _strtoi64 +#define strtoull _strtoui64 +#define wcstoll _wcstoi64 +#define wcstoull _wcstoui64 +#else // TARGET_WINDOWS +#if !defined(TARGET_DARWIN) +#define strtoll(str, endptr, base) (int64_t)strtod(str, endptr) +#define strtoull(str, endptr, base) (uint64_t)strtod(str, endptr) +#define wcstoll(str, endptr, base) (int64_t)wcstod(str, endptr) +#define wcstoull(str, endptr, base) (uint64_t)wcstod(str, endptr) +#endif +#endif // TARGET_WINDOWS +#endif // strtoll + +std::string trimRight(const std::string &str) +{ + std::string tmp = str; + // find_last_not_of will return string::npos (which is defined as -1) + // or a value between 0 and size() - 1 => find_last_not_of() + 1 will + // always result in a valid index between 0 and size() + tmp.erase(tmp.find_last_not_of(" \n\r\t") + 1); + + return tmp; +} + +std::wstring trimRight(const std::wstring &str) +{ + std::wstring tmp = str; + // find_last_not_of will return string::npos (which is defined as -1) + // or a value between 0 and size() - 1 => find_last_not_of() + 1 will + // always result in a valid index between 0 and size() + tmp.erase(tmp.find_last_not_of(L" \n\r\t") + 1); + + return tmp; +} + +int64_t str2int64(const std::string &str, int64_t fallback /* = 0 */) +{ + char *end = NULL; + std::string tmp = trimRight(str); + int64_t result = strtoll(tmp.c_str(), &end, 0); + if (end == NULL || *end == '\0') + return result; + + return fallback; +} + +int64_t str2int64(const std::wstring &str, int64_t fallback /* = 0 */) +{ + wchar_t *end = NULL; + std::wstring tmp = trimRight(str); + int64_t result = wcstoll(tmp.c_str(), &end, 0); + if (end == NULL || *end == '\0') + return result; + + return fallback; +} + +uint64_t str2uint64(const std::string &str, uint64_t fallback /* = 0 */) +{ + char *end = NULL; + std::string tmp = trimRight(str); + uint64_t result = strtoull(tmp.c_str(), &end, 0); + if (end == NULL || *end == '\0') + return result; + + return fallback; +} + +uint64_t str2uint64(const std::wstring &str, uint64_t fallback /* = 0 */) +{ + wchar_t *end = NULL; + std::wstring tmp = trimRight(str); + uint64_t result = wcstoull(tmp.c_str(), &end, 0); + if (end == NULL || *end == '\0') + return result; + + return fallback; +} + +double str2double(const std::string &str, double fallback /* = 0.0 */) +{ + char *end = NULL; + std::string tmp = trimRight(str); + double result = strtod(tmp.c_str(), &end); + if (end == NULL || *end == '\0') + return result; + + return fallback; +} + +double str2double(const std::wstring &str, double fallback /* = 0.0 */) +{ + wchar_t *end = NULL; + std::wstring tmp = trimRight(str); + double result = wcstod(tmp.c_str(), &end); + if (end == NULL || *end == '\0') + return result; + + return fallback; +} + +CVariant::CVariant() + : CVariant(VariantTypeNull) +{ +} + +CVariant CVariant::ConstNullVariant = CVariant::VariantTypeConstNull; +CVariant::VariantArray CVariant::EMPTY_ARRAY; +CVariant::VariantMap CVariant::EMPTY_MAP; + +CVariant::CVariant(VariantType type) +{ + m_type = type; + + switch (type) + { + case VariantTypeInteger: + m_data.integer = 0; + break; + case VariantTypeUnsignedInteger: + m_data.unsignedinteger = 0; + break; + case VariantTypeBoolean: + m_data.boolean = false; + break; + case VariantTypeDouble: + m_data.dvalue = 0.0; + break; + case VariantTypeString: + m_data.string = new std::string(); + break; + case VariantTypeWideString: + m_data.wstring = new std::wstring(); + break; + case VariantTypeArray: + m_data.array = new VariantArray(); + break; + case VariantTypeObject: + m_data.map = new VariantMap(); + break; + default: +#ifndef TARGET_WINDOWS_STORE // this corrupts the heap in Win10 UWP version + memset(&m_data, 0, sizeof(m_data)); +#endif + break; + } +} + +CVariant::CVariant(int integer) +{ + m_type = VariantTypeInteger; + m_data.integer = integer; +} + +CVariant::CVariant(int64_t integer) +{ + m_type = VariantTypeInteger; + m_data.integer = integer; +} + +CVariant::CVariant(unsigned int unsignedinteger) +{ + m_type = VariantTypeUnsignedInteger; + m_data.unsignedinteger = unsignedinteger; +} + +CVariant::CVariant(uint64_t unsignedinteger) +{ + m_type = VariantTypeUnsignedInteger; + m_data.unsignedinteger = unsignedinteger; +} + +CVariant::CVariant(double value) +{ + m_type = VariantTypeDouble; + m_data.dvalue = value; +} + +CVariant::CVariant(float value) +{ + m_type = VariantTypeDouble; + m_data.dvalue = (double)value; +} + +CVariant::CVariant(bool boolean) +{ + m_type = VariantTypeBoolean; + m_data.boolean = boolean; +} + +CVariant::CVariant(const char *str) +{ + m_type = VariantTypeString; + m_data.string = new std::string(str); +} + +CVariant::CVariant(const char *str, unsigned int length) +{ + m_type = VariantTypeString; + m_data.string = new std::string(str, length); +} + +CVariant::CVariant(const std::string &str) +{ + m_type = VariantTypeString; + m_data.string = new std::string(str); +} + +CVariant::CVariant(std::string &&str) +{ + m_type = VariantTypeString; + m_data.string = new std::string(std::move(str)); +} + +CVariant::CVariant(const wchar_t *str) +{ + m_type = VariantTypeWideString; + m_data.wstring = new std::wstring(str); +} + +CVariant::CVariant(const wchar_t *str, unsigned int length) +{ + m_type = VariantTypeWideString; + m_data.wstring = new std::wstring(str, length); +} + +CVariant::CVariant(const std::wstring &str) +{ + m_type = VariantTypeWideString; + m_data.wstring = new std::wstring(str); +} + +CVariant::CVariant(std::wstring &&str) +{ + m_type = VariantTypeWideString; + m_data.wstring = new std::wstring(std::move(str)); +} + +CVariant::CVariant(const std::vector &strArray) +{ + m_type = VariantTypeArray; + m_data.array = new VariantArray; + m_data.array->reserve(strArray.size()); + for (const auto& item : strArray) + m_data.array->push_back(CVariant(item)); +} + +CVariant::CVariant(const std::map &strMap) +{ + m_type = VariantTypeObject; + m_data.map = new VariantMap; + for (std::map::const_iterator it = strMap.begin(); it != strMap.end(); ++it) + m_data.map->insert(make_pair(it->first, CVariant(it->second))); +} + +CVariant::CVariant(const std::map &variantMap) +{ + m_type = VariantTypeObject; + m_data.map = new VariantMap(variantMap.begin(), variantMap.end()); +} + +CVariant::CVariant(const CVariant &variant) +{ + m_type = VariantTypeNull; + *this = variant; +} + +CVariant::CVariant(CVariant&& rhs) +{ + //Set this so that operator= don't try and run cleanup + //when we're not initialized. + m_type = VariantTypeNull; + + *this = std::move(rhs); +} + +CVariant::~CVariant() +{ + cleanup(); +} + +void CVariant::cleanup() +{ + switch (m_type) + { + case VariantTypeString: + delete m_data.string; + m_data.string = nullptr; + break; + + case VariantTypeWideString: + delete m_data.wstring; + m_data.wstring = nullptr; + break; + + case VariantTypeArray: + delete m_data.array; + m_data.array = nullptr; + break; + + case VariantTypeObject: + delete m_data.map; + m_data.map = nullptr; + break; + default: + break; + } + m_type = VariantTypeNull; +} + +bool CVariant::isInteger() const +{ + return isSignedInteger() || isUnsignedInteger(); +} + +bool CVariant::isSignedInteger() const +{ + return m_type == VariantTypeInteger; +} + +bool CVariant::isUnsignedInteger() const +{ + return m_type == VariantTypeUnsignedInteger; +} + +bool CVariant::isBoolean() const +{ + return m_type == VariantTypeBoolean; +} + +bool CVariant::isDouble() const +{ + return m_type == VariantTypeDouble; +} + +bool CVariant::isString() const +{ + return m_type == VariantTypeString; +} + +bool CVariant::isWideString() const +{ + return m_type == VariantTypeWideString; +} + +bool CVariant::isArray() const +{ + return m_type == VariantTypeArray; +} + +bool CVariant::isObject() const +{ + return m_type == VariantTypeObject; +} + +bool CVariant::isNull() const +{ + return m_type == VariantTypeNull || m_type == VariantTypeConstNull; +} + +CVariant::VariantType CVariant::type() const +{ + return m_type; +} + +int64_t CVariant::asInteger(int64_t fallback) const +{ + switch (m_type) + { + case VariantTypeInteger: + return m_data.integer; + case VariantTypeUnsignedInteger: + return (int64_t)m_data.unsignedinteger; + case VariantTypeDouble: + return (int64_t)m_data.dvalue; + case VariantTypeString: + return str2int64(*m_data.string, fallback); + case VariantTypeWideString: + return str2int64(*m_data.wstring, fallback); + default: + return fallback; + } + + return fallback; +} + +int32_t CVariant::asInteger32(int32_t fallback) const +{ + return static_cast(asInteger(fallback)); +} + +uint64_t CVariant::asUnsignedInteger(uint64_t fallback) const +{ + switch (m_type) + { + case VariantTypeUnsignedInteger: + return m_data.unsignedinteger; + case VariantTypeInteger: + return (uint64_t)m_data.integer; + case VariantTypeDouble: + return (uint64_t)m_data.dvalue; + case VariantTypeString: + return str2uint64(*m_data.string, fallback); + case VariantTypeWideString: + return str2uint64(*m_data.wstring, fallback); + default: + return fallback; + } + + return fallback; +} + +uint32_t CVariant::asUnsignedInteger32(uint32_t fallback) const +{ + return static_cast(asUnsignedInteger(fallback)); +} + +double CVariant::asDouble(double fallback) const +{ + switch (m_type) + { + case VariantTypeDouble: + return m_data.dvalue; + case VariantTypeInteger: + return (double)m_data.integer; + case VariantTypeUnsignedInteger: + return (double)m_data.unsignedinteger; + case VariantTypeString: + return str2double(*m_data.string, fallback); + case VariantTypeWideString: + return str2double(*m_data.wstring, fallback); + default: + return fallback; + } + + return fallback; +} + +float CVariant::asFloat(float fallback) const +{ + switch (m_type) + { + case VariantTypeDouble: + return (float)m_data.dvalue; + case VariantTypeInteger: + return (float)m_data.integer; + case VariantTypeUnsignedInteger: + return (float)m_data.unsignedinteger; + case VariantTypeString: + return (float)str2double(*m_data.string, fallback); + case VariantTypeWideString: + return (float)str2double(*m_data.wstring, fallback); + default: + return fallback; + } + + return fallback; +} + +bool CVariant::asBoolean(bool fallback) const +{ + switch (m_type) + { + case VariantTypeBoolean: + return m_data.boolean; + case VariantTypeInteger: + return (m_data.integer != 0); + case VariantTypeUnsignedInteger: + return (m_data.unsignedinteger != 0); + case VariantTypeDouble: + return (m_data.dvalue != 0); + case VariantTypeString: + if (m_data.string->empty() || m_data.string->compare("0") == 0 || m_data.string->compare("false") == 0) + return false; + return true; + case VariantTypeWideString: + if (m_data.wstring->empty() || m_data.wstring->compare(L"0") == 0 || m_data.wstring->compare(L"false") == 0) + return false; + return true; + default: + return fallback; + } + + return fallback; +} + +std::string CVariant::asString(const std::string &fallback /* = "" */) const +{ + switch (m_type) + { + case VariantTypeString: + return *m_data.string; + case VariantTypeBoolean: + return m_data.boolean ? "true" : "false"; + case VariantTypeInteger: + return std::to_string(m_data.integer); + case VariantTypeUnsignedInteger: + return std::to_string(m_data.unsignedinteger); + case VariantTypeDouble: + return std::to_string(m_data.dvalue); + default: + return fallback; + } + + return fallback; +} + +std::wstring CVariant::asWideString(const std::wstring &fallback /* = L"" */) const +{ + switch (m_type) + { + case VariantTypeWideString: + return *m_data.wstring; + case VariantTypeBoolean: + return m_data.boolean ? L"true" : L"false"; + case VariantTypeInteger: + return std::to_wstring(m_data.integer); + case VariantTypeUnsignedInteger: + return std::to_wstring(m_data.unsignedinteger); + case VariantTypeDouble: + return std::to_wstring(m_data.dvalue); + default: + return fallback; + } + + return fallback; +} + +CVariant &CVariant::operator[](const std::string &key) +{ + if (m_type == VariantTypeNull) + { + m_type = VariantTypeObject; + m_data.map = new VariantMap; + } + + if (m_type == VariantTypeObject) + return (*m_data.map)[key]; + else + return ConstNullVariant; +} + +const CVariant &CVariant::operator[](const std::string &key) const +{ + VariantMap::const_iterator it; + if (m_type == VariantTypeObject && (it = m_data.map->find(key)) != m_data.map->end()) + return it->second; + else + return ConstNullVariant; +} + +CVariant &CVariant::operator[](unsigned int position) +{ + if (m_type == VariantTypeArray && size() > position) + return m_data.array->at(position); + else + return ConstNullVariant; +} + +const CVariant &CVariant::operator[](unsigned int position) const +{ + if (m_type == VariantTypeArray && size() > position) + return m_data.array->at(position); + else + return ConstNullVariant; +} + +CVariant &CVariant::operator=(const CVariant &rhs) +{ + if (m_type == VariantTypeConstNull || this == &rhs) + return *this; + + cleanup(); + + m_type = rhs.m_type; + + switch (m_type) + { + case VariantTypeInteger: + m_data.integer = rhs.m_data.integer; + break; + case VariantTypeUnsignedInteger: + m_data.unsignedinteger = rhs.m_data.unsignedinteger; + break; + case VariantTypeBoolean: + m_data.boolean = rhs.m_data.boolean; + break; + case VariantTypeDouble: + m_data.dvalue = rhs.m_data.dvalue; + break; + case VariantTypeString: + m_data.string = new std::string(*rhs.m_data.string); + break; + case VariantTypeWideString: + m_data.wstring = new std::wstring(*rhs.m_data.wstring); + break; + case VariantTypeArray: + m_data.array = new VariantArray(rhs.m_data.array->begin(), rhs.m_data.array->end()); + break; + case VariantTypeObject: + m_data.map = new VariantMap(rhs.m_data.map->begin(), rhs.m_data.map->end()); + break; + default: + break; + } + + return *this; +} + +CVariant& CVariant::operator=(CVariant&& rhs) +{ + if (m_type == VariantTypeConstNull || this == &rhs) + return *this; + + //Make sure that if we're moved into we don't leak any pointers + if (m_type != VariantTypeNull) + cleanup(); + + m_type = rhs.m_type; + m_data = std::move(rhs.m_data); + + //Should be enough to just set m_type here + //but better safe than sorry, could probably lead to coverity warnings + if (rhs.m_type == VariantTypeString) + rhs.m_data.string = nullptr; + else if (rhs.m_type == VariantTypeWideString) + rhs.m_data.wstring = nullptr; + else if (rhs.m_type == VariantTypeArray) + rhs.m_data.array = nullptr; + else if (rhs.m_type == VariantTypeObject) + rhs.m_data.map = nullptr; + + rhs.m_type = VariantTypeNull; + + return *this; +} + +bool CVariant::operator==(const CVariant &rhs) const +{ + if (m_type == rhs.m_type) + { + switch (m_type) + { + case VariantTypeInteger: + return m_data.integer == rhs.m_data.integer; + case VariantTypeUnsignedInteger: + return m_data.unsignedinteger == rhs.m_data.unsignedinteger; + case VariantTypeBoolean: + return m_data.boolean == rhs.m_data.boolean; + case VariantTypeDouble: + return m_data.dvalue == rhs.m_data.dvalue; + case VariantTypeString: + return *m_data.string == *rhs.m_data.string; + case VariantTypeWideString: + return *m_data.wstring == *rhs.m_data.wstring; + case VariantTypeArray: + return *m_data.array == *rhs.m_data.array; + case VariantTypeObject: + return *m_data.map == *rhs.m_data.map; + default: + break; + } + } + + return false; +} + +void CVariant::reserve(size_t length) +{ + if (m_type == VariantTypeNull) + { + m_type = VariantTypeArray; + m_data.array = new VariantArray; + } + if (m_type == VariantTypeArray) + m_data.array->reserve(length); +} + +void CVariant::push_back(const CVariant &variant) +{ + if (m_type == VariantTypeNull) + { + m_type = VariantTypeArray; + m_data.array = new VariantArray; + } + + if (m_type == VariantTypeArray) + m_data.array->push_back(variant); +} + +void CVariant::push_back(CVariant &&variant) +{ + if (m_type == VariantTypeNull) + { + m_type = VariantTypeArray; + m_data.array = new VariantArray; + } + + if (m_type == VariantTypeArray) + m_data.array->push_back(std::move(variant)); +} + +void CVariant::append(const CVariant &variant) +{ + push_back(variant); +} + +void CVariant::append(CVariant&& variant) +{ + push_back(std::move(variant)); +} + +const char *CVariant::c_str() const +{ + if (m_type == VariantTypeString) + return m_data.string->c_str(); + else + return NULL; +} + +void CVariant::swap(CVariant &rhs) +{ + VariantType temp_type = m_type; + VariantUnion temp_data = m_data; + + m_type = rhs.m_type; + m_data = rhs.m_data; + + rhs.m_type = temp_type; + rhs.m_data = temp_data; +} + +CVariant::iterator_array CVariant::begin_array() +{ + if (m_type == VariantTypeArray) + return m_data.array->begin(); + else + return EMPTY_ARRAY.begin(); +} + +CVariant::const_iterator_array CVariant::begin_array() const +{ + if (m_type == VariantTypeArray) + return m_data.array->begin(); + else + return EMPTY_ARRAY.begin(); +} + +CVariant::iterator_array CVariant::end_array() +{ + if (m_type == VariantTypeArray) + return m_data.array->end(); + else + return EMPTY_ARRAY.end(); +} + +CVariant::const_iterator_array CVariant::end_array() const +{ + if (m_type == VariantTypeArray) + return m_data.array->end(); + else + return EMPTY_ARRAY.end(); +} + +CVariant::iterator_map CVariant::begin_map() +{ + if (m_type == VariantTypeObject) + return m_data.map->begin(); + else + return EMPTY_MAP.begin(); +} + +CVariant::const_iterator_map CVariant::begin_map() const +{ + if (m_type == VariantTypeObject) + return m_data.map->begin(); + else + return EMPTY_MAP.begin(); +} + +CVariant::iterator_map CVariant::end_map() +{ + if (m_type == VariantTypeObject) + return m_data.map->end(); + else + return EMPTY_MAP.end(); +} + +CVariant::const_iterator_map CVariant::end_map() const +{ + if (m_type == VariantTypeObject) + return m_data.map->end(); + else + return EMPTY_MAP.end(); +} + +unsigned int CVariant::size() const +{ + if (m_type == VariantTypeObject) + return m_data.map->size(); + else if (m_type == VariantTypeArray) + return m_data.array->size(); + else if (m_type == VariantTypeString) + return m_data.string->size(); + else if (m_type == VariantTypeWideString) + return m_data.wstring->size(); + else + return 0; +} + +bool CVariant::empty() const +{ + if (m_type == VariantTypeObject) + return m_data.map->empty(); + else if (m_type == VariantTypeArray) + return m_data.array->empty(); + else if (m_type == VariantTypeString) + return m_data.string->empty(); + else if (m_type == VariantTypeWideString) + return m_data.wstring->empty(); + else if (m_type == VariantTypeNull) + return true; + + return false; +} + +void CVariant::clear() +{ + if (m_type == VariantTypeObject) + m_data.map->clear(); + else if (m_type == VariantTypeArray) + m_data.array->clear(); + else if (m_type == VariantTypeString) + m_data.string->clear(); + else if (m_type == VariantTypeWideString) + m_data.wstring->clear(); +} + +void CVariant::erase(const std::string &key) +{ + if (m_type == VariantTypeNull) + { + m_type = VariantTypeObject; + m_data.map = new VariantMap; + } + else if (m_type == VariantTypeObject) + m_data.map->erase(key); +} + +void CVariant::erase(unsigned int position) +{ + if (m_type == VariantTypeNull) + { + m_type = VariantTypeArray; + m_data.array = new VariantArray; + } + + if (m_type == VariantTypeArray && position < size()) + m_data.array->erase(m_data.array->begin() + position); +} + +bool CVariant::isMember(const std::string &key) const +{ + if (m_type == VariantTypeObject) + return m_data.map->find(key) != m_data.map->end(); + + return false; +} diff --git a/xbmc/utils/Variant.h b/xbmc/utils/Variant.h new file mode 100644 index 0000000..45f8e90 --- /dev/null +++ b/xbmc/utils/Variant.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include +#include +#include + +int64_t str2int64(const std::string &str, int64_t fallback = 0); +int64_t str2int64(const std::wstring &str, int64_t fallback = 0); +uint64_t str2uint64(const std::string &str, uint64_t fallback = 0); +uint64_t str2uint64(const std::wstring &str, uint64_t fallback = 0); +double str2double(const std::string &str, double fallback = 0.0); +double str2double(const std::wstring &str, double fallback = 0.0); + +#ifdef TARGET_WINDOWS_STORE +#pragma pack(push) +#pragma pack(8) +#endif + +class CVariant +{ +public: + enum VariantType + { + VariantTypeInteger, + VariantTypeUnsignedInteger, + VariantTypeBoolean, + VariantTypeString, + VariantTypeWideString, + VariantTypeDouble, + VariantTypeArray, + VariantTypeObject, + VariantTypeNull, + VariantTypeConstNull + }; + + CVariant(); + CVariant(VariantType type); + CVariant(int integer); + CVariant(int64_t integer); + CVariant(unsigned int unsignedinteger); + CVariant(uint64_t unsignedinteger); + CVariant(double value); + CVariant(float value); + CVariant(bool boolean); + CVariant(const char *str); + CVariant(const char *str, unsigned int length); + CVariant(const std::string &str); + CVariant(std::string &&str); + CVariant(const wchar_t *str); + CVariant(const wchar_t *str, unsigned int length); + CVariant(const std::wstring &str); + CVariant(std::wstring &&str); + CVariant(const std::vector &strArray); + CVariant(const std::map &strMap); + CVariant(const std::map &variantMap); + CVariant(const CVariant &variant); + CVariant(CVariant &&rhs); + ~CVariant(); + + + + bool isInteger() const; + bool isSignedInteger() const; + bool isUnsignedInteger() const; + bool isBoolean() const; + bool isString() const; + bool isWideString() const; + bool isDouble() const; + bool isArray() const; + bool isObject() const; + bool isNull() const; + + VariantType type() const; + + int64_t asInteger(int64_t fallback = 0) const; + int32_t asInteger32(int32_t fallback = 0) const; + uint64_t asUnsignedInteger(uint64_t fallback = 0u) const; + uint32_t asUnsignedInteger32(uint32_t fallback = 0u) const; + bool asBoolean(bool fallback = false) const; + std::string asString(const std::string &fallback = "") const; + std::wstring asWideString(const std::wstring &fallback = L"") const; + double asDouble(double fallback = 0.0) const; + float asFloat(float fallback = 0.0f) const; + + CVariant &operator[](const std::string &key); + const CVariant &operator[](const std::string &key) const; + CVariant &operator[](unsigned int position); + const CVariant &operator[](unsigned int position) const; + + CVariant &operator=(const CVariant &rhs); + CVariant &operator=(CVariant &&rhs); + bool operator==(const CVariant &rhs) const; + bool operator!=(const CVariant &rhs) const { return !(*this == rhs); } + + void reserve(size_t length); + void push_back(const CVariant &variant); + void push_back(CVariant &&variant); + void append(const CVariant &variant); + void append(CVariant &&variant); + + const char *c_str() const; + + void swap(CVariant &rhs); + +private: + typedef std::vector VariantArray; + typedef std::map VariantMap; + +public: + typedef VariantArray::iterator iterator_array; + typedef VariantArray::const_iterator const_iterator_array; + + typedef VariantMap::iterator iterator_map; + typedef VariantMap::const_iterator const_iterator_map; + + iterator_array begin_array(); + const_iterator_array begin_array() const; + iterator_array end_array(); + const_iterator_array end_array() const; + + iterator_map begin_map(); + const_iterator_map begin_map() const; + iterator_map end_map(); + const_iterator_map end_map() const; + + unsigned int size() const; + bool empty() const; + void clear(); + void erase(const std::string &key); + void erase(unsigned int position); + + bool isMember(const std::string &key) const; + + static CVariant ConstNullVariant; + +private: + void cleanup(); + union VariantUnion + { + int64_t integer; + uint64_t unsignedinteger; + bool boolean; + double dvalue; + std::string *string; + std::wstring *wstring; + VariantArray *array; + VariantMap *map; + }; + + VariantType m_type; + VariantUnion m_data; + + static VariantArray EMPTY_ARRAY; + static VariantMap EMPTY_MAP; +}; + +#ifdef TARGET_WINDOWS_STORE +#pragma pack(pop) +#endif + diff --git a/xbmc/utils/Vector.cpp b/xbmc/utils/Vector.cpp new file mode 100644 index 0000000..1f3a2fd --- /dev/null +++ b/xbmc/utils/Vector.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Vector.h" + +#include + +CVector& CVector::operator+=(const CVector &other) +{ + x += other.x; + y += other.y; + + return *this; +} + +CVector& CVector::operator-=(const CVector &other) +{ + x -= other.x; + y -= other.y; + + return *this; +} + +float CVector::length() const +{ + return sqrt(pow(x, 2) + pow(y, 2)); +} diff --git a/xbmc/utils/Vector.h b/xbmc/utils/Vector.h new file mode 100644 index 0000000..f427ec9 --- /dev/null +++ b/xbmc/utils/Vector.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +class CVector +{ +public: + CVector() = default; + constexpr CVector(float xCoord, float yCoord):x(xCoord), y(yCoord) {} + + constexpr CVector operator+(const CVector &other) const + { + return CVector(x + other.x, y + other.y); + } + + constexpr CVector operator-(const CVector &other) const + { + return CVector(x - other.x, y - other.y); + } + + CVector& operator+=(const CVector &other); + CVector& operator-=(const CVector &other); + + constexpr float scalar(const CVector &other) const + { + return x * other.x + y * other.y; + } + + float length() const; + + float x = 0; + float y = 0; +}; diff --git a/xbmc/utils/XBMCTinyXML.cpp b/xbmc/utils/XBMCTinyXML.cpp new file mode 100644 index 0000000..6180522 --- /dev/null +++ b/xbmc/utils/XBMCTinyXML.cpp @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "XBMCTinyXML.h" + +#include "LangInfo.h" +#include "RegExp.h" +#include "filesystem/File.h" +#include "utils/CharsetConverter.h" +#include "utils/CharsetDetection.h" +#include "utils/StringUtils.h" +#include "utils/Utf8Utils.h" +#include "utils/log.h" + +#define MAX_ENTITY_LENGTH 8 // size of largest entity "&#xNNNN;" +#define BUFFER_SIZE 4096 + +CXBMCTinyXML::CXBMCTinyXML() +: TiXmlDocument() +{ +} + +CXBMCTinyXML::CXBMCTinyXML(const char *documentName) +: TiXmlDocument(documentName) +{ +} + +CXBMCTinyXML::CXBMCTinyXML(const std::string& documentName) +: TiXmlDocument(documentName) +{ +} + +CXBMCTinyXML::CXBMCTinyXML(const std::string& documentName, const std::string& documentCharset) +: TiXmlDocument(documentName), m_SuggestedCharset(documentCharset) +{ + StringUtils::ToUpper(m_SuggestedCharset); +} + +bool CXBMCTinyXML::LoadFile(TiXmlEncoding encoding) +{ + return LoadFile(value, encoding); +} + +bool CXBMCTinyXML::LoadFile(const char *_filename, TiXmlEncoding encoding) +{ + return LoadFile(std::string(_filename), encoding); +} + +bool CXBMCTinyXML::LoadFile(const std::string& _filename, TiXmlEncoding encoding) +{ + value = _filename.c_str(); + + XFILE::CFile file; + XFILE::auto_buffer buffer; + + if (file.LoadFile(value, buffer) <= 0) + { + SetError(TIXML_ERROR_OPENING_FILE, NULL, NULL, TIXML_ENCODING_UNKNOWN); + return false; + } + + // Delete the existing data: + Clear(); + location.Clear(); + + std::string data(buffer.get(), buffer.length()); + buffer.clear(); // free memory early + + if (encoding == TIXML_ENCODING_UNKNOWN) + Parse(data, file.GetProperty(XFILE::FILE_PROPERTY_CONTENT_CHARSET)); + else + Parse(data, encoding); + + if (Error()) + return false; + return true; +} + +bool CXBMCTinyXML::LoadFile(const std::string& _filename, const std::string& documentCharset) +{ + m_SuggestedCharset = documentCharset; + StringUtils::ToUpper(m_SuggestedCharset); + return LoadFile(_filename, TIXML_ENCODING_UNKNOWN); +} + +bool CXBMCTinyXML::LoadFile(FILE *f, TiXmlEncoding encoding) +{ + std::string data; + char buf[BUFFER_SIZE]; + memset(buf, 0, BUFFER_SIZE); + int result; + while ((result = fread(buf, 1, BUFFER_SIZE, f)) > 0) + data.append(buf, result); + return Parse(data, encoding); +} + +bool CXBMCTinyXML::SaveFile(const char *_filename) const +{ + return SaveFile(std::string(_filename)); +} + +bool CXBMCTinyXML::SaveFile(const std::string& filename) const +{ + XFILE::CFile file; + if (file.OpenForWrite(filename, true)) + { + TiXmlPrinter printer; + Accept(&printer); + bool suc = file.Write(printer.CStr(), printer.Size()) == static_cast(printer.Size()); + if (suc) + file.Flush(); + + return suc; + } + return false; +} + +bool CXBMCTinyXML::Parse(const std::string& data, const std::string& dataCharset) +{ + m_SuggestedCharset = dataCharset; + StringUtils::ToUpper(m_SuggestedCharset); + return Parse(data, TIXML_ENCODING_UNKNOWN); +} + +bool CXBMCTinyXML::Parse(const std::string& data, TiXmlEncoding encoding /*= TIXML_DEFAULT_ENCODING */) +{ + m_UsedCharset.clear(); + if (encoding != TIXML_ENCODING_UNKNOWN) + { // encoding != TIXML_ENCODING_UNKNOWN means "do not use m_SuggestedCharset and charset detection" + m_SuggestedCharset.clear(); + if (encoding == TIXML_ENCODING_UTF8) + m_UsedCharset = "UTF-8"; + + return InternalParse(data, encoding); + } + + if (!m_SuggestedCharset.empty() && TryParse(data, m_SuggestedCharset)) + return true; + + std::string detectedCharset; + if (CCharsetDetection::DetectXmlEncoding(data, detectedCharset) && TryParse(data, detectedCharset)) + { + if (!m_SuggestedCharset.empty()) + CLog::Log(LOGWARNING, "%s: \"%s\" charset was used instead of suggested charset \"%s\" for %s", __FUNCTION__, m_UsedCharset.c_str(), m_SuggestedCharset.c_str(), + (value.empty() ? "XML data" : ("file \"" + value + "\"").c_str())); + + return true; + } + + // check for valid UTF-8 + if (m_SuggestedCharset != "UTF-8" && detectedCharset != "UTF-8" && CUtf8Utils::isValidUtf8(data) && + TryParse(data, "UTF-8")) + { + if (!m_SuggestedCharset.empty()) + CLog::Log(LOGWARNING, "%s: \"%s\" charset was used instead of suggested charset \"%s\" for %s", __FUNCTION__, m_UsedCharset.c_str(), m_SuggestedCharset.c_str(), + (value.empty() ? "XML data" : ("file \"" + value + "\"").c_str())); + else if (!detectedCharset.empty()) + CLog::Log(LOGWARNING, "%s: \"%s\" charset was used instead of detected charset \"%s\" for %s", __FUNCTION__, m_UsedCharset.c_str(), detectedCharset.c_str(), + (value.empty() ? "XML data" : ("file \"" + value + "\"").c_str())); + return true; + } + + // fallback: try user GUI charset + if (TryParse(data, g_langInfo.GetGuiCharSet())) + { + if (!m_SuggestedCharset.empty()) + CLog::Log(LOGWARNING, "%s: \"%s\" charset was used instead of suggested charset \"%s\" for %s", __FUNCTION__, m_UsedCharset.c_str(), m_SuggestedCharset.c_str(), + (value.empty() ? "XML data" : ("file \"" + value + "\"").c_str())); + else if (!detectedCharset.empty()) + CLog::Log(LOGWARNING, "%s: \"%s\" charset was used instead of detected charset \"%s\" for %s", __FUNCTION__, m_UsedCharset.c_str(), detectedCharset.c_str(), + (value.empty() ? "XML data" : ("file \"" + value + "\"").c_str())); + return true; + } + + // can't detect correct data charset, try to process data as is + if (InternalParse(data, TIXML_ENCODING_UNKNOWN)) + { + if (!m_SuggestedCharset.empty()) + CLog::Log(LOGWARNING, "%s: Processed %s as unknown encoding instead of suggested \"%s\"", __FUNCTION__, + (value.empty() ? "XML data" : ("file \"" + value + "\"").c_str()), m_SuggestedCharset.c_str()); + else if (!detectedCharset.empty()) + CLog::Log(LOGWARNING, "%s: Processed %s as unknown encoding instead of detected \"%s\"", __FUNCTION__, + (value.empty() ? "XML data" : ("file \"" + value + "\"").c_str()), detectedCharset.c_str()); + return true; + } + + return false; +} + +bool CXBMCTinyXML::TryParse(const std::string& data, const std::string& tryDataCharset) +{ + if (tryDataCharset == "UTF-8") + InternalParse(data, TIXML_ENCODING_UTF8); // process data without conversion + else if (!tryDataCharset.empty()) + { + std::string converted; + /* some wrong conversions can leave US-ASCII XML header and structure untouched but break non-English data + * so conversion must fail on wrong character and then other encodings will be tried */ + if (!g_charsetConverter.ToUtf8(tryDataCharset, data, converted, true) || converted.empty()) + return false; // can't convert data + + InternalParse(converted, TIXML_ENCODING_UTF8); + } + else + InternalParse(data, TIXML_ENCODING_LEGACY); + + // 'Error()' contains result of last run of 'TiXmlDocument::Parse()' + if (Error()) + { + Clear(); + location.Clear(); + + return false; + } + + m_UsedCharset = tryDataCharset; + return true; +} + +bool CXBMCTinyXML::InternalParse(const std::string& rawdata, TiXmlEncoding encoding /*= TIXML_DEFAULT_ENCODING */) +{ + // Preprocess string, replacing '&' with '& for invalid XML entities + size_t pos = rawdata.find('&'); + if (pos == std::string::npos) + return (TiXmlDocument::Parse(rawdata.c_str(), NULL, encoding) != NULL); // nothing to fix, process data directly + + std::string data(rawdata); + CRegExp re(false, CRegExp::asciiOnly, "^&(amp|lt|gt|quot|apos|#x[a-fA-F0-9]{1,4}|#[0-9]{1,5});.*"); + do + { + if (re.RegFind(data, pos, MAX_ENTITY_LENGTH) < 0) + data.insert(pos + 1, "amp;"); + pos = data.find('&', pos + 1); + } while (pos != std::string::npos); + + return (TiXmlDocument::Parse(data.c_str(), NULL, encoding) != NULL); +} + +bool CXBMCTinyXML::Test() +{ + // scraper results with unescaped & + CXBMCTinyXML doc; + std::string data("
" + "http://api.themoviedb.org/3/movie/12244" + "?api_key=57983e31fb435df4df77afb854740ea9" + "&language=en???
"); + doc.Parse(data, TIXML_DEFAULT_ENCODING); + TiXmlNode *root = doc.RootElement(); + if (root && root->ValueStr() == "details") + { + TiXmlElement *url = root->FirstChildElement("url"); + if (url && url->FirstChild()) + { + return (url->FirstChild()->ValueStr() == "http://api.themoviedb.org/3/movie/12244?api_key=57983e31fb435df4df77afb854740ea9&language=en???"); + } + } + return false; +} diff --git a/xbmc/utils/XBMCTinyXML.h b/xbmc/utils/XBMCTinyXML.h new file mode 100644 index 0000000..2f4e188 --- /dev/null +++ b/xbmc/utils/XBMCTinyXML.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifndef TARGET_WINDOWS +//compile fix for TinyXml < 2.6.0 +#define DOCUMENT TINYXML_DOCUMENT +#define ELEMENT TINYXML_ELEMENT +#define COMMENT TINYXML_COMMENT +#define UNKNOWN TINYXML_UNKNOWN +#define TEXT TINYXML_TEXT +#define DECLARATION TINYXML_DECLARATION +#define TYPECOUNT TINYXML_TYPECOUNT +#endif + +#include +#include + +#undef DOCUMENT +#undef ELEMENT +#undef COMMENT +#undef UNKNOWN +//#undef TEXT +#undef DECLARATION +#undef TYPECOUNT + +class CXBMCTinyXML : public TiXmlDocument +{ +public: + CXBMCTinyXML(); + explicit CXBMCTinyXML(const char*); + explicit CXBMCTinyXML(const std::string& documentName); + CXBMCTinyXML(const std::string& documentName, const std::string& documentCharset); + bool LoadFile(TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); + bool LoadFile(const char*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); + bool LoadFile(const std::string& _filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); + bool LoadFile(const std::string& _filename, const std::string& documentCharset); + bool LoadFile(FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); + bool SaveFile(const char*) const; + bool SaveFile(const std::string& filename) const; + bool Parse(const std::string& data, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); + bool Parse(const std::string& data, const std::string& dataCharset); + inline std::string GetSuggestedCharset(void) const { return m_SuggestedCharset; } + inline std::string GetUsedCharset(void) const { return m_UsedCharset; } + static bool Test(); +protected: + using TiXmlDocument::Parse; + bool TryParse(const std::string& data, const std::string& tryDataCharset); + bool InternalParse(const std::string& rawdata, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); + + std::string m_SuggestedCharset; + std::string m_UsedCharset; +}; diff --git a/xbmc/utils/XMLUtils.cpp b/xbmc/utils/XMLUtils.cpp new file mode 100644 index 0000000..d921602 --- /dev/null +++ b/xbmc/utils/XMLUtils.cpp @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "XMLUtils.h" +#include "URL.h" +#include "StringUtils.h" + +bool XMLUtils::GetHex(const TiXmlNode* pRootNode, const char* strTag, uint32_t& hexValue) +{ + const TiXmlNode* pNode = pRootNode->FirstChild(strTag ); + if (!pNode || !pNode->FirstChild()) return false; + return sscanf(pNode->FirstChild()->Value(), "%x", &hexValue) == 1; +} + + +bool XMLUtils::GetUInt(const TiXmlNode* pRootNode, const char* strTag, uint32_t& uintValue) +{ + const TiXmlNode* pNode = pRootNode->FirstChild(strTag ); + if (!pNode || !pNode->FirstChild()) return false; + uintValue = atol(pNode->FirstChild()->Value()); + return true; +} + +bool XMLUtils::GetUInt(const TiXmlNode* pRootNode, const char* strTag, uint32_t &value, const uint32_t min, const uint32_t max) +{ + if (GetUInt(pRootNode, strTag, value)) + { + if (value < min) value = min; + if (value > max) value = max; + return true; + } + return false; +} + +bool XMLUtils::GetLong(const TiXmlNode* pRootNode, const char* strTag, long& lLongValue) +{ + const TiXmlNode* pNode = pRootNode->FirstChild(strTag ); + if (!pNode || !pNode->FirstChild()) return false; + lLongValue = atol(pNode->FirstChild()->Value()); + return true; +} + +bool XMLUtils::GetInt(const TiXmlNode* pRootNode, const char* strTag, int& iIntValue) +{ + const TiXmlNode* pNode = pRootNode->FirstChild(strTag ); + if (!pNode || !pNode->FirstChild()) return false; + iIntValue = atoi(pNode->FirstChild()->Value()); + return true; +} + +bool XMLUtils::GetInt(const TiXmlNode* pRootNode, const char* strTag, int &value, const int min, const int max) +{ + if (GetInt(pRootNode, strTag, value)) + { + if (value < min) value = min; + if (value > max) value = max; + return true; + } + return false; +} + +bool XMLUtils::GetDouble(const TiXmlNode* root, const char* tag, double& value) +{ + const TiXmlNode* node = root->FirstChild(tag); + if (!node || !node->FirstChild()) return false; + value = atof(node->FirstChild()->Value()); + return true; +} + +bool XMLUtils::GetFloat(const TiXmlNode* pRootNode, const char* strTag, float& value) +{ + const TiXmlNode* pNode = pRootNode->FirstChild(strTag ); + if (!pNode || !pNode->FirstChild()) return false; + value = (float)atof(pNode->FirstChild()->Value()); + return true; +} + +bool XMLUtils::GetFloat(const TiXmlNode* pRootElement, const char *tagName, float& fValue, const float fMin, const float fMax) +{ + if (GetFloat(pRootElement, tagName, fValue)) + { // check range + if (fValue < fMin) fValue = fMin; + if (fValue > fMax) fValue = fMax; + return true; + } + return false; +} + +bool XMLUtils::GetBoolean(const TiXmlNode* pRootNode, const char* strTag, bool& bBoolValue) +{ + const TiXmlNode* pNode = pRootNode->FirstChild(strTag ); + if (!pNode || !pNode->FirstChild()) return false; + std::string strEnabled = pNode->FirstChild()->ValueStr(); + StringUtils::ToLower(strEnabled); + if (strEnabled == "off" || strEnabled == "no" || strEnabled == "disabled" || strEnabled == "false" || strEnabled == "0" ) + bBoolValue = false; + else + { + bBoolValue = true; + if (strEnabled != "on" && strEnabled != "yes" && strEnabled != "enabled" && strEnabled != "true") + return false; // invalid bool switch - it's probably some other string. + } + return true; +} + +bool XMLUtils::GetString(const TiXmlNode* pRootNode, const char* strTag, std::string& strStringValue) +{ + const TiXmlElement* pElement = pRootNode->FirstChildElement(strTag); + if (!pElement) return false; + + const char* encoded = pElement->Attribute("urlencoded"); + const TiXmlNode* pNode = pElement->FirstChild(); + if (pNode != NULL) + { + strStringValue = pNode->ValueStr(); + if (encoded && StringUtils::CompareNoCase(encoded, "yes") == 0) + strStringValue = CURL::Decode(strStringValue); + return true; + } + strStringValue.clear(); + return true; +} + +std::string XMLUtils::GetString(const TiXmlNode* pRootNode, const char* strTag) +{ + std::string temp; + GetString(pRootNode, strTag, temp); + return temp; +} + +bool XMLUtils::HasChild(const TiXmlNode* pRootNode, const char* strTag) +{ + const TiXmlElement* pElement = pRootNode->FirstChildElement(strTag); + if (!pElement) return false; + const TiXmlNode* pNode = pElement->FirstChild(); + return (pNode != NULL); +} + +bool XMLUtils::GetAdditiveString(const TiXmlNode* pRootNode, const char* strTag, + const std::string& strSeparator, std::string& strStringValue, + bool clear) +{ + std::string strTemp; + const TiXmlElement* node = pRootNode->FirstChildElement(strTag); + bool bResult=false; + if (node && node->FirstChild() && clear) + strStringValue.clear(); + while (node) + { + if (node->FirstChild()) + { + bResult = true; + strTemp = node->FirstChild()->Value(); + const char* clear=node->Attribute("clear"); + if (strStringValue.empty() || (clear && StringUtils::CompareNoCase(clear, "true") == 0)) + strStringValue = strTemp; + else + strStringValue += strSeparator+strTemp; + } + node = node->NextSiblingElement(strTag); + } + + return bResult; +} + +/*! + Parses the XML for multiple tags of the given name. + Does not clear the array to support chaining. +*/ +bool XMLUtils::GetStringArray(const TiXmlNode* pRootNode, const char* strTag, std::vector& arrayValue, bool clear /* = false */, const std::string& separator /* = "" */) +{ + std::string strTemp; + const TiXmlElement* node = pRootNode->FirstChildElement(strTag); + bool bResult=false; + if (node && node->FirstChild() && clear) + arrayValue.clear(); + while (node) + { + if (node->FirstChild()) + { + bResult = true; + strTemp = node->FirstChild()->ValueStr(); + + const char* clearAttr = node->Attribute("clear"); + if (clearAttr && StringUtils::CompareNoCase(clearAttr, "true") == 0) + arrayValue.clear(); + + if (strTemp.empty()) + continue; + + if (separator.empty()) + arrayValue.push_back(strTemp); + else + { + std::vector tempArray = StringUtils::Split(strTemp, separator); + arrayValue.insert(arrayValue.end(), tempArray.begin(), tempArray.end()); + } + } + node = node->NextSiblingElement(strTag); + } + + return bResult; +} + +bool XMLUtils::GetPath(const TiXmlNode* pRootNode, const char* strTag, std::string& strStringValue) +{ + const TiXmlElement* pElement = pRootNode->FirstChildElement(strTag); + if (!pElement) return false; + + const char* encoded = pElement->Attribute("urlencoded"); + const TiXmlNode* pNode = pElement->FirstChild(); + if (pNode != NULL) + { + strStringValue = pNode->Value(); + if (encoded && StringUtils::CompareNoCase(encoded, "yes") == 0) + strStringValue = CURL::Decode(strStringValue); + return true; + } + strStringValue.clear(); + return false; +} + +bool XMLUtils::GetDate(const TiXmlNode* pRootNode, const char* strTag, CDateTime& date) +{ + std::string strDate; + if (GetString(pRootNode, strTag, strDate) && !strDate.empty()) + { + date.SetFromDBDate(strDate); + return true; + } + + return false; +} + +bool XMLUtils::GetDateTime(const TiXmlNode* pRootNode, const char* strTag, CDateTime& dateTime) +{ + std::string strDateTime; + if (GetString(pRootNode, strTag, strDateTime) && !strDateTime.empty()) + { + dateTime.SetFromDBDateTime(strDateTime); + return true; + } + + return false; +} + +std::string XMLUtils::GetAttribute(const TiXmlElement *element, const char *tag) +{ + if (element) + { + const char *attribute = element->Attribute(tag); + if (attribute) + return attribute; + } + return ""; +} + +void XMLUtils::SetAdditiveString(TiXmlNode* pRootNode, const char *strTag, const std::string& strSeparator, const std::string& strValue) +{ + std::vector list = StringUtils::Split(strValue, strSeparator); + for (std::vector::const_iterator i = list.begin(); i != list.end(); ++i) + SetString(pRootNode, strTag, *i); +} + +void XMLUtils::SetStringArray(TiXmlNode* pRootNode, const char *strTag, const std::vector& arrayValue) +{ + for (unsigned int i = 0; i < arrayValue.size(); i++) + SetString(pRootNode, strTag, arrayValue.at(i)); +} + +TiXmlNode* XMLUtils::SetString(TiXmlNode* pRootNode, const char *strTag, const std::string& strValue) +{ + TiXmlElement newElement(strTag); + TiXmlNode *pNewNode = pRootNode->InsertEndChild(newElement); + if (pNewNode) + { + TiXmlText value(strValue); + pNewNode->InsertEndChild(value); + } + return pNewNode; +} + +TiXmlNode* XMLUtils::SetInt(TiXmlNode* pRootNode, const char *strTag, int value) +{ + std::string strValue = StringUtils::Format("%i", value); + return SetString(pRootNode, strTag, strValue); +} + +void XMLUtils::SetLong(TiXmlNode* pRootNode, const char *strTag, long value) +{ + std::string strValue = StringUtils::Format("%ld", value); + SetString(pRootNode, strTag, strValue); +} + +TiXmlNode* XMLUtils::SetFloat(TiXmlNode* pRootNode, const char *strTag, float value) +{ + std::string strValue = StringUtils::Format("%f", value); + return SetString(pRootNode, strTag, strValue); +} + +TiXmlNode* XMLUtils::SetDouble(TiXmlNode* pRootNode, const char* strTag, double value) +{ + std::string strValue = StringUtils::Format("%lf", value); + return SetString(pRootNode, strTag, strValue); +} + +void XMLUtils::SetBoolean(TiXmlNode* pRootNode, const char *strTag, bool value) +{ + SetString(pRootNode, strTag, value ? "true" : "false"); +} + +void XMLUtils::SetHex(TiXmlNode* pRootNode, const char *strTag, uint32_t value) +{ + std::string strValue = StringUtils::Format("%x", value); + SetString(pRootNode, strTag, strValue); +} + +void XMLUtils::SetPath(TiXmlNode* pRootNode, const char *strTag, const std::string& strValue) +{ + TiXmlElement newElement(strTag); + newElement.SetAttribute("pathversion", path_version); + TiXmlNode *pNewNode = pRootNode->InsertEndChild(newElement); + if (pNewNode) + { + TiXmlText value(strValue); + pNewNode->InsertEndChild(value); + } +} + +void XMLUtils::SetDate(TiXmlNode* pRootNode, const char *strTag, const CDateTime& date) +{ + SetString(pRootNode, strTag, date.IsValid() ? date.GetAsDBDate() : ""); +} + +void XMLUtils::SetDateTime(TiXmlNode* pRootNode, const char *strTag, const CDateTime& dateTime) +{ + SetString(pRootNode, strTag, dateTime.IsValid() ? dateTime.GetAsDBDateTime() : ""); +} diff --git a/xbmc/utils/XMLUtils.h b/xbmc/utils/XMLUtils.h new file mode 100644 index 0000000..fcd23bd --- /dev/null +++ b/xbmc/utils/XMLUtils.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/XBMCTinyXML.h" + +#include +#include +#include + +class CDateTime; + +class XMLUtils +{ +public: + static bool HasChild(const TiXmlNode* pRootNode, const char* strTag); + + static bool GetHex(const TiXmlNode* pRootNode, const char* strTag, uint32_t& dwHexValue); + static bool GetUInt(const TiXmlNode* pRootNode, const char* strTag, uint32_t& dwUIntValue); + static bool GetLong(const TiXmlNode* pRootNode, const char* strTag, long& lLongValue); + static bool GetFloat(const TiXmlNode* pRootNode, const char* strTag, float& value); + static bool GetDouble(const TiXmlNode* pRootNode, const char* strTag, double& value); + static bool GetInt(const TiXmlNode* pRootNode, const char* strTag, int& iIntValue); + static bool GetBoolean(const TiXmlNode* pRootNode, const char* strTag, bool& bBoolValue); + + /*! \brief Get a string value from the xml tag + If the specified tag isn't found strStringvalue is not modified and will contain whatever + value it had before the method call. + + \param[in] pRootNode the xml node that contains the tag + \param[in] strTag the xml tag to read from + \param[in,out] strStringValue where to store the read string + \return true on success, false if the tag isn't found + */ + static bool GetString(const TiXmlNode* pRootNode, const char* strTag, std::string& strStringValue); + + /*! \brief Get a string value from the xml tag + + \param[in] pRootNode the xml node that contains the tag + \param[in] strTag the tag to read from + + \return the value in the specified tag or an empty string if the tag isn't found + */ + static std::string GetString(const TiXmlNode* pRootNode, const char* strTag); + /*! \brief Get multiple tags, concatenating the values together. + Transforms + value1 + value2 + ... + valuen + into value2...valuen, appending it to the value string. Note that is overwritten by the clear="true" tag. + + \param rootNode the parent containing the 's. + \param tag the in question. + \param separator the separator to use when concatenating values. + \param value [out] the resulting string. Remains untouched if no is available, else is appended (or cleared based on the clear parameter). + \param clear if true, clears the string prior to adding tags, if tags are available. Defaults to false. + */ + static bool GetAdditiveString(const TiXmlNode* rootNode, const char* tag, const std::string& separator, std::string& value, bool clear = false); + static bool GetStringArray(const TiXmlNode* rootNode, const char* tag, std::vector& arrayValue, bool clear = false, const std::string& separator = ""); + static bool GetPath(const TiXmlNode* pRootNode, const char* strTag, std::string& strStringValue); + static bool GetFloat(const TiXmlNode* pRootNode, const char* strTag, float& value, const float min, const float max); + static bool GetUInt(const TiXmlNode* pRootNode, const char* strTag, uint32_t& dwUIntValue, const uint32_t min, const uint32_t max); + static bool GetInt(const TiXmlNode* pRootNode, const char* strTag, int& iIntValue, const int min, const int max); + static bool GetDate(const TiXmlNode* pRootNode, const char* strTag, CDateTime& date); + static bool GetDateTime(const TiXmlNode* pRootNode, const char* strTag, CDateTime& dateTime); + /*! \brief Fetch a std::string copy of an attribute, if it exists. Cannot distinguish between empty and non-existent attributes. + \param element the element to query. + \param tag the name of the attribute. + \return the attribute, if it exists, else an empty string + */ + static std::string GetAttribute(const TiXmlElement *element, const char *tag); + + static TiXmlNode* SetString(TiXmlNode* pRootNode, const char *strTag, const std::string& strValue); + static void SetAdditiveString(TiXmlNode* pRootNode, const char *strTag, const std::string& strSeparator, const std::string& strValue); + static void SetStringArray(TiXmlNode* pRootNode, const char *strTag, const std::vector& arrayValue); + static TiXmlNode* SetInt(TiXmlNode* pRootNode, const char *strTag, int value); + static TiXmlNode* SetFloat(TiXmlNode* pRootNode, const char *strTag, float value); + static TiXmlNode* SetDouble(TiXmlNode* pRootNode, const char* strTag, double value); + static void SetBoolean(TiXmlNode* pRootNode, const char *strTag, bool value); + static void SetHex(TiXmlNode* pRootNode, const char *strTag, uint32_t value); + static void SetPath(TiXmlNode* pRootNode, const char *strTag, const std::string& strValue); + static void SetLong(TiXmlNode* pRootNode, const char *strTag, long iValue); + static void SetDate(TiXmlNode* pRootNode, const char *strTag, const CDateTime& date); + static void SetDateTime(TiXmlNode* pRootNode, const char *strTag, const CDateTime& dateTime); + + static const int path_version = 1; +}; + diff --git a/xbmc/utils/XSLTUtils.cpp b/xbmc/utils/XSLTUtils.cpp new file mode 100644 index 0000000..b2ef27b --- /dev/null +++ b/xbmc/utils/XSLTUtils.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "XSLTUtils.h" +#include "log.h" +#include +#include + +#ifndef TARGET_WINDOWS +#include +#endif + +#define TMP_BUF_SIZE 512 +void err(void *ctx, const char *msg, ...) { + char string[TMP_BUF_SIZE]; + va_list arg_ptr; + va_start(arg_ptr, msg); + vsnprintf(string, TMP_BUF_SIZE, msg, arg_ptr); + va_end(arg_ptr); + CLog::Log(LOGDEBUG, "XSLT: %s", string); +} + +XSLTUtils::XSLTUtils() +{ + // initialize libxslt + xmlSubstituteEntitiesDefault(1); + xmlLoadExtDtdDefaultValue = 0; + xsltSetGenericErrorFunc(NULL, err); +} + +XSLTUtils::~XSLTUtils() +{ + if (m_xmlInput) + xmlFreeDoc(m_xmlInput); + if (m_xmlOutput) + xmlFreeDoc(m_xmlOutput); + if (m_xsltStylesheet) + xsltFreeStylesheet(m_xsltStylesheet); +} + +bool XSLTUtils::XSLTTransform(std::string& output) +{ + const char *params[16+1]; + params[0] = NULL; + m_xmlOutput = xsltApplyStylesheet(m_xsltStylesheet, m_xmlInput, params); + if (!m_xmlOutput) + { + CLog::Log(LOGDEBUG, "XSLT: xslt transformation failed"); + return false; + } + + xmlChar *xmlResultBuffer = NULL; + int xmlResultLength = 0; + int res = xsltSaveResultToString(&xmlResultBuffer, &xmlResultLength, m_xmlOutput, m_xsltStylesheet); + if (res == -1) + { + xmlFree(xmlResultBuffer); + return false; + } + + output.append((const char *)xmlResultBuffer, xmlResultLength); + xmlFree(xmlResultBuffer); + + return true; +} + +bool XSLTUtils::SetInput(const std::string& input) +{ + m_xmlInput = xmlParseMemory(input.c_str(), input.size()); + if (!m_xmlInput) + return false; + return true; +} + +bool XSLTUtils::SetStylesheet(const std::string& stylesheet) +{ + if (m_xsltStylesheet) { + xsltFreeStylesheet(m_xsltStylesheet); + m_xsltStylesheet = NULL; + } + + m_xmlStylesheet = xmlParseMemory(stylesheet.c_str(), stylesheet.size()); + if (!m_xmlStylesheet) + { + CLog::Log(LOGDEBUG, "could not xmlParseMemory stylesheetdoc"); + return false; + } + + m_xsltStylesheet = xsltParseStylesheetDoc(m_xmlStylesheet); + if (!m_xsltStylesheet) { + CLog::Log(LOGDEBUG, "could not parse stylesheetdoc"); + xmlFree(m_xmlStylesheet); + m_xmlStylesheet = NULL; + return false; + } + + return true; +} diff --git a/xbmc/utils/XSLTUtils.h b/xbmc/utils/XSLTUtils.h new file mode 100644 index 0000000..78221b9 --- /dev/null +++ b/xbmc/utils/XSLTUtils.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +#include +#include + +class XSLTUtils +{ +public: + XSLTUtils(); + ~XSLTUtils(); + + /*! \brief Set the input XML for an XSLT transform from a string. + This sets up the XSLT transformer with some input XML from a string in memory. + The input XML should be well formed. + \param input the XML document to be transformed. + */ + bool SetInput(const std::string& input); + + /*! \brief Set the stylesheet (XSL) for an XSLT transform from a string. + This sets up the XSLT transformer with some stylesheet XML from a string in memory. + The input XSL should be well formed. + \param input the XSL document to be transformed. + */ + bool SetStylesheet(const std::string& stylesheet); + + /*! \brief Perform an XSLT transform on an inbound XML document. + This will apply an XSLT transformation on an input XML document, + giving an output XML document, using the specified XSLT document + as the transformer. + \param input the parent containing the 's. + \param filename the in question. + */ + bool XSLTTransform(std::string& output); + + +private: + xmlDocPtr m_xmlInput = nullptr; + xmlDocPtr m_xmlOutput = nullptr; + xmlDocPtr m_xmlStylesheet = nullptr; + xsltStylesheetPtr m_xsltStylesheet = nullptr; +}; diff --git a/xbmc/utils/XTimeUtils.h b/xbmc/utils/XTimeUtils.h new file mode 100644 index 0000000..721c1f7 --- /dev/null +++ b/xbmc/utils/XTimeUtils.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +#if !defined(TARGET_WINDOWS) +#include "PlatformDefs.h" +#else +// This is needed, a forward declaration of FILETIME +// breaks everything +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif + +namespace KODI +{ +namespace TIME +{ +struct SystemTime +{ + unsigned short year; + unsigned short month; + unsigned short dayOfWeek; + unsigned short day; + unsigned short hour; + unsigned short minute; + unsigned short second; + unsigned short milliseconds; +}; + +struct TimeZoneInformation +{ + long bias; + std::string standardName; + SystemTime standardDate; + long standardBias; + std::string daylightName; + SystemTime daylightDate; + long daylightBias; +}; + +constexpr int KODI_TIME_ZONE_ID_INVALID{-1}; +constexpr int KODI_TIME_ZONE_ID_UNKNOWN{0}; +constexpr int KODI_TIME_ZONE_ID_STANDARD{1}; +constexpr int KODI_TIME_ZONE_ID_DAYLIGHT{2}; + +struct FileTime +{ + unsigned int lowDateTime; + unsigned int highDateTime; +}; + +void GetLocalTime(SystemTime* systemTime); +uint32_t GetTimeZoneInformation(TimeZoneInformation* timeZoneInformation); + +void Sleep(uint32_t milliSeconds); + +int FileTimeToLocalFileTime(const FileTime* fileTime, FileTime* localFileTime); +int SystemTimeToFileTime(const SystemTime* systemTime, FileTime* fileTime); +long CompareFileTime(const FileTime* fileTime1, const FileTime* fileTime2); +int FileTimeToSystemTime(const FileTime* fileTime, SystemTime* systemTime); +int LocalFileTimeToFileTime(const FileTime* LocalFileTime, FileTime* fileTime); + +int FileTimeToTimeT(const FileTime* localFileTime, time_t* pTimeT); +int TimeTToFileTime(time_t timeT, FileTime* localFileTime); +} // namespace TIME +} // namespace KODI diff --git a/xbmc/utils/auto_buffer.cpp b/xbmc/utils/auto_buffer.cpp new file mode 100644 index 0000000..e88a960 --- /dev/null +++ b/xbmc/utils/auto_buffer.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2013-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "auto_buffer.h" + +#include // for std::bad_alloc +#include // for malloc(), realloc() and free() + +using namespace XUTILS; + +auto_buffer::auto_buffer(size_t size) +{ + if (!size) + return; + + p = malloc(size); // "malloc()" instead of "new" allow to use "realloc()" + if (!p) + throw std::bad_alloc(); + s = size; +} + +auto_buffer::~auto_buffer() +{ + free(p); +} + +auto_buffer& auto_buffer::allocate(size_t size) +{ + clear(); + if (size) + { + p = malloc(size); + if (!p) + throw std::bad_alloc(); + s = size; + } + return *this; +} + +auto_buffer& auto_buffer::resize(size_t newSize) +{ + if (!newSize) + return clear(); + + void* newPtr = realloc(p, newSize); + if (!newPtr) + throw std::bad_alloc(); + p = newPtr; + s = newSize; + return *this; +} + +auto_buffer& auto_buffer::clear(void) +{ + free(p); + p = 0; + s = 0; + return *this; +} + +auto_buffer& auto_buffer::attach(void* pointer, size_t size) +{ + clear(); + if ((pointer && size) || (!pointer && !size)) + { + p = pointer; + s = size; + } + return *this; +} + +void* auto_buffer::detach(void) +{ + void* returnPtr = p; + p = 0; + s = 0; + return returnPtr; +} + diff --git a/xbmc/utils/auto_buffer.h b/xbmc/utils/auto_buffer.h new file mode 100644 index 0000000..066b6f8 --- /dev/null +++ b/xbmc/utils/auto_buffer.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include // for size_t + +namespace XUTILS +{ + + class auto_buffer + { + public: + /** + * Create buffer with zero size + */ + auto_buffer(void) = default; + /** + * Create buffer with specified size + * @param size of created buffer + */ + explicit auto_buffer(size_t size); + ~auto_buffer(); + + /** + * Allocate specified size for buffer, discarding current buffer content + * @param size of buffer to allocate + * @return reference to itself + */ + auto_buffer& allocate(size_t size); + /** + * Resize current buffer to new size. Buffer will be extended or truncated at the end. + * @param newSize of buffer + * @return reference to itself + */ + auto_buffer& resize(size_t newSize); + /** + * Reset buffer to zero size + * @return reference to itself + */ + auto_buffer& clear(void); + + /** + * Get pointer to buffer content + * @return pointer to buffer content or NULL if buffer is zero size + */ + inline char* get(void) { return static_cast(p); } + /** + * Get constant pointer to buffer content + * @return constant pointer to buffer content + */ + inline const char* get(void) const { return static_cast(p); } + /** + * Get size of the buffer + * @return size of the buffer + */ + inline size_t size(void) const { return s; } + /** + * Get size of the buffer + * @return size of the buffer + */ + inline size_t length(void) const { return s; } + + /** + * Attach malloc'ed pointer to the buffer, discarding current buffer content + * Pointer must be acquired by malloc() or realloc(). + * Pointer will be automatically freed on destroy of the buffer. + * @param pointer to attach + * @param size of new memory region pointed by pointer + * @return reference to itself + */ + auto_buffer& attach(void* pointer, size_t size); + /** + * Detach current buffer content from the buffer, reset buffer to zero size + * Caller is responsible to free memory by calling free() for returned pointer + * when pointer in not needed anymore + * @return detached from buffer pointer to content + */ + void* detach(void); + + private: + auto_buffer(const auto_buffer& other) = delete; // disallow copy constructor + auto_buffer& operator=(const auto_buffer& other) = delete; // disallow assignment + + void* p = 0; + size_t s = 0; + }; +} diff --git a/xbmc/utils/log.cpp b/xbmc/utils/log.cpp new file mode 100644 index 0000000..7fb87fe --- /dev/null +++ b/xbmc/utils/log.cpp @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "log.h" + +#include "CompileInfo.h" +#include "ServiceBroker.h" +#include "filesystem/File.h" +#include "guilib/LocalizeStrings.h" +#if defined(TARGET_ANDROID) +#include "platform/android/utils/AndroidInterfaceForCLog.h" +#elif defined(TARGET_DARWIN) +#include "platform/darwin/utils/DarwinInterfaceForCLog.h" +#elif defined(TARGET_WINDOWS) || defined(TARGET_WIN10) +#include "platform/win32/utils/Win32InterfaceForCLog.h" +#else +#include "platform/posix/utils/PosixInterfaceForCLog.h" +#endif +#include "settings/SettingUtils.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "settings/lib/Setting.h" +#include "settings/lib/SettingsManager.h" +#include "utils/URIUtils.h" + +#include +#include + +#include +#include + +static constexpr unsigned char Utf8Bom[3] = {0xEF, 0xBB, 0xBF}; +static const std::string LogFileExtension = ".log"; +static const std::string LogPattern = "%Y-%m-%d %T.%e T:%-5t %7l <%n>: %v"; + +CLog::CLog() + : m_platform(IPlatformLog::CreatePlatformLog()), + m_sinks(std::make_shared()), + m_defaultLogger(CreateLogger("general")), + m_logLevel(LOG_LEVEL_DEBUG), + m_componentLogEnabled(false), + m_componentLogLevels(0) +{ + // add platform-specific debug sinks + m_platform->AddSinks(m_sinks); + + // register the default logger with spdlog + spdlog::set_default_logger(m_defaultLogger); + + // set the formatting pattern globally + spdlog::set_pattern(LogPattern); + + // flush on debug logs + spdlog::flush_on(spdlog::level::debug); + + // set the log level + SetLogLevel(m_logLevel); +} + +void CLog::OnSettingsLoaded() +{ + const std::shared_ptr settings = CServiceBroker::GetSettingsComponent()->GetSettings(); + m_componentLogEnabled = settings->GetBool(CSettings::SETTING_DEBUG_EXTRALOGGING); + SetComponentLogLevel(settings->GetList(CSettings::SETTING_DEBUG_SETEXTRALOGLEVEL)); +} + +void CLog::OnSettingChanged(std::shared_ptr setting) +{ + if (setting == NULL) + return; + + const std::string& settingId = setting->GetId(); + if (settingId == CSettings::SETTING_DEBUG_EXTRALOGGING) + m_componentLogEnabled = std::static_pointer_cast(setting)->GetValue(); + else if (settingId == CSettings::SETTING_DEBUG_SETEXTRALOGLEVEL) + SetComponentLogLevel( + CSettingUtils::GetList(std::static_pointer_cast(setting))); +} + +void CLog::Initialize(const std::string& path) +{ + if (m_fileSink != nullptr) + return; + + // register setting callbacks + auto settingsManager = + CServiceBroker::GetSettingsComponent()->GetSettings()->GetSettingsManager(); + settingsManager->RegisterSettingOptionsFiller("loggingcomponents", + SettingOptionsLoggingComponentsFiller); + settingsManager->RegisterSettingsHandler(this); + std::set settingSet; + settingSet.insert(CSettings::SETTING_DEBUG_EXTRALOGGING); + settingSet.insert(CSettings::SETTING_DEBUG_SETEXTRALOGLEVEL); + settingsManager->RegisterCallback(this, settingSet); + + if (path.empty()) + return; + + // put together the path to the log file(s) + std::string appName = CCompileInfo::GetAppName(); + StringUtils::ToLower(appName); + const std::string filePathBase = URIUtils::AddFileToFolder(path, appName); + const std::string filePath = filePathBase + LogFileExtension; + const std::string oldFilePath = filePathBase + ".old" + LogFileExtension; + + // handle old.log by deleting an existing old.log and renaming the last log to old.log + XFILE::CFile::Delete(oldFilePath); + XFILE::CFile::Rename(filePath, oldFilePath); + + // write UTF-8 BOM + { + XFILE::CFile file; + if (file.OpenForWrite(filePath, true)) + file.Write(Utf8Bom, sizeof(Utf8Bom)); + } + + // create the file sink + m_fileSink = std::make_shared( + m_platform->GetLogFilename(filePath), false); + m_fileSink->set_pattern(LogPattern); + + // add it to the existing sinks + m_sinks->add_sink(m_fileSink); +} + +void CLog::Uninitialize() +{ + if (m_fileSink == nullptr) + return; + + // unregister setting callbacks + auto settingsManager = + CServiceBroker::GetSettingsComponent()->GetSettings()->GetSettingsManager(); + settingsManager->UnregisterSettingOptionsFiller("loggingcomponents"); + settingsManager->UnregisterSettingsHandler(this); + settingsManager->UnregisterCallback(this); + + // flush all loggers + spdlog::apply_all([](std::shared_ptr logger) { logger->flush(); }); + + // flush the file sink + m_fileSink->flush(); + + // remove and destroy the file sink + m_sinks->remove_sink(m_fileSink); + m_fileSink.reset(); +} + +void CLog::SetLogLevel(int level) +{ + if (level < LOG_LEVEL_NONE || level > LOG_LEVEL_MAX) + return; + + m_logLevel = level; + + auto spdLevel = spdlog::level::info; + if (level <= LOG_LEVEL_NONE) + spdLevel = spdlog::level::off; + else if (level >= LOG_LEVEL_DEBUG) + spdLevel = spdlog::level::trace; + + if (m_defaultLogger != nullptr && m_defaultLogger->level() == spdLevel) + return; + + spdlog::set_level(spdLevel); + FormatAndLogInternal(spdlog::level::info, "Log level changed to \"{}\"", + spdlog::level::to_string_view(spdLevel)); +} + +bool CLog::IsLogLevelLogged(int loglevel) +{ + if (m_logLevel >= LOG_LEVEL_DEBUG) + return true; + if (m_logLevel <= LOG_LEVEL_NONE) + return false; + + return (loglevel & LOGMASK) >= LOGNOTICE; +} + +bool CLog::CanLogComponent(uint32_t component) const +{ + if (!m_componentLogEnabled || component == 0) + return false; + + return ((m_componentLogLevels & component) == component); +} + +void CLog::SettingOptionsLoggingComponentsFiller(SettingConstPtr setting, + std::vector& list, + int& current, + void* data) +{ + list.emplace_back(g_localizeStrings.Get(669), LOGSAMBA); + list.emplace_back(g_localizeStrings.Get(670), LOGCURL); + list.emplace_back(g_localizeStrings.Get(672), LOGFFMPEG); + list.emplace_back(g_localizeStrings.Get(675), LOGJSONRPC); + list.emplace_back(g_localizeStrings.Get(676), LOGAUDIO); + list.emplace_back(g_localizeStrings.Get(680), LOGVIDEO); + list.emplace_back(g_localizeStrings.Get(683), LOGAVTIMING); + list.emplace_back(g_localizeStrings.Get(684), LOGWINDOWING); + list.emplace_back(g_localizeStrings.Get(685), LOGPVR); + list.emplace_back(g_localizeStrings.Get(686), LOGEPG); + list.emplace_back(g_localizeStrings.Get(39117), LOGANNOUNCE); +#ifdef HAS_DBUS + list.emplace_back(g_localizeStrings.Get(674), LOGDBUS); +#endif +#ifdef HAS_WEB_SERVER + list.emplace_back(g_localizeStrings.Get(681), LOGWEBSERVER); +#endif +#ifdef HAS_AIRTUNES + list.emplace_back(g_localizeStrings.Get(677), LOGAIRTUNES); +#endif +#ifdef HAS_UPNP + list.emplace_back(g_localizeStrings.Get(678), LOGUPNP); +#endif +#ifdef HAVE_LIBCEC + list.emplace_back(g_localizeStrings.Get(679), LOGCEC); +#endif + list.emplace_back(g_localizeStrings.Get(682), LOGDATABASE); +} + +Logger CLog::GetLogger(const std::string& loggerName) +{ + auto logger = spdlog::get(loggerName); + if (logger == nullptr) + logger = CreateLogger(loggerName); + + return logger; +} + +CLog& CLog::GetInstance() +{ + return CServiceBroker::GetLogging(); +} + +spdlog::level::level_enum CLog::MapLogLevel(int level) +{ + switch (level) + { + case LOGDEBUG: + return spdlog::level::debug; + case LOGINFO: + case LOGNOTICE: + return spdlog::level::info; + case LOGWARNING: + return spdlog::level::warn; + case LOGERROR: + return spdlog::level::err; + case LOGSEVERE: + case LOGFATAL: + return spdlog::level::critical; + case LOGNONE: + return spdlog::level::off; + + default: + break; + } + + return spdlog::level::info; +} + +Logger CLog::CreateLogger(const std::string& loggerName) +{ + // create the logger + auto logger = std::make_shared(loggerName, m_sinks); + + // initialize the logger + spdlog::initialize_logger(logger); + + return logger; +} + +void CLog::SetComponentLogLevel(const std::vector& components) +{ + m_componentLogLevels = 0; + for (const auto& component : components) + { + if (!component.isInteger()) + continue; + + m_componentLogLevels |= static_cast(component.asInteger()); + } +} diff --git a/xbmc/utils/log.h b/xbmc/utils/log.h new file mode 100644 index 0000000..7287918 --- /dev/null +++ b/xbmc/utils/log.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +// spdlog specific defines +#define SPDLOG_LEVEL_NAMES {"TRACE", "DEBUG", "INFO", "WARNING", "ERROR", "FATAL", "OFF"}; + +#include "commons/ilog.h" +#include "settings/lib/ISettingCallback.h" +#include "settings/lib/ISettingsHandler.h" +#include "settings/lib/SettingDefinitions.h" +#include "utils/IPlatformLog.h" +#include "utils/StringUtils.h" +#include "utils/logtypes.h" + +#include +#include + +#include + +namespace spdlog +{ +namespace sinks +{ +template +class basic_file_sink; + +template +class dist_sink; +} // namespace sinks +} // namespace spdlog + +class CLog : public ISettingsHandler, public ISettingCallback +{ +public: + CLog(); + ~CLog() = default; + + // implementation of ISettingsHandler + void OnSettingsLoaded() override; + + // implementation of ISettingCallback + void OnSettingChanged(std::shared_ptr setting) override; + + void Initialize(const std::string& path); + void Uninitialize(); + + void SetLogLevel(int level); + int GetLogLevel() { return m_logLevel; } + bool IsLogLevelLogged(int loglevel); + + bool CanLogComponent(uint32_t component) const; + static void SettingOptionsLoggingComponentsFiller(std::shared_ptr setting, + std::vector& list, + int& current, + void* data); + + Logger GetLogger(const std::string& loggerName); + + template + static inline void Log(int level, const Char* format, Args&&... args) + { + Log(MapLogLevel(level), format, std::forward(args)...); + } + + template + static inline void Log(int level, uint32_t component, const Char* format, Args&&... args) + { + if (!GetInstance().CanLogComponent(component)) + return; + + Log(level, format, std::forward(args)...); + } + + template + static inline void Log(spdlog::level::level_enum level, const Char* format, Args&&... args) + { + GetInstance().FormatAndLogInternal(level, format, std::forward(args)...); + } + + template + static inline void Log(spdlog::level::level_enum level, + uint32_t component, + const Char* format, + Args&&... args) + { + if (!GetInstance().CanLogComponent(component)) + return; + + Log(level, format, std::forward(args)...); + } + + template + static inline void LogFunction(int level, + const char* functionName, + const Char* format, + Args&&... args) + { + LogFunction(MapLogLevel(level), functionName, format, std::forward(args)...); + } + + template + static inline void LogFunction( + int level, const char* functionName, uint32_t component, const Char* format, Args&&... args) + { + if (!GetInstance().CanLogComponent(component)) + return; + + LogFunction(level, functionName, format, std::forward(args)...); + } + + template + static inline void LogFunction(spdlog::level::level_enum level, + const char* functionName, + const Char* format, + Args&&... args) + { + if (functionName == nullptr || strlen(functionName) == 0) + GetInstance().FormatAndLogInternal(level, format, std::forward(args)...); + else + GetInstance().FormatAndLogFunctionInternal(level, functionName, format, + std::forward(args)...); + } + + template + static inline void LogFunction(spdlog::level::level_enum level, + const char* functionName, + uint32_t component, + const Char* format, + Args&&... args) + { + if (!GetInstance().CanLogComponent(component)) + return; + + LogFunction(level, functionName, format, std::forward(args)...); + } + +#define LogF(level, format, ...) LogFunction((level), __FUNCTION__, (format), ##__VA_ARGS__) +#define LogFC(level, component, format, ...) \ + LogFunction((level), __FUNCTION__, (component), (format), ##__VA_ARGS__) + +private: + static CLog& GetInstance(); + + static spdlog::level::level_enum MapLogLevel(int level); + + template + static inline void FormatAndLogFunctionInternal(spdlog::level::level_enum level, + const char* functionName, + const char* format, + Args&&... args) + { + GetInstance().FormatAndLogInternal( + level, StringUtils::Format("{0:s}: {1:s}", functionName, format).c_str(), + std::forward(args)...); + } + + template + static inline void FormatAndLogFunctionInternal(spdlog::level::level_enum level, + const char* functionName, + const wchar_t* format, + Args&&... args) + { + GetInstance().FormatAndLogInternal( + level, StringUtils::Format(L"{0:s}: {1:s}", functionName, format).c_str(), + std::forward(args)...); + } + + template + inline void FormatAndLogInternal(spdlog::level::level_enum level, + const Char* format, + Args&&... args) + { + // TODO: for now we manually format the messages to support both python- and printf-style formatting. + // this can be removed once all log messages have been adjusted to python-style formatting + auto logString = StringUtils::Format(format, std::forward(args)...); + + // fixup newline alignment, number of spaces should equal prefix length + StringUtils::Replace(logString, "\n", "\n "); + + m_defaultLogger->log(level, std::move(logString)); + } + + Logger CreateLogger(const std::string& loggerName); + + void SetComponentLogLevel(const std::vector& components); + + std::unique_ptr m_platform; + std::shared_ptr> m_sinks; + Logger m_defaultLogger; + + std::shared_ptr> m_fileSink; + + int m_logLevel; + + bool m_componentLogEnabled; + uint32_t m_componentLogLevels; +}; + +namespace XbmcUtils +{ +class LogImplementation : public XbmcCommons::ILogger +{ +public: + ~LogImplementation() override = default; + inline void log(int logLevel, IN_STRING const char* message) override + { + CLog::Log(logLevel, "{0:s}", message); + } +}; +} // namespace XbmcUtils diff --git a/xbmc/utils/logtypes.h b/xbmc/utils/logtypes.h new file mode 100644 index 0000000..f41aa7e --- /dev/null +++ b/xbmc/utils/logtypes.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include + +namespace spdlog +{ +class logger; +} + +using Logger = std::shared_ptr; diff --git a/xbmc/utils/params_check_macros.h b/xbmc/utils/params_check_macros.h new file mode 100644 index 0000000..30f2355 --- /dev/null +++ b/xbmc/utils/params_check_macros.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2014-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +// macros for gcc, clang & others +#ifndef PARAM1_PRINTF_FORMAT +#ifdef __GNUC__ +// for use in functions that take printf format string as first parameter and additional printf parameters as second parameter +// for example: int myprintf(const char* format, ...) PARAM1_PRINTF_FORMAT; +#define PARAM1_PRINTF_FORMAT __attribute__((format(printf,1,2))) + +// for use in functions that take printf format string as second parameter and additional printf parameters as third parameter +// for example: bool log_string(int logLevel, const char* format, ...) PARAM2_PRINTF_FORMAT; +// note: all non-static class member functions take pointer to class object as hidden first parameter +#define PARAM2_PRINTF_FORMAT __attribute__((format(printf,2,3))) + +// for use in functions that take printf format string as third parameter and additional printf parameters as fourth parameter +// note: all non-static class member functions take pointer to class object as hidden first parameter +// for example: class A { bool log_string(int logLevel, const char* functionName, const char* format, ...) PARAM3_PRINTF_FORMAT; }; +#define PARAM3_PRINTF_FORMAT __attribute__((format(printf,3,4))) + +// for use in functions that take printf format string as fourth parameter and additional printf parameters as fith parameter +// note: all non-static class member functions take pointer to class object as hidden first parameter +// for example: class A { bool log_string(int logLevel, const char* functionName, int component, const char* format, ...) PARAM4_PRINTF_FORMAT; }; +#define PARAM4_PRINTF_FORMAT __attribute__((format(printf,4,5))) +#else // ! __GNUC__ +#define PARAM1_PRINTF_FORMAT +#define PARAM2_PRINTF_FORMAT +#define PARAM3_PRINTF_FORMAT +#define PARAM4_PRINTF_FORMAT +#endif // ! __GNUC__ +#endif // PARAM1_PRINTF_FORMAT + +// macros for VC +// VC check parameters only when "Code Analysis" is called +#ifndef PRINTF_FORMAT_STRING +#ifdef _MSC_VER +#include + +// for use in any function that take printf format string and parameters +// for example: bool log_string(int logLevel, PRINTF_FORMAT_STRING const char* format, ...); +#define PRINTF_FORMAT_STRING _In_z_ _Printf_format_string_ + +// specify that parameter must be zero-terminated string +// for example: void SetName(IN_STRING const char* newName); +#define IN_STRING _In_z_ + +// specify that parameter must be zero-terminated string or NULL +// for example: bool SetAdditionalName(IN_OPT_STRING const char* addName); +#define IN_OPT_STRING _In_opt_z_ +#else // ! _MSC_VER +#define PRINTF_FORMAT_STRING +#define IN_STRING +#define IN_OPT_STRING +#endif // ! _MSC_VER +#endif // PRINTF_FORMAT_STRING diff --git a/xbmc/utils/rfft.cpp b/xbmc/utils/rfft.cpp new file mode 100644 index 0000000..871eea7 --- /dev/null +++ b/xbmc/utils/rfft.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "rfft.h" + +#if defined(TARGET_WINDOWS) && !defined(_USE_MATH_DEFINES) +#define _USE_MATH_DEFINES +#endif +#include + +RFFT::RFFT(int size, bool windowed) : + m_size(size), m_windowed(windowed) +{ + m_cfg = kiss_fftr_alloc(m_size,0,nullptr,nullptr); +} + +RFFT::~RFFT() +{ + // we don' use kiss_fftr_free here because + // its hardcoded to free and doesn't pay attention + // to SIMD (which might be used during kiss_fftr_alloc + //in the C'tor). + KISS_FFT_FREE(m_cfg); +} + +void RFFT::calc(const float* input, float* output) +{ + // temporary buffers + std::vector linput(m_size), rinput(m_size); + std::vector loutput(m_size), routput(m_size); + + for (size_t i=0;i + +void RFFT::hann(std::vector& data) +{ + for (size_t i=0;i + +//! \brief Class performing a RFFT of interleaved stereo data. +class RFFT +{ +public: + //! \brief The constructor creates a RFFT plan. + //! \brief size Length of time data for a single channel. + //! \brief windowed Whether or not to apply a Hann window to data. + RFFT(int size, bool windowed=false); + + //! \brief Free the RFFT plan + ~RFFT(); + + //! \brief Calculate FFTs + //! \param input Input data of size 2*m_size + //! \param output Output data of size m_size. + void calc(const float* input, float* output); +protected: + //! \brief Apply a Hann window to a buffer. + //! \param data Vector with data to apply window to. + static void hann(std::vector& data); + + size_t m_size; //!< Size for a single channel. + bool m_windowed; //!< Whether or not a Hann window is applied. + kiss_fftr_cfg m_cfg; //!< FFT plan +}; diff --git a/xbmc/utils/test/CMakeLists.txt b/xbmc/utils/test/CMakeLists.txt new file mode 100644 index 0000000..e953af6 --- /dev/null +++ b/xbmc/utils/test/CMakeLists.txt @@ -0,0 +1,53 @@ +set(SOURCES TestAlarmClock.cpp + TestAliasShortcutUtils.cpp + TestArchive.cpp + TestBase64.cpp + TestBitstreamStats.cpp + TestCharsetConverter.cpp + TestCPUInfo.cpp + TestCrc32.cpp + TestDatabaseUtils.cpp + TestDigest.cpp + TestEndianSwap.cpp + TestFileOperationJob.cpp + TestFileUtils.cpp + TestGlobalsHandling.cpp + TestHTMLUtil.cpp + TestHttpHeader.cpp + TestHttpParser.cpp + TestHttpRangeUtils.cpp + TestHttpResponse.cpp + TestJobManager.cpp + TestJSONVariantParser.cpp + TestJSONVariantWriter.cpp + TestLabelFormatter.cpp + TestLangCodeExpander.cpp + TestLocale.cpp + Testlog.cpp + TestMathUtils.cpp + TestMime.cpp + TestPOUtils.cpp + TestRegExp.cpp + Testrfft.cpp + TestRingBuffer.cpp + TestScraperParser.cpp + TestScraperUrl.cpp + TestSortUtils.cpp + TestStopwatch.cpp + TestStreamDetails.cpp + TestStreamUtils.cpp + TestStringUtils.cpp + TestSystemInfo.cpp + TestURIUtils.cpp + TestUrlOptions.cpp + TestVariant.cpp + TestXBMCTinyXML.cpp + TestXMLUtils.cpp) + +set(HEADERS TestGlobalsHandlingPattern1.h) + +if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) + list(APPEND SOURCES TestCryptThreading.cpp) +endif() + +core_add_test_library(utils_test) diff --git a/xbmc/utils/test/CXBMCTinyXML-test.xml b/xbmc/utils/test/CXBMCTinyXML-test.xml new file mode 100644 index 0000000..9444dc8 --- /dev/null +++ b/xbmc/utils/test/CXBMCTinyXML-test.xml @@ -0,0 +1,6 @@ + +
+ + http://api.themoviedb.org/3/movie/12244?api_key=57983e31fb435df4df77afb854740ea9&language=en??? + +
diff --git a/xbmc/utils/test/TestAlarmClock.cpp b/xbmc/utils/test/TestAlarmClock.cpp new file mode 100644 index 0000000..75ea84a --- /dev/null +++ b/xbmc/utils/test/TestAlarmClock.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/AlarmClock.h" + +#include + +TEST(TestAlarmClock, General) +{ + CAlarmClock a; + EXPECT_FALSE(a.IsRunning()); + EXPECT_FALSE(a.HasAlarm("test")); + a.Start("test", 100.f, "test"); + EXPECT_TRUE(a.IsRunning()); + EXPECT_TRUE(a.HasAlarm("test")); + EXPECT_FALSE(a.HasAlarm("test2")); + EXPECT_NE(0.f, a.GetRemaining("test")); + EXPECT_EQ(0.f, a.GetRemaining("test2")); + a.Stop("test"); +} diff --git a/xbmc/utils/test/TestAliasShortcutUtils.cpp b/xbmc/utils/test/TestAliasShortcutUtils.cpp new file mode 100644 index 0000000..d36fd41 --- /dev/null +++ b/xbmc/utils/test/TestAliasShortcutUtils.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/AliasShortcutUtils.h" +#include "filesystem/File.h" +#include "test/TestUtils.h" + +#if defined(TARGET_DARWIN_OSX) +#include "platform/darwin/DarwinUtils.h" +#endif +#include + +TEST(TestAliasShortcutUtils, IsAliasShortcut) +{ + XFILE::CFile *tmpFile = XBMC_CREATETEMPFILE("noaliastest"); + std::string noalias = XBMC_TEMPFILEPATH(tmpFile); + +#if defined(TARGET_DARWIN_OSX) + XFILE::CFile *aliasDestFile = XBMC_CREATETEMPFILE("aliastest"); + std::string alias = XBMC_TEMPFILEPATH(aliasDestFile); + + //we only need the path here so delete the alias file + //which will be recreated as shortcut later: + XBMC_DELETETEMPFILE(aliasDestFile); + + // create alias from a pointing to /Volumes + CDarwinUtils::CreateAliasShortcut(alias, "/Volumes"); + EXPECT_TRUE(IsAliasShortcut(alias, true)); + XFILE::CFile::Delete(alias); + + // volumes is not a shortcut but a dir + EXPECT_FALSE(IsAliasShortcut("/Volumes", true)); +#endif + + // a regular file is not a shortcut + EXPECT_FALSE(IsAliasShortcut(noalias, false)); + XBMC_DELETETEMPFILE(tmpFile); + + // empty string is not an alias + std::string emptyString; + EXPECT_FALSE(IsAliasShortcut(emptyString, false)); + + // non-existent file is no alias + std::string nonExistingFile="/IDontExistsNormally/somefile.txt"; + EXPECT_FALSE(IsAliasShortcut(nonExistingFile, false)); +} + +TEST(TestAliasShortcutUtils, TranslateAliasShortcut) +{ + XFILE::CFile *tmpFile = XBMC_CREATETEMPFILE("noaliastest"); + std::string noalias = XBMC_TEMPFILEPATH(tmpFile); + std::string noaliastemp = noalias; + +#if defined(TARGET_DARWIN_OSX) + XFILE::CFile *aliasDestFile = XBMC_CREATETEMPFILE("aliastest"); + std::string alias = XBMC_TEMPFILEPATH(aliasDestFile); + + //we only need the path here so delete the alias file + //which will be recreated as shortcut later: + XBMC_DELETETEMPFILE(aliasDestFile); + + // create alias from a pointing to /Volumes + CDarwinUtils::CreateAliasShortcut(alias, "/Volumes"); + + // resolve the shortcut + TranslateAliasShortcut(alias); + EXPECT_STREQ("/Volumes", alias.c_str()); + XFILE::CFile::Delete(alias); +#endif + + // translating a non-shortcut url should result in no change... + TranslateAliasShortcut(noaliastemp); + EXPECT_STREQ(noaliastemp.c_str(), noalias.c_str()); + XBMC_DELETETEMPFILE(tmpFile); + + //translate empty should stay empty + std::string emptyString; + TranslateAliasShortcut(emptyString); + EXPECT_STREQ("", emptyString.c_str()); + + // translate non-existent file should result in no change... + std::string nonExistingFile="/IDontExistsNormally/somefile.txt"; + std::string resolvedNonExistingFile=nonExistingFile; + TranslateAliasShortcut(resolvedNonExistingFile); + EXPECT_STREQ(resolvedNonExistingFile.c_str(), nonExistingFile.c_str()); +} diff --git a/xbmc/utils/test/TestArchive.cpp b/xbmc/utils/test/TestArchive.cpp new file mode 100644 index 0000000..65023fd --- /dev/null +++ b/xbmc/utils/test/TestArchive.cpp @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#if defined(TARGET_WINDOWS) +# include +#endif + +#include "utils/Archive.h" +#include "utils/Variant.h" +#include "filesystem/File.h" + +#include "test/TestUtils.h" + +#include + +class TestArchive : public testing::Test +{ +protected: + TestArchive() + { + file = XBMC_CREATETEMPFILE(".ar"); + } + ~TestArchive() override + { + EXPECT_TRUE(XBMC_DELETETEMPFILE(file)); + } + XFILE::CFile *file; +}; + +TEST_F(TestArchive, IsStoring) +{ + ASSERT_NE(nullptr, file); + CArchive arstore(file, CArchive::store); + EXPECT_TRUE(arstore.IsStoring()); + EXPECT_FALSE(arstore.IsLoading()); + arstore.Close(); +} + +TEST_F(TestArchive, IsLoading) +{ + ASSERT_NE(nullptr, file); + CArchive arload(file, CArchive::load); + EXPECT_TRUE(arload.IsLoading()); + EXPECT_FALSE(arload.IsStoring()); + arload.Close(); +} + +TEST_F(TestArchive, FloatArchive) +{ + ASSERT_NE(nullptr, file); + float float_ref = 1, float_var = 0; + + CArchive arstore(file, CArchive::store); + arstore << float_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> float_var; + arload.Close(); + + EXPECT_EQ(float_ref, float_var); +} + +TEST_F(TestArchive, DoubleArchive) +{ + ASSERT_NE(nullptr, file); + double double_ref = 2, double_var = 0; + + CArchive arstore(file, CArchive::store); + arstore << double_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> double_var; + arload.Close(); + + EXPECT_EQ(double_ref, double_var); +} + +TEST_F(TestArchive, IntegerArchive) +{ + ASSERT_NE(nullptr, file); + int int_ref = 3, int_var = 0; + + CArchive arstore(file, CArchive::store); + arstore << int_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> int_var; + arload.Close(); + + EXPECT_EQ(int_ref, int_var); +} + +TEST_F(TestArchive, UnsignedIntegerArchive) +{ + ASSERT_NE(nullptr, file); + unsigned int unsigned_int_ref = 4, unsigned_int_var = 0; + + CArchive arstore(file, CArchive::store); + arstore << unsigned_int_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> unsigned_int_var; + arload.Close(); + + EXPECT_EQ(unsigned_int_ref, unsigned_int_var); +} + +TEST_F(TestArchive, Int64tArchive) +{ + ASSERT_NE(nullptr, file); + int64_t int64_t_ref = 5, int64_t_var = 0; + + CArchive arstore(file, CArchive::store); + arstore << int64_t_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> int64_t_var; + arload.Close(); + + EXPECT_EQ(int64_t_ref, int64_t_var); +} + +TEST_F(TestArchive, UInt64tArchive) +{ + ASSERT_NE(nullptr, file); + uint64_t uint64_t_ref = 6, uint64_t_var = 0; + + CArchive arstore(file, CArchive::store); + arstore << uint64_t_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> uint64_t_var; + arload.Close(); + + EXPECT_EQ(uint64_t_ref, uint64_t_var); +} + +TEST_F(TestArchive, BoolArchive) +{ + ASSERT_NE(nullptr, file); + bool bool_ref = true, bool_var = false; + + CArchive arstore(file, CArchive::store); + arstore << bool_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> bool_var; + arload.Close(); + + EXPECT_EQ(bool_ref, bool_var); +} + +TEST_F(TestArchive, CharArchive) +{ + ASSERT_NE(nullptr, file); + char char_ref = 'A', char_var = '\0'; + + CArchive arstore(file, CArchive::store); + arstore << char_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> char_var; + arload.Close(); + + EXPECT_EQ(char_ref, char_var); +} + +TEST_F(TestArchive, WStringArchive) +{ + ASSERT_NE(nullptr, file); + std::wstring wstring_ref = L"test wstring", wstring_var; + + CArchive arstore(file, CArchive::store); + arstore << wstring_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> wstring_var; + arload.Close(); + + EXPECT_STREQ(wstring_ref.c_str(), wstring_var.c_str()); +} + +TEST_F(TestArchive, StringArchive) +{ + ASSERT_NE(nullptr, file); + std::string string_ref = "test string", string_var; + + CArchive arstore(file, CArchive::store); + arstore << string_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> string_var; + arload.Close(); + + EXPECT_STREQ(string_ref.c_str(), string_var.c_str()); +} + +TEST_F(TestArchive, SystemTimeArchive) +{ + ASSERT_NE(nullptr, file); + KODI::TIME::SystemTime SystemTime_ref = {1, 2, 3, 4, 5, 6, 7, 8}; + KODI::TIME::SystemTime SystemTime_var = {0, 0, 0, 0, 0, 0, 0, 0}; + + CArchive arstore(file, CArchive::store); + arstore << SystemTime_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> SystemTime_var; + arload.Close(); + + EXPECT_TRUE(!memcmp(&SystemTime_ref, &SystemTime_var, sizeof(KODI::TIME::SystemTime))); +} + +TEST_F(TestArchive, CVariantArchive) +{ + ASSERT_NE(nullptr, file); + CVariant CVariant_ref((int)1), CVariant_var; + + CArchive arstore(file, CArchive::store); + arstore << CVariant_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> CVariant_var; + arload.Close(); + + EXPECT_TRUE(CVariant_var.isInteger()); + EXPECT_EQ(1, CVariant_var.asInteger()); +} + +TEST_F(TestArchive, CVariantArchiveString) +{ + ASSERT_NE(nullptr, file); + CVariant CVariant_ref("teststring"), CVariant_var; + + CArchive arstore(file, CArchive::store); + arstore << CVariant_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> CVariant_var; + arload.Close(); + + EXPECT_TRUE(CVariant_var.isString()); + EXPECT_STREQ("teststring", CVariant_var.asString().c_str()); +} + +TEST_F(TestArchive, StringVectorArchive) +{ + ASSERT_NE(nullptr, file); + std::vector strArray_ref, strArray_var; + strArray_ref.emplace_back("test strArray_ref 0"); + strArray_ref.emplace_back("test strArray_ref 1"); + strArray_ref.emplace_back("test strArray_ref 2"); + strArray_ref.emplace_back("test strArray_ref 3"); + + CArchive arstore(file, CArchive::store); + arstore << strArray_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> strArray_var; + arload.Close(); + + EXPECT_STREQ("test strArray_ref 0", strArray_var.at(0).c_str()); + EXPECT_STREQ("test strArray_ref 1", strArray_var.at(1).c_str()); + EXPECT_STREQ("test strArray_ref 2", strArray_var.at(2).c_str()); + EXPECT_STREQ("test strArray_ref 3", strArray_var.at(3).c_str()); +} + +TEST_F(TestArchive, IntegerVectorArchive) +{ + ASSERT_NE(nullptr, file); + std::vector iArray_ref, iArray_var; + iArray_ref.push_back(0); + iArray_ref.push_back(1); + iArray_ref.push_back(2); + iArray_ref.push_back(3); + + CArchive arstore(file, CArchive::store); + arstore << iArray_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> iArray_var; + arload.Close(); + + EXPECT_EQ(0, iArray_var.at(0)); + EXPECT_EQ(1, iArray_var.at(1)); + EXPECT_EQ(2, iArray_var.at(2)); + EXPECT_EQ(3, iArray_var.at(3)); +} + +TEST_F(TestArchive, MultiTypeArchive) +{ + ASSERT_NE(nullptr, file); + float float_ref = 1, float_var = 0; + double double_ref = 2, double_var = 0; + int int_ref = 3, int_var = 0; + unsigned int unsigned_int_ref = 4, unsigned_int_var = 0; + int64_t int64_t_ref = 5, int64_t_var = 0; + uint64_t uint64_t_ref = 6, uint64_t_var = 0; + bool bool_ref = true, bool_var = false; + char char_ref = 'A', char_var = '\0'; + std::string string_ref = "test string", string_var; + std::wstring wstring_ref = L"test wstring", wstring_var; + KODI::TIME::SystemTime SystemTime_ref = {1, 2, 3, 4, 5, 6, 7, 8}; + KODI::TIME::SystemTime SystemTime_var = {0, 0, 0, 0, 0, 0, 0, 0}; + CVariant CVariant_ref((int)1), CVariant_var; + std::vector strArray_ref, strArray_var; + strArray_ref.emplace_back("test strArray_ref 0"); + strArray_ref.emplace_back("test strArray_ref 1"); + strArray_ref.emplace_back("test strArray_ref 2"); + strArray_ref.emplace_back("test strArray_ref 3"); + std::vector iArray_ref, iArray_var; + iArray_ref.push_back(0); + iArray_ref.push_back(1); + iArray_ref.push_back(2); + iArray_ref.push_back(3); + + CArchive arstore(file, CArchive::store); + EXPECT_TRUE(arstore.IsStoring()); + EXPECT_FALSE(arstore.IsLoading()); + arstore << float_ref; + arstore << double_ref; + arstore << int_ref; + arstore << unsigned_int_ref; + arstore << int64_t_ref; + arstore << uint64_t_ref; + arstore << bool_ref; + arstore << char_ref; + arstore << string_ref; + arstore << wstring_ref; + arstore << SystemTime_ref; + arstore << CVariant_ref; + arstore << strArray_ref; + arstore << iArray_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + EXPECT_TRUE(arload.IsLoading()); + EXPECT_FALSE(arload.IsStoring()); + arload >> float_var; + arload >> double_var; + arload >> int_var; + arload >> unsigned_int_var; + arload >> int64_t_var; + arload >> uint64_t_var; + arload >> bool_var; + arload >> char_var; + arload >> string_var; + arload >> wstring_var; + arload >> SystemTime_var; + arload >> CVariant_var; + arload >> strArray_var; + arload >> iArray_var; + arload.Close(); + + EXPECT_EQ(float_ref, float_var); + EXPECT_EQ(double_ref, double_var); + EXPECT_EQ(int_ref, int_var); + EXPECT_EQ(unsigned_int_ref, unsigned_int_var); + EXPECT_EQ(int64_t_ref, int64_t_var); + EXPECT_EQ(uint64_t_ref, uint64_t_var); + EXPECT_EQ(bool_ref, bool_var); + EXPECT_EQ(char_ref, char_var); + EXPECT_STREQ(string_ref.c_str(), string_var.c_str()); + EXPECT_STREQ(wstring_ref.c_str(), wstring_var.c_str()); + EXPECT_TRUE(!memcmp(&SystemTime_ref, &SystemTime_var, sizeof(KODI::TIME::SystemTime))); + EXPECT_TRUE(CVariant_var.isInteger()); + EXPECT_STREQ("test strArray_ref 0", strArray_var.at(0).c_str()); + EXPECT_STREQ("test strArray_ref 1", strArray_var.at(1).c_str()); + EXPECT_STREQ("test strArray_ref 2", strArray_var.at(2).c_str()); + EXPECT_STREQ("test strArray_ref 3", strArray_var.at(3).c_str()); + EXPECT_EQ(0, iArray_var.at(0)); + EXPECT_EQ(1, iArray_var.at(1)); + EXPECT_EQ(2, iArray_var.at(2)); + EXPECT_EQ(3, iArray_var.at(3)); +} diff --git a/xbmc/utils/test/TestBase64.cpp b/xbmc/utils/test/TestBase64.cpp new file mode 100644 index 0000000..8416378 --- /dev/null +++ b/xbmc/utils/test/TestBase64.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/Base64.h" + +#include + +static const char refdata[] = "\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18" + "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20" + "\x21\x22\x23\x24\x25\x26\x27\x28" + "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"; + +static const char refbase64data[] = "AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY" + "GRobHB0eHyAhIiMkJSYnKCkqKywtLi8w"; + +TEST(TestBase64, Encode_1) +{ + std::string a; + Base64::Encode(refdata, sizeof(refdata) - 1, a); + EXPECT_STREQ(refbase64data, a.c_str()); +} + +TEST(TestBase64, Encode_2) +{ + std::string a; + a = Base64::Encode(refdata, sizeof(refdata) - 1); + EXPECT_STREQ(refbase64data, a.c_str()); +} + +TEST(TestBase64, Encode_3) +{ + std::string a; + Base64::Encode(refdata, a); + EXPECT_STREQ(refbase64data, a.c_str()); +} + +TEST(TestBase64, Encode_4) +{ + std::string a; + a = Base64::Encode(refdata); + EXPECT_STREQ(refbase64data, a.c_str()); +} + +TEST(TestBase64, Decode_1) +{ + std::string a; + Base64::Decode(refbase64data, sizeof(refbase64data) - 1, a); + EXPECT_STREQ(refdata, a.c_str()); +} + +TEST(TestBase64, Decode_2) +{ + std::string a; + a = Base64::Decode(refbase64data, sizeof(refbase64data) - 1); + EXPECT_STREQ(refdata, a.c_str()); +} + +TEST(TestBase64, Decode_3) +{ + std::string a; + Base64::Decode(refbase64data, a); + EXPECT_STREQ(refdata, a.c_str()); +} + +TEST(TestBase64, Decode_4) +{ + std::string a; + a = Base64::Decode(refbase64data); + EXPECT_STREQ(refdata, a.c_str()); +} diff --git a/xbmc/utils/test/TestBitstreamStats.cpp b/xbmc/utils/test/TestBitstreamStats.cpp new file mode 100644 index 0000000..69e4c88 --- /dev/null +++ b/xbmc/utils/test/TestBitstreamStats.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "threads/Thread.h" +#include "utils/BitstreamStats.h" + +#include + +#define BITS (256 * 8) +#define BYTES (256) + +class CTestBitstreamStatsThread : public CThread +{ +public: + CTestBitstreamStatsThread() : + CThread("TestBitstreamStats"){} + +}; + +TEST(TestBitstreamStats, General) +{ + int i; + BitstreamStats a; + CTestBitstreamStatsThread t; + + i = 0; + a.Start(); + EXPECT_EQ(0.0, a.GetBitrate()); + EXPECT_EQ(0.0, a.GetMaxBitrate()); + EXPECT_EQ(-1.0, a.GetMinBitrate()); + while (i <= BITS) + { + a.AddSampleBits(1); + i++; + t.Sleep(1); + } + a.CalculateBitrate(); + EXPECT_GT(a.GetBitrate(), 0.0); + EXPECT_GT(a.GetMaxBitrate(), 0.0); + EXPECT_GT(a.GetMinBitrate(), 0.0); + + i = 0; + while (i <= BYTES) + { + a.AddSampleBytes(1); + t.Sleep(2); + i++; + } + a.CalculateBitrate(); + EXPECT_GT(a.GetBitrate(), 0.0); + EXPECT_GT(a.GetMaxBitrate(), 0.0); + EXPECT_LE(a.GetMinBitrate(), a.GetMaxBitrate()); +} diff --git a/xbmc/utils/test/TestCPUInfo.cpp b/xbmc/utils/test/TestCPUInfo.cpp new file mode 100644 index 0000000..bd9572a --- /dev/null +++ b/xbmc/utils/test/TestCPUInfo.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#if defined(TARGET_WINDOWS) +# include +#endif + +#include "ServiceBroker.h" +#include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" +#include "utils/CPUInfo.h" +#include "utils/Temperature.h" +#include "utils/XTimeUtils.h" + +#include + +struct TestCPUInfo : public ::testing::Test +{ + TestCPUInfo() { CServiceBroker::RegisterCPUInfo(CCPUInfo::GetCPUInfo()); } + + ~TestCPUInfo() { CServiceBroker::UnregisterCPUInfo(); } +}; + +TEST_F(TestCPUInfo, GetUsedPercentage) +{ + EXPECT_GE(CServiceBroker::GetCPUInfo()->GetUsedPercentage(), 0); +} + +TEST_F(TestCPUInfo, GetCPUCount) +{ + EXPECT_GT(CServiceBroker::GetCPUInfo()->GetCPUCount(), 0); +} + +TEST_F(TestCPUInfo, GetCPUFrequency) +{ + EXPECT_GE(CServiceBroker::GetCPUInfo()->GetCPUFrequency(), 0.f); +} + +#if defined(TARGET_WINDOWS) +TEST_F(TestCPUInfo, DISABLED_GetTemperature) +#else +TEST_F(TestCPUInfo, GetTemperature) +#endif +{ + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_cpuTempCmd = "echo '50 c'"; + CTemperature t; + EXPECT_TRUE(CServiceBroker::GetCPUInfo()->GetTemperature(t)); + EXPECT_TRUE(t.IsValid()); +} + +TEST_F(TestCPUInfo, CoreInfo) +{ + ASSERT_TRUE(CServiceBroker::GetCPUInfo()->HasCoreId(0)); + const CoreInfo c = CServiceBroker::GetCPUInfo()->GetCoreInfo(0); + EXPECT_TRUE(c.m_id == 0); +} + +TEST_F(TestCPUInfo, GetCoresUsageString) +{ + EXPECT_STRNE("", CServiceBroker::GetCPUInfo()->GetCoresUsageString().c_str()); +} + +TEST_F(TestCPUInfo, GetCPUFeatures) +{ + unsigned int a = CServiceBroker::GetCPUInfo()->GetCPUFeatures(); + (void)a; +} diff --git a/xbmc/utils/test/TestCharsetConverter.cpp b/xbmc/utils/test/TestCharsetConverter.cpp new file mode 100644 index 0000000..f8736b7 --- /dev/null +++ b/xbmc/utils/test/TestCharsetConverter.cpp @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ServiceBroker.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/CharsetConverter.h" +#include "utils/Utf8Utils.h" + +#include + +#if 0 +static const uint16_t refutf16LE1[] = { 0xff54, 0xff45, 0xff53, 0xff54, + 0xff3f, 0xff55, 0xff54, 0xff46, + 0xff11, 0xff16, 0xff2c, 0xff25, + 0xff54, 0xff4f, 0xff57, 0x0 }; + +static const uint16_t refutf16LE2[] = { 0xff54, 0xff45, 0xff53, 0xff54, + 0xff3f, 0xff55, 0xff54, 0xff46, + 0xff18, 0xff34, 0xff4f, 0xff1a, + 0xff3f, 0xff43, 0xff48, 0xff41, + 0xff52, 0xff53, 0xff45, 0xff54, + 0xff3f, 0xff35, 0xff34, 0xff26, + 0xff0d, 0xff11, 0xff16, 0xff2c, + 0xff25, 0xff0c, 0xff3f, 0xff23, + 0xff33, 0xff54, 0xff44, 0xff33, + 0xff54, 0xff52, 0xff49, 0xff4e, + 0xff47, 0xff11, 0xff16, 0x0 }; +#endif + +static const char refutf16LE3[] = "T\377E\377S\377T\377?\377S\377T\377" + "R\377I\377N\377G\377#\377H\377A\377" + "R\377S\377E\377T\377\064\377O\377\065" + "\377T\377F\377\030\377"; + +#if 0 +static const uint16_t refutf16LE4[] = { 0xff54, 0xff45, 0xff53, 0xff54, + 0xff3f, 0xff55, 0xff54, 0xff46, + 0xff11, 0xff16, 0xff2c, 0xff25, + 0xff54, 0xff4f, 0xff35, 0xff34, + 0xff26, 0xff18, 0x0 }; + +static const uint32_t refutf32LE1[] = { 0xff54, 0xff45, 0xff53, 0xff54, + 0xff3f, 0xff55, 0xff54, 0xff46, + 0xff18, 0xff34, 0xff4f, 0xff1a, + 0xff3f, 0xff43, 0xff48, 0xff41, + 0xff52, 0xff53, 0xff45, 0xff54, + 0xff3f, 0xff35, 0xff34, 0xff26, + 0xff0d, 0xff13, 0xff12, 0xff2c, + 0xff25, 0xff0c, 0xff3f, 0xff23, + 0xff33, 0xff54, 0xff44, 0xff33, + 0xff54, 0xff52, 0xff49, 0xff4e, + 0xff47, 0xff13, 0xff12, 0xff3f, +#ifdef TARGET_DARWIN + 0x0 }; +#else + 0x1f42d, 0x1f42e, 0x0 }; +#endif + +static const uint16_t refutf16BE[] = { 0x54ff, 0x45ff, 0x53ff, 0x54ff, + 0x3fff, 0x55ff, 0x54ff, 0x46ff, + 0x11ff, 0x16ff, 0x22ff, 0x25ff, + 0x54ff, 0x4fff, 0x35ff, 0x34ff, + 0x26ff, 0x18ff, 0x0}; + +static const uint16_t refucs2[] = { 0xff54, 0xff45, 0xff53, 0xff54, + 0xff3f, 0xff55, 0xff43, 0xff53, + 0xff12, 0xff54, 0xff4f, 0xff35, + 0xff34, 0xff26, 0xff18, 0x0 }; +#endif + +class TestCharsetConverter : public testing::Test +{ +protected: + TestCharsetConverter() + { + /* Add default settings for locale. + * Settings here are taken from CGUISettings::Initialize() + */ + /* + //! @todo implement + CSettingsCategory *loc = CServiceBroker::GetSettingsComponent()->GetSettings()->AddCategory(7, "locale", 14090); + CServiceBroker::GetSettingsComponent()->GetSettings()->AddString(loc, CSettings::SETTING_LOCALE_LANGUAGE,248,"english", + SPIN_CONTROL_TEXT); + CServiceBroker::GetSettingsComponent()->GetSettings()->AddString(loc, CSettings::SETTING_LOCALE_COUNTRY, 20026, "USA", + SPIN_CONTROL_TEXT); + CServiceBroker::GetSettingsComponent()->GetSettings()->AddString(loc, CSettings::SETTING_LOCALE_CHARSET, 14091, "DEFAULT", + SPIN_CONTROL_TEXT); // charset is set by the + // language file + + // Add default settings for subtitles + CSettingsCategory *sub = CServiceBroker::GetSettingsComponent()->GetSettings()->AddCategory(5, "subtitles", 287); + CServiceBroker::GetSettingsComponent()->GetSettings()->AddString(sub, CSettings::SETTING_SUBTITLES_CHARSET, 735, "DEFAULT", + SPIN_CONTROL_TEXT); + */ + g_charsetConverter.reset(); + g_charsetConverter.clear(); + } + + ~TestCharsetConverter() override + { + CServiceBroker::GetSettingsComponent()->GetSettings()->Unload(); + } + + std::string refstra1, refstra2, varstra1; + std::wstring refstrw1, varstrw1; + std::string refstr1; +}; + +TEST_F(TestCharsetConverter, utf8ToW) +{ + refstra1 = "test utf8ToW"; + refstrw1 = L"test utf8ToW"; + varstrw1.clear(); + g_charsetConverter.utf8ToW(refstra1, varstrw1, true, false, false); + EXPECT_STREQ(refstrw1.c_str(), varstrw1.c_str()); +} + + +//TEST_F(TestCharsetConverter, utf16LEtoW) +//{ +// refstrw1 = L"test_utf16LEtow"; +// //! @todo Should be able to use '=' operator instead of assign() +// std::wstring refstr16_1; +// refstr16_1.assign(refutf16LE1); +// varstrw1.clear(); +// g_charsetConverter.utf16LEtoW(refstr16_1, varstrw1); +// EXPECT_STREQ(refstrw1.c_str(), varstrw1.c_str()); +//} + +TEST_F(TestCharsetConverter, subtitleCharsetToUtf8) +{ + refstra1 = "test subtitleCharsetToW"; + varstra1.clear(); + g_charsetConverter.subtitleCharsetToUtf8(refstra1, varstra1); + + /* Assign refstra1 to refstrw1 so that we can compare */ + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, utf8ToStringCharset_1) +{ + refstra1 = "test utf8ToStringCharset"; + varstra1.clear(); + g_charsetConverter.utf8ToStringCharset(refstra1, varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, utf8ToStringCharset_2) +{ + refstra1 = "test utf8ToStringCharset"; + varstra1 = "test utf8ToStringCharset"; + g_charsetConverter.utf8ToStringCharset(varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, utf8ToSystem) +{ + refstra1 = "test utf8ToSystem"; + varstra1 = "test utf8ToSystem"; + g_charsetConverter.utf8ToSystem(varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, utf8To_ASCII) +{ + refstra1 = "test utf8To: charset ASCII, std::string"; + varstra1.clear(); + g_charsetConverter.utf8To("ASCII", refstra1, varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +/* +TEST_F(TestCharsetConverter, utf8To_UTF16LE) +{ + refstra1 = "test_utf8To:_charset_UTF-16LE,_" + "CStdString16"; + refstr16_1.assign(refutf16LE2); + varstr16_1.clear(); + g_charsetConverter.utf8To("UTF-16LE", refstra1, varstr16_1); + EXPECT_TRUE(!memcmp(refstr16_1.c_str(), varstr16_1.c_str(), + refstr16_1.length() * sizeof(uint16_t))); +} +*/ + +//TEST_F(TestCharsetConverter, utf8To_UTF32LE) +//{ +// refstra1 = "test_utf8To:_charset_UTF-32LE,_" +//#ifdef TARGET_DARWIN +///* OSX has its own 'special' utf-8 charset which we use (see UTF8_SOURCE in CharsetConverter.cpp) +// which is basically NFD (decomposed) utf-8. The trouble is, it fails on the COW FACE and MOUSE FACE +// characters for some reason (possibly anything over 0x100000, or maybe there's a decomposed form of these +// that I couldn't find???) If UTF8_SOURCE is switched to UTF-8 then this test would pass as-is, but then +// some filenames stored in utf8-mac wouldn't display correctly in the UI. */ +// "CStdString32_"; +//#else +// "CStdString32_🐭🐮"; +//#endif +// refstr32_1.assign(refutf32LE1); +// varstr32_1.clear(); +// g_charsetConverter.utf8To("UTF-32LE", refstra1, varstr32_1); +// EXPECT_TRUE(!memcmp(refstr32_1.c_str(), varstr32_1.c_str(), +// sizeof(refutf32LE1))); +//} + +TEST_F(TestCharsetConverter, stringCharsetToUtf8) +{ + refstra1 = "test_stringCharsetToUtf8"; + varstra1.clear(); + g_charsetConverter.ToUtf8("UTF-16LE", refutf16LE3, varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, isValidUtf8_1) +{ + varstra1.clear(); + g_charsetConverter.ToUtf8("UTF-16LE", refutf16LE3, varstra1); + EXPECT_TRUE(CUtf8Utils::isValidUtf8(varstra1.c_str())); +} + +TEST_F(TestCharsetConverter, isValidUtf8_2) +{ + refstr1 = refutf16LE3; + EXPECT_FALSE(CUtf8Utils::isValidUtf8(refstr1)); +} + +TEST_F(TestCharsetConverter, isValidUtf8_3) +{ + varstra1.clear(); + g_charsetConverter.ToUtf8("UTF-16LE", refutf16LE3, varstra1); + EXPECT_TRUE(CUtf8Utils::isValidUtf8(varstra1.c_str())); +} + +TEST_F(TestCharsetConverter, isValidUtf8_4) +{ + EXPECT_FALSE(CUtf8Utils::isValidUtf8(refutf16LE3)); +} + +//! @todo Resolve correct input/output for this function +// TEST_F(TestCharsetConverter, ucs2CharsetToStringCharset) +// { +// void ucs2CharsetToStringCharset(const std::wstring& strSource, +// std::string& strDest, bool swap = false); +// } + +TEST_F(TestCharsetConverter, wToUTF8) +{ + refstrw1 = L"test_wToUTF8"; + refstra1 = u8"test_wToUTF8"; + varstra1.clear(); + g_charsetConverter.wToUTF8(refstrw1, varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +//TEST_F(TestCharsetConverter, utf16BEtoUTF8) +//{ +// refstr16_1.assign(refutf16BE); +// refstra1 = "test_utf16BEtoUTF8"; +// varstra1.clear(); +// g_charsetConverter.utf16BEtoUTF8(refstr16_1, varstra1); +// EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +//} + +//TEST_F(TestCharsetConverter, utf16LEtoUTF8) +//{ +// refstr16_1.assign(refutf16LE4); +// refstra1 = "test_utf16LEtoUTF8"; +// varstra1.clear(); +// g_charsetConverter.utf16LEtoUTF8(refstr16_1, varstra1); +// EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +//} + +//TEST_F(TestCharsetConverter, ucs2ToUTF8) +//{ +// refstr16_1.assign(refucs2); +// refstra1 = "test_ucs2toUTF8"; +// varstra1.clear(); +// g_charsetConverter.ucs2ToUTF8(refstr16_1, varstra1); +// EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +//} + +TEST_F(TestCharsetConverter, utf8logicalToVisualBiDi) +{ + refstra1 = "test_utf8logicalToVisualBiDi"; + refstra2 = "test_utf8logicalToVisualBiDi"; + varstra1.clear(); + g_charsetConverter.utf8logicalToVisualBiDi(refstra1, varstra1); + EXPECT_STREQ(refstra2.c_str(), varstra1.c_str()); +} + +//! @todo Resolve correct input/output for this function +// TEST_F(TestCharsetConverter, utf32ToStringCharset) +// { +// void utf32ToStringCharset(const unsigned long* strSource, std::string& strDest); +// } + +TEST_F(TestCharsetConverter, getCharsetLabels) +{ + std::vector reflabels; + reflabels.emplace_back("Western Europe (ISO)"); + reflabels.emplace_back("Central Europe (ISO)"); + reflabels.emplace_back("South Europe (ISO)"); + reflabels.emplace_back("Baltic (ISO)"); + reflabels.emplace_back("Cyrillic (ISO)"); + reflabels.emplace_back("Arabic (ISO)"); + reflabels.emplace_back("Greek (ISO)"); + reflabels.emplace_back("Hebrew (ISO)"); + reflabels.emplace_back("Turkish (ISO)"); + reflabels.emplace_back("Central Europe (Windows)"); + reflabels.emplace_back("Cyrillic (Windows)"); + reflabels.emplace_back("Western Europe (Windows)"); + reflabels.emplace_back("Greek (Windows)"); + reflabels.emplace_back("Turkish (Windows)"); + reflabels.emplace_back("Hebrew (Windows)"); + reflabels.emplace_back("Arabic (Windows)"); + reflabels.emplace_back("Baltic (Windows)"); + reflabels.emplace_back("Vietnamese (Windows)"); + reflabels.emplace_back("Thai (Windows)"); + reflabels.emplace_back("Chinese Traditional (Big5)"); + reflabels.emplace_back("Chinese Simplified (GBK)"); + reflabels.emplace_back("Japanese (Shift-JIS)"); + reflabels.emplace_back("Korean"); + reflabels.emplace_back("Hong Kong (Big5-HKSCS)"); + + std::vector varlabels = g_charsetConverter.getCharsetLabels(); + ASSERT_EQ(reflabels.size(), varlabels.size()); + + size_t pos = 0; + for (const auto& it : varlabels) + { + EXPECT_STREQ((reflabels.at(pos++)).c_str(), it.c_str()); + } +} + +TEST_F(TestCharsetConverter, getCharsetLabelByName) +{ + std::string varstr = + g_charsetConverter.getCharsetLabelByName("ISO-8859-1"); + EXPECT_STREQ("Western Europe (ISO)", varstr.c_str()); + varstr.clear(); + varstr = g_charsetConverter.getCharsetLabelByName("Bogus"); + EXPECT_STREQ("", varstr.c_str()); +} + +TEST_F(TestCharsetConverter, getCharsetNameByLabel) +{ + std::string varstr = + g_charsetConverter.getCharsetNameByLabel("Western Europe (ISO)"); + EXPECT_STREQ("ISO-8859-1", varstr.c_str()); + varstr.clear(); + varstr = g_charsetConverter.getCharsetNameByLabel("Bogus"); + EXPECT_STREQ("", varstr.c_str()); +} + +TEST_F(TestCharsetConverter, unknownToUTF8_1) +{ + refstra1 = "test_unknownToUTF8"; + varstra1 = "test_unknownToUTF8"; + g_charsetConverter.unknownToUTF8(varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, unknownToUTF8_2) +{ + refstra1 = "test_unknownToUTF8"; + varstra1.clear(); + g_charsetConverter.unknownToUTF8(refstra1, varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, toW) +{ + refstra1 = "test_toW:_charset_UTF-16LE"; + refstrw1 = L"\xBDEF\xEF94\x85BD\xBDEF\xEF93\x94BD\xBCEF\xEFBF" + L"\x94BD\xBDEF\xEF8F\xB7BC\xBCEF\xEF9A\xBFBC\xBDEF" + L"\xEF83\x88BD\xBDEF\xEF81\x92BD\xBDEF\xEF93\x85BD" + L"\xBDEF\xEF94\xBFBC\xBCEF\xEFB5\xB4BC\xBCEF\xEFA6" + L"\x8DBC\xBCEF\xEF91\x96BC\xBCEF\xEFAC\xA5BC"; + varstrw1.clear(); + g_charsetConverter.toW(refstra1, varstrw1, "UTF-16LE"); + EXPECT_STREQ(refstrw1.c_str(), varstrw1.c_str()); +} + +TEST_F(TestCharsetConverter, fromW) +{ + refstrw1 = L"\xBDEF\xEF94\x85BD\xBDEF\xEF93\x94BD\xBCEF\xEFBF" + L"\x86BD\xBDEF\xEF92\x8FBD\xBDEF\xEF8D\xB7BC\xBCEF" + L"\xEF9A\xBFBC\xBDEF\xEF83\x88BD\xBDEF\xEF81\x92BD" + L"\xBDEF\xEF93\x85BD\xBDEF\xEF94\xBFBC\xBCEF\xEFB5" + L"\xB4BC\xBCEF\xEFA6\x8DBC\xBCEF\xEF91\x96BC\xBCEF" + L"\xEFAC\xA5BC"; + refstra1 = "test_fromW:_charset_UTF-16LE"; + varstra1.clear(); + g_charsetConverter.fromW(refstrw1, varstra1, "UTF-16LE"); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} diff --git a/xbmc/utils/test/TestCrc32.cpp b/xbmc/utils/test/TestCrc32.cpp new file mode 100644 index 0000000..99a2dd5 --- /dev/null +++ b/xbmc/utils/test/TestCrc32.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/Crc32.h" + +#include + +static const char refdata[] = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "01234567890!@#$%^&*()"; + +TEST(TestCrc32, Compute_1) +{ + Crc32 a; + uint32_t varcrc; + a.Compute(refdata, sizeof(refdata) - 1); + varcrc = a; + EXPECT_EQ(0xa4eb60e3, varcrc); +} + +TEST(TestCrc32, Compute_2) +{ + uint32_t varcrc; + std::string s = refdata; + varcrc = Crc32::Compute(s); + EXPECT_EQ(0xa4eb60e3, varcrc); +} + +TEST(TestCrc32, ComputeFromLowerCase) +{ + std::string s = refdata; + uint32_t varcrc = Crc32::ComputeFromLowerCase(s); + EXPECT_EQ((uint32_t)0x7f045b3e, varcrc); +} + +TEST(TestCrc32, Reset) +{ + Crc32 a; + uint32_t varcrc; + std::string s = refdata; + a.Compute(s.c_str(), s.length()); + a.Reset(); + varcrc = a; + EXPECT_EQ(0xffffffff, varcrc); +} diff --git a/xbmc/utils/test/TestCryptThreading.cpp b/xbmc/utils/test/TestCryptThreading.cpp new file mode 100644 index 0000000..949bd6f --- /dev/null +++ b/xbmc/utils/test/TestCryptThreading.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/CryptThreading.h" +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) +#include "threads/SingleLock.h" + +#include +#include +#include +#include + +#include + +TEST(TestCryptThreadingInitializer, General) +{ + std::cout << "g_cryptThreadingInitializer address: " << + testing::PrintToString(&g_cryptThreadingInitializer) << "\n"; +} + +#define PVTID_NUM_THREADS 10 + +TEST(TestCryptThreadingInitializer, ProducesValidThreadIds) +{ + std::thread testThreads[PVTID_NUM_THREADS]; + + std::vector gatheredIds; + CCriticalSection gatheredIdsMutex; + + std::atomic threadsWaiting{0}; + std::atomic gate{false}; + + for (int i = 0; i < PVTID_NUM_THREADS; i++) + { + testThreads[i] = std::thread([&gatheredIds, &gatheredIdsMutex, &threadsWaiting, &gate]() { + threadsWaiting++; + + while (!gate); + + unsigned long myTid = g_cryptThreadingInitializer.GetCurrentCryptThreadId(); + + { + CSingleLock gatheredIdsLock(gatheredIdsMutex); + gatheredIds.push_back(myTid); + } + }); + } + + gate = true; + + for (int i = 0; i < PVTID_NUM_THREADS; i++) + // This is somewhat dangerous but C++ doesn't have a join with timeout or a way to check + // if a thread is still running. + testThreads[i].join(); + + // Verify that all of the thread id's are unique, and that there are 10 of them, and that none + // of them is zero + std::set checkIds; + for (std::vector::const_iterator i = gatheredIds.begin(); i != gatheredIds.end(); ++i) + { + unsigned long curId = *i; + // Thread ID isn't zero (since the sequence is pre-incremented and starts at 0) + ASSERT_TRUE(curId != 0); + + // Make sure the ID isn't duplicated + ASSERT_TRUE(checkIds.find(curId) == checkIds.end()); + checkIds.insert(curId); + } + + // Make sure there's exactly PVTID_NUM_THREADS of them + ASSERT_EQ(PVTID_NUM_THREADS, gatheredIds.size()); + ASSERT_EQ(PVTID_NUM_THREADS, checkIds.size()); +} +#endif diff --git a/xbmc/utils/test/TestDatabaseUtils.cpp b/xbmc/utils/test/TestDatabaseUtils.cpp new file mode 100644 index 0000000..41e20bd --- /dev/null +++ b/xbmc/utils/test/TestDatabaseUtils.cpp @@ -0,0 +1,1376 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "dbwrappers/qry_dat.h" +#include "music/MusicDatabase.h" +#include "utils/DatabaseUtils.h" +#include "utils/StringUtils.h" +#include "utils/Variant.h" +#include "video/VideoDatabase.h" + +#include + +class TestDatabaseUtilsHelper +{ +public: + TestDatabaseUtilsHelper() + { + album_idAlbum = CMusicDatabase::album_idAlbum; + album_strAlbum = CMusicDatabase::album_strAlbum; + album_strArtists = CMusicDatabase::album_strArtists; + album_strGenres = CMusicDatabase::album_strGenres; + album_strMoods = CMusicDatabase::album_strMoods; + album_strReleaseDate = CMusicDatabase::album_strReleaseDate; + album_strOrigReleaseDate = CMusicDatabase::album_strOrigReleaseDate; + album_strStyles = CMusicDatabase::album_strStyles; + album_strThemes = CMusicDatabase::album_strThemes; + album_strReview = CMusicDatabase::album_strReview; + album_strLabel = CMusicDatabase::album_strLabel; + album_strType = CMusicDatabase::album_strType; + album_fRating = CMusicDatabase::album_fRating; + album_iVotes = CMusicDatabase::album_iVotes; + album_iUserrating = CMusicDatabase::album_iUserrating; + album_dtDateAdded = CMusicDatabase::album_dateAdded; + + song_idSong = CMusicDatabase::song_idSong; + song_strTitle = CMusicDatabase::song_strTitle; + song_iTrack = CMusicDatabase::song_iTrack; + song_iDuration = CMusicDatabase::song_iDuration; + song_strReleaseDate = CMusicDatabase::song_strReleaseDate; + song_strOrigReleaseDate = CMusicDatabase::song_strOrigReleaseDate; + song_strFileName = CMusicDatabase::song_strFileName; + song_iTimesPlayed = CMusicDatabase::song_iTimesPlayed; + song_iStartOffset = CMusicDatabase::song_iStartOffset; + song_iEndOffset = CMusicDatabase::song_iEndOffset; + song_lastplayed = CMusicDatabase::song_lastplayed; + song_rating = CMusicDatabase::song_rating; + song_votes = CMusicDatabase::song_votes; + song_userrating = CMusicDatabase::song_userrating; + song_comment = CMusicDatabase::song_comment; + song_strAlbum = CMusicDatabase::song_strAlbum; + song_strPath = CMusicDatabase::song_strPath; + song_strGenres = CMusicDatabase::song_strGenres; + song_strArtists = CMusicDatabase::song_strArtists; + } + + int album_idAlbum; + int album_strAlbum; + int album_strArtists; + int album_strGenres; + int album_strMoods; + int album_strReleaseDate; + int album_strOrigReleaseDate; + int album_strStyles; + int album_strThemes; + int album_strReview; + int album_strLabel; + int album_strType; + int album_fRating; + int album_iVotes; + int album_iUserrating; + int album_dtDateAdded; + + int song_idSong; + int song_strTitle; + int song_iTrack; + int song_iDuration; + int song_strReleaseDate; + int song_strOrigReleaseDate; + int song_strFileName; + int song_iTimesPlayed; + int song_iStartOffset; + int song_iEndOffset; + int song_lastplayed; + int song_rating; + int song_votes; + int song_userrating; + int song_comment; + int song_strAlbum; + int song_strPath; + int song_strGenres; + int song_strArtists; +}; + +TEST(TestDatabaseUtils, GetField_None) +{ + std::string refstr, varstr; + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldNone, MediaTypeNone, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + varstr = DatabaseUtils::GetField(FieldNone, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_MediaTypeAlbum) +{ + std::string refstr, varstr; + + refstr = "albumview.idAlbum"; + varstr = DatabaseUtils::GetField(FieldId, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strAlbum"; + varstr = DatabaseUtils::GetField(FieldAlbum, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strArtists"; + varstr = DatabaseUtils::GetField(FieldArtist, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strArtists"; + varstr = DatabaseUtils::GetField(FieldAlbumArtist, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strGenres"; + varstr = DatabaseUtils::GetField(FieldGenre, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strReleaseDate"; + varstr = DatabaseUtils::GetField(FieldYear, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + +refstr = "albumview.strOrigReleaseDate"; + varstr = DatabaseUtils::GetField(FieldOrigYear, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strMoods"; + varstr = DatabaseUtils::GetField(FieldMoods, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strStyles"; + varstr = DatabaseUtils::GetField(FieldStyles, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strThemes"; + varstr = DatabaseUtils::GetField(FieldThemes, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strReview"; + varstr = DatabaseUtils::GetField(FieldReview, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strLabel"; + varstr = DatabaseUtils::GetField(FieldMusicLabel, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strType"; + varstr = DatabaseUtils::GetField(FieldAlbumType, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.fRating"; + varstr = DatabaseUtils::GetField(FieldRating, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.iVotes"; + varstr = DatabaseUtils::GetField(FieldVotes, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.iUserrating"; + varstr = DatabaseUtils::GetField(FieldUserRating, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.dateAdded"; + varstr = DatabaseUtils::GetField(FieldDateAdded, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldNone, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strAlbum"; + varstr = DatabaseUtils::GetField(FieldAlbum, MediaTypeAlbum, + DatabaseQueryPartWhere); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + varstr = DatabaseUtils::GetField(FieldAlbum, MediaTypeAlbum, + DatabaseQueryPartOrderBy); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_MediaTypeSong) +{ + std::string refstr, varstr; + + refstr = "songview.idSong"; + varstr = DatabaseUtils::GetField(FieldId, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strTitle"; + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.iTrack"; + varstr = DatabaseUtils::GetField(FieldTrackNumber, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.iDuration"; + varstr = DatabaseUtils::GetField(FieldTime, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strFilename"; + varstr = DatabaseUtils::GetField(FieldFilename, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.iTimesPlayed"; + varstr = DatabaseUtils::GetField(FieldPlaycount, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.iStartOffset"; + varstr = DatabaseUtils::GetField(FieldStartOffset, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.iEndOffset"; + varstr = DatabaseUtils::GetField(FieldEndOffset, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.lastPlayed"; + varstr = DatabaseUtils::GetField(FieldLastPlayed, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.rating"; + varstr = DatabaseUtils::GetField(FieldRating, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.votes"; + varstr = DatabaseUtils::GetField(FieldVotes, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.userrating"; + varstr = DatabaseUtils::GetField(FieldUserRating, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.comment"; + varstr = DatabaseUtils::GetField(FieldComment, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strReleaseDate"; + varstr = DatabaseUtils::GetField(FieldYear, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strOrigReleaseDate"; + varstr = DatabaseUtils::GetField(FieldOrigYear, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strAlbum"; + varstr = DatabaseUtils::GetField(FieldAlbum, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strArtists"; + varstr = DatabaseUtils::GetField(FieldArtist, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strArtists"; + varstr = DatabaseUtils::GetField(FieldAlbumArtist, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strGenres"; + varstr = DatabaseUtils::GetField(FieldGenre, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.dateAdded"; + varstr = DatabaseUtils::GetField(FieldDateAdded, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeSong, + DatabaseQueryPartWhere); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeSong, + DatabaseQueryPartOrderBy); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_MediaTypeMusicVideo) +{ + std::string refstr, varstr; + + refstr = "musicvideo_view.idMVideo"; + varstr = DatabaseUtils::GetField(FieldId, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c%02d",VIDEODB_ID_MUSICVIDEO_TITLE); + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c%02d",VIDEODB_ID_MUSICVIDEO_RUNTIME); + varstr = DatabaseUtils::GetField(FieldTime, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c%02d",VIDEODB_ID_MUSICVIDEO_DIRECTOR); + varstr = DatabaseUtils::GetField(FieldDirector, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c%02d",VIDEODB_ID_MUSICVIDEO_STUDIOS); + varstr = DatabaseUtils::GetField(FieldStudio, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c%02d",VIDEODB_ID_MUSICVIDEO_PLOT); + varstr = DatabaseUtils::GetField(FieldPlot, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c%02d",VIDEODB_ID_MUSICVIDEO_ALBUM); + varstr = DatabaseUtils::GetField(FieldAlbum, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c%02d",VIDEODB_ID_MUSICVIDEO_ARTIST); + varstr = DatabaseUtils::GetField(FieldArtist, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c%02d",VIDEODB_ID_MUSICVIDEO_GENRE); + varstr = DatabaseUtils::GetField(FieldGenre, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c%02d",VIDEODB_ID_MUSICVIDEO_TRACK); + varstr = DatabaseUtils::GetField(FieldTrackNumber, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.strFilename"; + varstr = DatabaseUtils::GetField(FieldFilename, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.playCount"; + varstr = DatabaseUtils::GetField(FieldPlaycount, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.lastPlayed"; + varstr = DatabaseUtils::GetField(FieldLastPlayed, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.dateAdded"; + varstr = DatabaseUtils::GetField(FieldDateAdded, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldVideoResolution, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeMusicVideo, + DatabaseQueryPartWhere); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeMusicVideo, + DatabaseQueryPartOrderBy); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.userrating"; + varstr = DatabaseUtils::GetField(FieldUserRating, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_MediaTypeMovie) +{ + std::string refstr, varstr; + + refstr = "movie_view.idMovie"; + varstr = DatabaseUtils::GetField(FieldId, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_TITLE); + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("CASE WHEN length(movie_view.c%02d) > 0 THEN movie_view.c%02d " + "ELSE movie_view.c%02d END", VIDEODB_ID_SORTTITLE, + VIDEODB_ID_SORTTITLE, VIDEODB_ID_TITLE); + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeMovie, + DatabaseQueryPartOrderBy); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_PLOT); + varstr = DatabaseUtils::GetField(FieldPlot, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_PLOTOUTLINE); + varstr = DatabaseUtils::GetField(FieldPlotOutline, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_TAGLINE); + varstr = DatabaseUtils::GetField(FieldTagline, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.votes"; + varstr = DatabaseUtils::GetField(FieldVotes, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.rating"; + varstr = DatabaseUtils::GetField(FieldRating, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_CREDITS); + varstr = DatabaseUtils::GetField(FieldWriter, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_SORTTITLE); + varstr = DatabaseUtils::GetField(FieldSortTitle, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_RUNTIME); + varstr = DatabaseUtils::GetField(FieldTime, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_MPAA); + varstr = DatabaseUtils::GetField(FieldMPAA, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_TOP250); + varstr = DatabaseUtils::GetField(FieldTop250, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_GENRE); + varstr = DatabaseUtils::GetField(FieldGenre, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_DIRECTOR); + varstr = DatabaseUtils::GetField(FieldDirector, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_STUDIOS); + varstr = DatabaseUtils::GetField(FieldStudio, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_TRAILER); + varstr = DatabaseUtils::GetField(FieldTrailer, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c%02d", VIDEODB_ID_COUNTRY); + varstr = DatabaseUtils::GetField(FieldCountry, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.strFilename"; + varstr = DatabaseUtils::GetField(FieldFilename, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.playCount"; + varstr = DatabaseUtils::GetField(FieldPlaycount, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.lastPlayed"; + varstr = DatabaseUtils::GetField(FieldLastPlayed, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.dateAdded"; + varstr = DatabaseUtils::GetField(FieldDateAdded, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.userrating"; + varstr = DatabaseUtils::GetField(FieldUserRating, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldRandom, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_MediaTypeTvShow) +{ + std::string refstr, varstr; + + refstr = "tvshow_view.idShow"; + varstr = DatabaseUtils::GetField(FieldId, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("CASE WHEN length(tvshow_view.c%02d) > 0 THEN tvshow_view.c%02d " + "ELSE tvshow_view.c%02d END", VIDEODB_ID_TV_SORTTITLE, + VIDEODB_ID_TV_SORTTITLE, VIDEODB_ID_TV_TITLE); + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeTvShow, + DatabaseQueryPartOrderBy); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_TITLE); + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_PLOT); + varstr = DatabaseUtils::GetField(FieldPlot, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_STATUS); + varstr = DatabaseUtils::GetField(FieldTvShowStatus, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.votes"; + varstr = DatabaseUtils::GetField(FieldVotes, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.rating"; + varstr = DatabaseUtils::GetField(FieldRating, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_PREMIERED); + varstr = DatabaseUtils::GetField(FieldYear, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_GENRE); + varstr = DatabaseUtils::GetField(FieldGenre, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_MPAA); + varstr = DatabaseUtils::GetField(FieldMPAA, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_STUDIOS); + varstr = DatabaseUtils::GetField(FieldStudio, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c%02d", VIDEODB_ID_TV_SORTTITLE); + varstr = DatabaseUtils::GetField(FieldSortTitle, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.dateAdded"; + varstr = DatabaseUtils::GetField(FieldDateAdded, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.totalSeasons"; + varstr = DatabaseUtils::GetField(FieldSeason, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.totalCount"; + varstr = DatabaseUtils::GetField(FieldNumberOfEpisodes, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.watchedcount"; + varstr = DatabaseUtils::GetField(FieldNumberOfWatchedEpisodes, + MediaTypeTvShow, DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.userrating"; + varstr = DatabaseUtils::GetField(FieldUserRating, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldRandom, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_MediaTypeEpisode) +{ + std::string refstr, varstr; + + refstr = "episode_view.idEpisode"; + varstr = DatabaseUtils::GetField(FieldId, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_TITLE); + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_PLOT); + varstr = DatabaseUtils::GetField(FieldPlot, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.votes"; + varstr = DatabaseUtils::GetField(FieldVotes, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.rating"; + varstr = DatabaseUtils::GetField(FieldRating, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_CREDITS); + varstr = DatabaseUtils::GetField(FieldWriter, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_AIRED); + varstr = DatabaseUtils::GetField(FieldAirDate, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_RUNTIME); + varstr = DatabaseUtils::GetField(FieldTime, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_DIRECTOR); + varstr = DatabaseUtils::GetField(FieldDirector, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_SEASON); + varstr = DatabaseUtils::GetField(FieldSeason, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c%02d", VIDEODB_ID_EPISODE_EPISODE); + varstr = DatabaseUtils::GetField(FieldEpisodeNumber, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.strFilename"; + varstr = DatabaseUtils::GetField(FieldFilename, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.playCount"; + varstr = DatabaseUtils::GetField(FieldPlaycount, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.lastPlayed"; + varstr = DatabaseUtils::GetField(FieldLastPlayed, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.dateAdded"; + varstr = DatabaseUtils::GetField(FieldDateAdded, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.strTitle"; + varstr = DatabaseUtils::GetField(FieldTvShowTitle, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.premiered"; + varstr = DatabaseUtils::GetField(FieldYear, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.mpaa"; + varstr = DatabaseUtils::GetField(FieldMPAA, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.strStudio"; + varstr = DatabaseUtils::GetField(FieldStudio, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.userrating"; + varstr = DatabaseUtils::GetField(FieldUserRating, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldRandom, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_FieldRandom) +{ + std::string refstr, varstr; + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldRandom, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldRandom, MediaTypeEpisode, + DatabaseQueryPartWhere); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "RANDOM()"; + varstr = DatabaseUtils::GetField(FieldRandom, MediaTypeEpisode, + DatabaseQueryPartOrderBy); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetFieldIndex_None) +{ + int refindex, varindex; + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeNone); + EXPECT_EQ(refindex, varindex); + + varindex = DatabaseUtils::GetFieldIndex(FieldNone, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); +} + +//! @todo Should enums in CMusicDatabase be made public instead? +TEST(TestDatabaseUtils, GetFieldIndex_MediaTypeAlbum) +{ + int refindex, varindex; + TestDatabaseUtilsHelper a; + + refindex = a.album_idAlbum; + varindex = DatabaseUtils::GetFieldIndex(FieldId, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strAlbum; + varindex = DatabaseUtils::GetFieldIndex(FieldAlbum, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strArtists; + varindex = DatabaseUtils::GetFieldIndex(FieldArtist, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strArtists; + varindex = DatabaseUtils::GetFieldIndex(FieldAlbumArtist, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strGenres; + varindex = DatabaseUtils::GetFieldIndex(FieldGenre, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strReleaseDate; + varindex = DatabaseUtils::GetFieldIndex(FieldYear, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strOrigReleaseDate; + varindex = DatabaseUtils::GetFieldIndex(FieldOrigYear, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strMoods; + varindex = DatabaseUtils::GetFieldIndex(FieldMoods, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strStyles; + varindex = DatabaseUtils::GetFieldIndex(FieldStyles, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strThemes; + varindex = DatabaseUtils::GetFieldIndex(FieldThemes, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strReview; + varindex = DatabaseUtils::GetFieldIndex(FieldReview, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strLabel; + varindex = DatabaseUtils::GetFieldIndex(FieldMusicLabel, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strType; + varindex = DatabaseUtils::GetFieldIndex(FieldAlbumType, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_fRating; + varindex = DatabaseUtils::GetFieldIndex(FieldRating, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_dtDateAdded; + varindex = DatabaseUtils::GetFieldIndex(FieldDateAdded, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); +} + +TEST(TestDatabaseUtils, GetFieldIndex_MediaTypeSong) +{ + int refindex, varindex; + TestDatabaseUtilsHelper a; + + refindex = a.song_idSong; + varindex = DatabaseUtils::GetFieldIndex(FieldId, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strTitle; + varindex = DatabaseUtils::GetFieldIndex(FieldTitle, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_iTrack; + varindex = DatabaseUtils::GetFieldIndex(FieldTrackNumber, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_iDuration; + varindex = DatabaseUtils::GetFieldIndex(FieldTime, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strReleaseDate; + varindex = DatabaseUtils::GetFieldIndex(FieldYear, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strFileName; + varindex = DatabaseUtils::GetFieldIndex(FieldFilename, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_iTimesPlayed; + varindex = DatabaseUtils::GetFieldIndex(FieldPlaycount, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_iStartOffset; + varindex = DatabaseUtils::GetFieldIndex(FieldStartOffset, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_iEndOffset; + varindex = DatabaseUtils::GetFieldIndex(FieldEndOffset, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_lastplayed; + varindex = DatabaseUtils::GetFieldIndex(FieldLastPlayed, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_rating; + varindex = DatabaseUtils::GetFieldIndex(FieldRating, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_votes; + varindex = DatabaseUtils::GetFieldIndex(FieldVotes, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_userrating; + varindex = DatabaseUtils::GetFieldIndex(FieldUserRating, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_comment; + varindex = DatabaseUtils::GetFieldIndex(FieldComment, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strAlbum; + varindex = DatabaseUtils::GetFieldIndex(FieldAlbum, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strPath; + varindex = DatabaseUtils::GetFieldIndex(FieldPath, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strArtists; + varindex = DatabaseUtils::GetFieldIndex(FieldArtist, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strGenres; + varindex = DatabaseUtils::GetFieldIndex(FieldGenre, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeSong); + EXPECT_EQ(refindex, varindex); +} + +TEST(TestDatabaseUtils, GetFieldIndex_MediaTypeMusicVideo) +{ + int refindex, varindex; + + refindex = 0; + varindex = DatabaseUtils::GetFieldIndex(FieldId, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_TITLE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTitle, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_RUNTIME + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTime, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_DIRECTOR + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldDirector, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_STUDIOS + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldStudio, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_PLOT + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldPlot, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_ALBUM + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldAlbum, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_ARTIST + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldArtist, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_GENRE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldGenre, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_TRACK + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTrackNumber, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_FILE; + varindex = DatabaseUtils::GetFieldIndex(FieldFilename, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_PATH; + varindex = DatabaseUtils::GetFieldIndex(FieldPath, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_PLAYCOUNT; + varindex = DatabaseUtils::GetFieldIndex(FieldPlaycount, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_LASTPLAYED; + varindex = DatabaseUtils::GetFieldIndex(FieldLastPlayed, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_DATEADDED; + varindex = DatabaseUtils::GetFieldIndex(FieldDateAdded, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_USER_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldUserRating, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_PREMIERED; + varindex = DatabaseUtils::GetFieldIndex(FieldYear, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); +} + +TEST(TestDatabaseUtils, GetFieldIndex_MediaTypeMovie) +{ + int refindex, varindex; + + refindex = 0; + varindex = DatabaseUtils::GetFieldIndex(FieldId, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TITLE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTitle, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_SORTTITLE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldSortTitle, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_PLOT + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldPlot, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_PLOTOUTLINE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldPlotOutline, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TAGLINE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTagline, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_CREDITS + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldWriter, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_RUNTIME + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTime, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MPAA + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldMPAA, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TOP250 + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTop250, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_GENRE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldGenre, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_DIRECTOR + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldDirector, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_STUDIOS + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldStudio, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TRAILER + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTrailer, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_COUNTRY + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldCountry, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_FILE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldFilename, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_PATH; + varindex = DatabaseUtils::GetFieldIndex(FieldPath, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_PLAYCOUNT; + varindex = DatabaseUtils::GetFieldIndex(FieldPlaycount, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_LASTPLAYED; + varindex = DatabaseUtils::GetFieldIndex(FieldLastPlayed, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_DATEADDED; + varindex = DatabaseUtils::GetFieldIndex(FieldDateAdded, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_USER_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldUserRating, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_VOTES; + varindex = DatabaseUtils::GetFieldIndex(FieldVotes, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldRating, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_PREMIERED; + varindex = DatabaseUtils::GetFieldIndex(FieldYear, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); +} + +TEST(TestDatabaseUtils, GetFieldIndex_MediaTypeTvShow) +{ + int refindex, varindex; + + refindex = 0; + varindex = DatabaseUtils::GetFieldIndex(FieldId, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_TITLE + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldTitle, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_SORTTITLE + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldSortTitle, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_PLOT + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldPlot, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_STATUS + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldTvShowStatus, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_PREMIERED + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldYear, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_GENRE + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldGenre, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_MPAA + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldMPAA, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_STUDIOS + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldStudio, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_PATH; + varindex = DatabaseUtils::GetFieldIndex(FieldPath, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_DATEADDED; + varindex = DatabaseUtils::GetFieldIndex(FieldDateAdded, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_NUM_EPISODES; + varindex = DatabaseUtils::GetFieldIndex(FieldNumberOfEpisodes, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_NUM_WATCHED; + varindex = DatabaseUtils::GetFieldIndex(FieldNumberOfWatchedEpisodes, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_NUM_SEASONS; + varindex = DatabaseUtils::GetFieldIndex(FieldSeason, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_USER_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldUserRating, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_VOTES; + varindex = DatabaseUtils::GetFieldIndex(FieldVotes, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldRating, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); +} + +TEST(TestDatabaseUtils, GetFieldIndex_MediaTypeEpisode) +{ + int refindex, varindex; + + refindex = 0; + varindex = DatabaseUtils::GetFieldIndex(FieldId, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_TITLE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTitle, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_PLOT + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldPlot, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_CREDITS + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldWriter, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_AIRED + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldAirDate, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_RUNTIME + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTime, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_DIRECTOR + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldDirector, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_SEASON + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldSeason, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_EPISODE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldEpisodeNumber, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_FILE; + varindex = DatabaseUtils::GetFieldIndex(FieldFilename, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_PATH; + varindex = DatabaseUtils::GetFieldIndex(FieldPath, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_PLAYCOUNT; + varindex = DatabaseUtils::GetFieldIndex(FieldPlaycount, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_LASTPLAYED; + varindex = DatabaseUtils::GetFieldIndex(FieldLastPlayed, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_DATEADDED; + varindex = DatabaseUtils::GetFieldIndex(FieldDateAdded, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_TVSHOW_NAME; + varindex = DatabaseUtils::GetFieldIndex(FieldTvShowTitle, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_TVSHOW_STUDIO; + varindex = DatabaseUtils::GetFieldIndex(FieldStudio, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_TVSHOW_AIRED; + varindex = DatabaseUtils::GetFieldIndex(FieldYear, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_TVSHOW_MPAA; + varindex = DatabaseUtils::GetFieldIndex(FieldMPAA, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_USER_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldUserRating, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_VOTES; + varindex = DatabaseUtils::GetFieldIndex(FieldVotes, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldRating, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); +} + +TEST(TestDatabaseUtils, GetSelectFields) +{ + Fields fields; + FieldList fieldlist; + + EXPECT_FALSE(DatabaseUtils::GetSelectFields(fields, MediaTypeAlbum, + fieldlist)); + + fields.insert(FieldId); + fields.insert(FieldGenre); + fields.insert(FieldAlbum); + fields.insert(FieldArtist); + fields.insert(FieldTitle); + EXPECT_FALSE(DatabaseUtils::GetSelectFields(fields, MediaTypeNone, + fieldlist)); + EXPECT_TRUE(DatabaseUtils::GetSelectFields(fields, MediaTypeAlbum, + fieldlist)); + EXPECT_FALSE(fieldlist.empty()); +} + +TEST(TestDatabaseUtils, GetFieldValue) +{ + CVariant v_null, v_string; + dbiplus::field_value f_null, f_string("test"); + + f_null.set_isNull(); + EXPECT_TRUE(DatabaseUtils::GetFieldValue(f_null, v_null)); + EXPECT_TRUE(v_null.isNull()); + + EXPECT_TRUE(DatabaseUtils::GetFieldValue(f_string, v_string)); + EXPECT_FALSE(v_string.isNull()); + EXPECT_TRUE(v_string.isString()); +} + +//! @todo Need some way to test this function +// TEST(TestDatabaseUtils, GetDatabaseResults) +// { +// static bool GetDatabaseResults(MediaType mediaType, const FieldList &fields, +// const std::unique_ptr &dataset, +// DatabaseResults &results); +// } + +TEST(TestDatabaseUtils, BuildLimitClause) +{ + std::string a = DatabaseUtils::BuildLimitClause(100); + EXPECT_STREQ(" LIMIT 100", a.c_str()); +} + +// class DatabaseUtils +// { +// public: +// +// +// static std::string BuildLimitClause(int end, int start = 0); +// }; diff --git a/xbmc/utils/test/TestDigest.cpp b/xbmc/utils/test/TestDigest.cpp new file mode 100644 index 0000000..96d0529 --- /dev/null +++ b/xbmc/utils/test/TestDigest.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/Digest.h" + +#include + +using KODI::UTILITY::CDigest; +using KODI::UTILITY::TypedDigest; + +TEST(TestDigest, Digest_Empty) +{ + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::MD5, "").c_str(), "d41d8cd98f00b204e9800998ecf8427e"); + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::MD5, nullptr, 0).c_str(), "d41d8cd98f00b204e9800998ecf8427e"); + { + CDigest digest{CDigest::Type::MD5}; + EXPECT_STREQ(digest.Finalize().c_str(), "d41d8cd98f00b204e9800998ecf8427e"); + } + { + CDigest digest{CDigest::Type::MD5}; + digest.Update(""); + digest.Update(nullptr, 0); + EXPECT_STREQ(digest.Finalize().c_str(), "d41d8cd98f00b204e9800998ecf8427e"); + } +} + +TEST(TestDigest, Digest_Basic) +{ + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::MD5, "asdf").c_str(), "912ec803b2ce49e4a541068d495ab570"); + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::MD5, "asdf", 4).c_str(), "912ec803b2ce49e4a541068d495ab570"); + { + CDigest digest{CDigest::Type::MD5}; + digest.Update("as"); + digest.Update("df", 2); + EXPECT_STREQ(digest.Finalize().c_str(), "912ec803b2ce49e4a541068d495ab570"); + } +} + +TEST(TestDigest, Digest_SHA1) +{ + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::SHA1, "").c_str(), "da39a3ee5e6b4b0d3255bfef95601890afd80709"); + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::SHA1, "asdf").c_str(), "3da541559918a808c2402bba5012f6c60b27661c"); +} + +TEST(TestDigest, Digest_SHA256) +{ + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::SHA256, "").c_str(), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::SHA256, "asdf").c_str(), "f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b"); +} + +TEST(TestDigest, Digest_SHA512) +{ + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::SHA512, "").c_str(), "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"); + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::SHA512, "asdf").c_str(), "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429080fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1"); +} + +TEST(TestDigest, TypedDigest_Empty) +{ + TypedDigest t1, t2; + EXPECT_EQ(t1, t2); + EXPECT_EQ(t1.type, CDigest::Type::INVALID); + EXPECT_EQ(t1.value, ""); + EXPECT_TRUE(t1.Empty()); + t1.type = CDigest::Type::SHA1; + EXPECT_TRUE(t1.Empty()); +} + +TEST(TestDigest, TypedDigest_SameType) +{ + TypedDigest t1{CDigest::Type::SHA1, "da39a3ee5e6b4b0d3255bfef95601890afd80709"}; + TypedDigest t2{CDigest::Type::SHA1, "da39a3ee5e6b4b0d3255bfef95601890afd80708"}; + EXPECT_NE(t1, t2); + EXPECT_FALSE(t1.Empty()); +} + +TEST(TestDigest, TypedDigest_CompareCase) +{ + TypedDigest t1{CDigest::Type::SHA1, "da39a3ee5e6b4b0d3255bfef95601890afd80708"}; + TypedDigest t2{CDigest::Type::SHA1, "da39A3EE5e6b4b0d3255bfef95601890afd80708"}; + EXPECT_EQ(t1, t2); +} + +TEST(TestDigest, TypedDigest_DifferingType) +{ + TypedDigest t1{CDigest::Type::SHA1, "da39a3ee5e6b4b0d3255bfef95601890afd80709"}; + TypedDigest t2{CDigest::Type::SHA256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}; + // Silence "unused expression" warning + bool a; + EXPECT_THROW(a = (t1 == t2), std::logic_error); + // Silence "unused variable" warning + (void)a; + EXPECT_THROW(a = (t1 != t2), std::logic_error); + (void)a; +} diff --git a/xbmc/utils/test/TestEndianSwap.cpp b/xbmc/utils/test/TestEndianSwap.cpp new file mode 100644 index 0000000..70d3cf0 --- /dev/null +++ b/xbmc/utils/test/TestEndianSwap.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/EndianSwap.h" + +#include + +TEST(TestEndianSwap, Endian_Swap16) +{ + uint16_t ref, var; + ref = 0x00FF; + var = Endian_Swap16(0xFF00); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_Swap32) +{ + uint32_t ref, var; + ref = 0x00FF00FF; + var = Endian_Swap32(0xFF00FF00); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_Swap64) +{ + uint64_t ref, var; + ref = UINT64_C(0x00FF00FF00FF00FF); + var = Endian_Swap64(UINT64_C(0xFF00FF00FF00FF00)); + EXPECT_EQ(ref, var); +} + +#ifndef WORDS_BIGENDIAN +TEST(TestEndianSwap, Endian_SwapLE16) +{ + uint16_t ref, var; + ref = 0x00FF; + var = Endian_SwapLE16(0x00FF); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapLE32) +{ + uint32_t ref, var; + ref = 0x00FF00FF; + var = Endian_SwapLE32(0x00FF00FF); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapLE64) +{ + uint64_t ref, var; + ref = UINT64_C(0x00FF00FF00FF00FF); + var = Endian_SwapLE64(UINT64_C(0x00FF00FF00FF00FF)); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapBE16) +{ + uint16_t ref, var; + ref = 0x00FF; + var = Endian_SwapBE16(0xFF00); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapBE32) +{ + uint32_t ref, var; + ref = 0x00FF00FF; + var = Endian_SwapBE32(0xFF00FF00); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapBE64) +{ + uint64_t ref, var; + ref = UINT64_C(0x00FF00FF00FF00FF); + var = Endian_SwapBE64(UINT64_C(0xFF00FF00FF00FF00)); + EXPECT_EQ(ref, var); +} +#else +TEST(TestEndianSwap, Endian_SwapLE16) +{ + uint16_t ref, var; + ref = 0x00FF; + var = Endian_SwapLE16(0xFF00); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapLE32) +{ + uint32_t ref, var; + ref = 0x00FF00FF; + var = Endian_SwapLE32(0xFF00FF00); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapLE64) +{ + uint64_t ref, var; + ref = UINT64_C(0x00FF00FF00FF00FF); + var = Endian_SwapLE64(UINT64_C(0xFF00FF00FF00FF00)); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapBE16) +{ + uint16_t ref, var; + ref = 0x00FF; + var = Endian_SwapBE16(0x00FF); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapBE32) +{ + uint32_t ref, var; + ref = 0x00FF00FF; + var = Endian_SwapBE32(0x00FF00FF); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapBE64) +{ + uint64_t ref, var; + ref = UINT64_C(0x00FF00FF00FF00FF); + var = Endian_SwapBE64(UINT64_C(0x00FF00FF00FF00FF)); + EXPECT_EQ(ref, var); +} +#endif diff --git a/xbmc/utils/test/TestFileOperationJob.cpp b/xbmc/utils/test/TestFileOperationJob.cpp new file mode 100644 index 0000000..cab4125 --- /dev/null +++ b/xbmc/utils/test/TestFileOperationJob.cpp @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "filesystem/Directory.h" +#include "filesystem/File.h" +#include "test/TestUtils.h" +#include "utils/FileOperationJob.h" +#include "utils/URIUtils.h" + +#include + +TEST(TestFileOperationJob, ActionCopy) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destfile; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + tmpfile->Close(); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + items.Add(item); + + std::string destpath = URIUtils::GetDirectory(tmpfilepath); + destpath = URIUtils::AddFileToFolder(destpath, "copy"); + destfile = URIUtils::AddFileToFolder(destpath, URIUtils::GetFileName(tmpfilepath)); + ASSERT_FALSE(XFILE::CFile::Exists(destfile)); + + job.SetFileOperation(CFileOperationJob::ActionCopy, items, destpath); + EXPECT_EQ(CFileOperationJob::ActionCopy, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CFile::Exists(tmpfilepath)); + EXPECT_TRUE(XFILE::CFile::Exists(destfile)); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); + EXPECT_TRUE(XFILE::CFile::Delete(destfile)); + EXPECT_TRUE(XFILE::CDirectory::Remove(destpath)); +} + +TEST(TestFileOperationJob, ActionMove) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destfile; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + tmpfile->Close(); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + items.Add(item); + + std::string destpath = URIUtils::GetDirectory(tmpfilepath); + destpath = URIUtils::AddFileToFolder(destpath, "move"); + destfile = URIUtils::AddFileToFolder(destpath, URIUtils::GetFileName(tmpfilepath)); + ASSERT_FALSE(XFILE::CFile::Exists(destfile)); + ASSERT_TRUE(XFILE::CDirectory::Create(destpath)); + + job.SetFileOperation(CFileOperationJob::ActionMove, items, destpath); + EXPECT_EQ(CFileOperationJob::ActionMove, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_FALSE(XFILE::CFile::Exists(tmpfilepath)); + EXPECT_TRUE(XFILE::CFile::Exists(destfile)); + + EXPECT_TRUE(XFILE::CFile::Delete(destfile)); + EXPECT_TRUE(XFILE::CDirectory::Remove(destpath)); +} + +TEST(TestFileOperationJob, ActionDelete) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destfile; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + tmpfile->Close(); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + items.Add(item); + + std::string destpath = URIUtils::GetDirectory(tmpfilepath); + destpath = URIUtils::AddFileToFolder(destpath, "delete"); + destfile = URIUtils::AddFileToFolder(destpath, URIUtils::GetFileName(tmpfilepath)); + ASSERT_FALSE(XFILE::CFile::Exists(destfile)); + + job.SetFileOperation(CFileOperationJob::ActionCopy, items, destpath); + EXPECT_EQ(CFileOperationJob::ActionCopy, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CFile::Exists(tmpfilepath)); + EXPECT_TRUE(XFILE::CFile::Exists(destfile)); + + job.SetFileOperation(CFileOperationJob::ActionDelete, items, ""); + EXPECT_EQ(CFileOperationJob::ActionDelete, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_FALSE(XFILE::CFile::Exists(tmpfilepath)); + + items.Clear(); + CFileItemPtr item2(new CFileItem(destfile)); + item2->SetPath(destfile); + item2->m_bIsFolder = false; + item2->Select(true); + items.Add(item2); + + job.SetFileOperation(CFileOperationJob::ActionDelete, items, ""); + EXPECT_EQ(CFileOperationJob::ActionDelete, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_FALSE(XFILE::CFile::Exists(destfile)); + EXPECT_TRUE(XFILE::CDirectory::Remove(destpath)); +} + +TEST(TestFileOperationJob, ActionReplace) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destfile; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + tmpfile->Close(); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + items.Add(item); + + std::string destpath = URIUtils::GetDirectory(tmpfilepath); + destpath = URIUtils::AddFileToFolder(destpath, "replace"); + destfile = URIUtils::AddFileToFolder(destpath, URIUtils::GetFileName(tmpfilepath)); + ASSERT_FALSE(XFILE::CFile::Exists(destfile)); + + job.SetFileOperation(CFileOperationJob::ActionCopy, items, destpath); + EXPECT_EQ(CFileOperationJob::ActionCopy, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CFile::Exists(tmpfilepath)); + EXPECT_TRUE(XFILE::CFile::Exists(destfile)); + + job.SetFileOperation(CFileOperationJob::ActionReplace, items, destpath); + EXPECT_EQ(CFileOperationJob::ActionReplace, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CFile::Exists(destfile)); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); + EXPECT_TRUE(XFILE::CFile::Delete(destfile)); + EXPECT_TRUE(XFILE::CDirectory::Remove(destpath)); +} + +TEST(TestFileOperationJob, ActionCreateFolder) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destpath; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + + std::string tmpfiledirectory = + CXBMCTestUtils::Instance().TempFileDirectory(tmpfile); + + tmpfile->Close(); + + destpath = tmpfilepath; + destpath += ".createfolder"; + ASSERT_FALSE(XFILE::CFile::Exists(destpath)); + + CFileItemPtr item(new CFileItem(destpath)); + item->SetPath(destpath); + item->m_bIsFolder = true; + item->Select(true); + items.Add(item); + + job.SetFileOperation(CFileOperationJob::ActionCreateFolder, items, tmpfiledirectory); + EXPECT_EQ(CFileOperationJob::ActionCreateFolder, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CDirectory::Exists(destpath)); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); + EXPECT_TRUE(XFILE::CDirectory::Remove(destpath)); +} + +// This test will fail until ActionDeleteFolder has a proper implementation +TEST(TestFileOperationJob, ActionDeleteFolder) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destpath; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + + std::string tmpfiledirectory = + CXBMCTestUtils::Instance().TempFileDirectory(tmpfile); + + tmpfile->Close(); + + destpath = tmpfilepath; + destpath += ".deletefolder"; + ASSERT_FALSE(XFILE::CFile::Exists(destpath)); + + CFileItemPtr item(new CFileItem(destpath)); + item->SetPath(destpath); + item->m_bIsFolder = true; + item->Select(true); + items.Add(item); + + job.SetFileOperation(CFileOperationJob::ActionCreateFolder, items, tmpfiledirectory); + EXPECT_EQ(CFileOperationJob::ActionCreateFolder, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CDirectory::Exists(destpath)); + + job.SetFileOperation(CFileOperationJob::ActionDeleteFolder, items, tmpfiledirectory); + EXPECT_EQ(CFileOperationJob::ActionDeleteFolder, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_FALSE(XFILE::CDirectory::Exists(destpath)); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); +} + +TEST(TestFileOperationJob, GetFunctions) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destfile; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + tmpfile->Close(); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + items.Add(item); + + std::string destpath = URIUtils::GetDirectory(tmpfilepath); + destpath = URIUtils::AddFileToFolder(destpath, "getfunctions"); + destfile = URIUtils::AddFileToFolder(destpath, URIUtils::GetFileName(tmpfilepath)); + ASSERT_FALSE(XFILE::CFile::Exists(destfile)); + + job.SetFileOperation(CFileOperationJob::ActionCopy, items, destpath); + EXPECT_EQ(CFileOperationJob::ActionCopy, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CFile::Exists(tmpfilepath)); + EXPECT_TRUE(XFILE::CFile::Exists(destfile)); + + std::cout << "GetAverageSpeed(): " << job.GetAverageSpeed() << std::endl; + std::cout << "GetCurrentOperation(): " << job.GetCurrentOperation() << std::endl; + std::cout << "GetCurrentFile(): " << job.GetCurrentFile() << std::endl; + EXPECT_FALSE(job.GetItems().IsEmpty()); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); + EXPECT_TRUE(XFILE::CFile::Delete(destfile)); + EXPECT_TRUE(XFILE::CDirectory::Remove(destpath)); +} diff --git a/xbmc/utils/test/TestFileUtils.cpp b/xbmc/utils/test/TestFileUtils.cpp new file mode 100644 index 0000000..720e82d --- /dev/null +++ b/xbmc/utils/test/TestFileUtils.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "filesystem/File.h" +#include "test/TestUtils.h" +#include "utils/FileUtils.h" + +#include + +TEST(TestFileUtils, DeleteItem_CFileItemPtr) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + tmpfile->Close(); //Close tmpfile before we try to delete it + EXPECT_TRUE(CFileUtils::DeleteItem(item)); +} + +TEST(TestFileUtils, DeleteItemString) +{ + XFILE::CFile *tmpfile; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfile->Close(); //Close tmpfile before we try to delete it + EXPECT_TRUE(CFileUtils::DeleteItem(XBMC_TEMPFILEPATH(tmpfile))); +} + +/* Executing RenameFile() requires input from the user */ +// static bool RenameFile(const std::string &strFile); diff --git a/xbmc/utils/test/TestGlobalsHandling.cpp b/xbmc/utils/test/TestGlobalsHandling.cpp new file mode 100644 index 0000000..5b8d26a --- /dev/null +++ b/xbmc/utils/test/TestGlobalsHandling.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/test/TestGlobalsHandlingPattern1.h" + +#include + +using namespace xbmcutil; +using namespace test; + +bool TestGlobalPattern1::ctorCalled = false; +bool TestGlobalPattern1::dtorCalled = false; + +TEST(TestGlobal, Pattern1) +{ + EXPECT_TRUE(TestGlobalPattern1::ctorCalled); + { + std::shared_ptr ptr = g_testGlobalPattern1Ref; + } +} diff --git a/xbmc/utils/test/TestGlobalsHandlingPattern1.h b/xbmc/utils/test/TestGlobalsHandlingPattern1.h new file mode 100644 index 0000000..92088b8 --- /dev/null +++ b/xbmc/utils/test/TestGlobalsHandlingPattern1.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/GlobalsHandling.h" + +#include + +namespace xbmcutil +{ + namespace test + { + class TestGlobalPattern1 + { + public: + static bool ctorCalled; + static bool dtorCalled; + + int somethingToAccess = 0; + + TestGlobalPattern1() { ctorCalled = true; } + ~TestGlobalPattern1() + { + std::cout << "Clean shutdown of TestGlobalPattern1" << std::endl << std::flush; + dtorCalled = true; + } + + void beHappy() { if (somethingToAccess) throw somethingToAccess; } + }; + } +} + +XBMC_GLOBAL_REF(xbmcutil::test::TestGlobalPattern1,g_testGlobalPattern1); +#define g_testGlobalPattern1 XBMC_GLOBAL_USE(xbmcutil::test::TestGlobalPattern1) diff --git a/xbmc/utils/test/TestHTMLUtil.cpp b/xbmc/utils/test/TestHTMLUtil.cpp new file mode 100644 index 0000000..7d0e515 --- /dev/null +++ b/xbmc/utils/test/TestHTMLUtil.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/HTMLUtil.h" + +#include + +TEST(TestHTMLUtil, RemoveTags) +{ + std::string str; + str = "\n" + "\n" + " \n" + " \n" + "

blah blah blah

\n" + " \n" + " \n" + "\n"; + HTML::CHTMLUtil::RemoveTags(str); + EXPECT_STREQ("\n\n \n \n blah blah blah\n \n \n\n", + str.c_str()); +} + +TEST(TestHTMLUtil, ConvertHTMLToW) +{ + std::wstring inw, refstrw, varstrw; + inw = L"å&€"; + refstrw = L"\u00e5&\u20ac"; + HTML::CHTMLUtil::ConvertHTMLToW(inw, varstrw); + EXPECT_STREQ(refstrw.c_str(), varstrw.c_str()); +} diff --git a/xbmc/utils/test/TestHttpHeader.cpp b/xbmc/utils/test/TestHttpHeader.cpp new file mode 100644 index 0000000..1aeecc7 --- /dev/null +++ b/xbmc/utils/test/TestHttpHeader.cpp @@ -0,0 +1,505 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/HttpHeader.h" + +#include + +#include + +#define CHECK_CNT_TYPE_NAME "Content-Type" +#define CHECK_CONTENT_TYPE_HTML "text/html" +#define CHECK_CONTENT_TYPE_HTML_CHRS "text/html; charset=WINDOWS-1251" +#define CHECK_CONTENT_TYPE_XML_CHRS "text/xml; charset=uTf-8" +#define CHECK_CONTENT_TYPE_TEXT "text/plain" +#define CHECK_DATE_NAME "Date" +#define CHECK_DATE_VALUE1 "Thu, 09 Jan 2014 17:58:30 GMT" +#define CHECK_DATE_VALUE2 "Thu, 09 Jan 2014 20:21:20 GMT" +#define CHECK_DATE_VALUE3 "Thu, 09 Jan 2014 20:25:02 GMT" +#define CHECK_PROT_LINE_200 "HTTP/1.1 200 OK" +#define CHECK_PROT_LINE_301 "HTTP/1.1 301 Moved Permanently" + +#define CHECK_HEADER_SMPL CHECK_PROT_LINE_200 "\r\n" \ + CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML "\r\n" \ + "\r\n" + +#define CHECK_HEADER_L1 CHECK_PROT_LINE_200 "\r\n" \ + "Server: nginx/1.4.4\r\n" \ + CHECK_DATE_NAME ": " CHECK_DATE_VALUE1 "\r\n" \ + CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML_CHRS "\r\n" \ + "Transfer-Encoding: chunked\r\n" \ + "Connection: close\r\n" \ + "Set-Cookie: PHPSESSID=90857d437518db8f0944ca012761048a; path=/; domain=example.com\r\n" \ + "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n" \ + "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" \ + "Pragma: no-cache\r\n" \ + "Set-Cookie: user_country=ot; expires=Thu, 09-Jan-2014 18:58:30 GMT; path=/; domain=.example.com\r\n" \ + "\r\n" + +#define CHECK_HEADER_R CHECK_PROT_LINE_301 "\r\n" \ + "Server: nginx/1.4.4\r\n" \ + CHECK_DATE_NAME ": " CHECK_DATE_VALUE2 "\r\n" \ + CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML "\r\n" \ + "Content-Length: 150\r\n" \ + "Connection: close\r\n" \ + "Location: http://www.Example.Com\r\n" \ + "\r\n" + +#define CHECK_HEADER_L2 CHECK_PROT_LINE_200 "\r\n" \ + CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\n" \ + "Server: Apache/2.4.7 (Unix) mod_wsgi/3.4 Python/2.7.5 OpenSSL/1.0.1e\r\n" \ + "Last-Modified: Thu, 09 Jan 2014 20:10:28 GMT\r\n" \ + "ETag: \"9a97-4ef8f335ebd10\"\r\n" \ + "Accept-Ranges: bytes\r\n" \ + "Content-Length: 33355\r\n" \ + "Vary: Accept-Encoding\r\n" \ + "Cache-Control: max-age=3600\r\n" \ + "Expires: Thu, 09 Jan 2014 21:25:02 GMT\r\n" \ + "Connection: close\r\n" \ + CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_XML_CHRS "\r\n" \ + "\r\n" + +// local helper function: replace substrings +std::string strReplace(const std::string& str, const std::string& from, const std::string& to) +{ + std::string result; + size_t prevPos = 0; + size_t pos; + const size_t len = str.length(); + + do + { + pos = str.find(from, prevPos); + result.append(str, prevPos, pos - prevPos); + if (pos >= len) + break; + result.append(to); + prevPos = pos + from.length(); + } while (true); + + return result; +} + +TEST(TestHttpHeader, General) +{ + /* check freshly created object */ + CHttpHeader testHdr; + EXPECT_TRUE(testHdr.GetHeader().empty()) << "Newly created object is not empty"; + EXPECT_TRUE(testHdr.GetProtoLine().empty()) << "Newly created object has non-empty protocol line"; + EXPECT_TRUE(testHdr.GetMimeType().empty()) << "Newly created object has non-empty MIME-type"; + EXPECT_TRUE(testHdr.GetCharset().empty()) << "Newly created object has non-empty charset"; + EXPECT_TRUE(testHdr.GetValue("foo").empty()) << "Newly created object has some parameter"; + EXPECT_TRUE(testHdr.GetValues("bar").empty()) << "Newly created object has some parameters"; + EXPECT_FALSE(testHdr.IsHeaderDone()) << "Newly created object has \"parsing finished\" state"; + + /* check general functions in simple case */ + testHdr.Parse(CHECK_HEADER_SMPL); + EXPECT_FALSE(testHdr.GetHeader().empty()) << "Parsed header is empty"; + EXPECT_FALSE(testHdr.GetProtoLine().empty()) << "Parsed header has empty protocol line"; + EXPECT_FALSE(testHdr.GetMimeType().empty()) << "Parsed header has empty MIME-type"; + EXPECT_FALSE(testHdr.GetValue(CHECK_CNT_TYPE_NAME).empty()) << "Parsed header has empty \"" CHECK_CNT_TYPE_NAME "\" parameter"; + EXPECT_FALSE(testHdr.GetValues(CHECK_CNT_TYPE_NAME).empty()) << "Parsed header has no \"" CHECK_CNT_TYPE_NAME "\" parameters"; + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Parsed header has \"parsing not finished\" state"; + + /* check clearing of object */ + testHdr.Clear(); + EXPECT_TRUE(testHdr.GetHeader().empty()) << "Cleared object is not empty"; + EXPECT_TRUE(testHdr.GetProtoLine().empty()) << "Cleared object has non-empty protocol line"; + EXPECT_TRUE(testHdr.GetMimeType().empty()) << "Cleared object has non-empty MIME-type"; + EXPECT_TRUE(testHdr.GetCharset().empty()) << "Cleared object has non-empty charset"; + EXPECT_TRUE(testHdr.GetValue(CHECK_CNT_TYPE_NAME).empty()) << "Cleared object has some parameter"; + EXPECT_TRUE(testHdr.GetValues(CHECK_CNT_TYPE_NAME).empty()) << "Cleared object has some parameters"; + EXPECT_FALSE(testHdr.IsHeaderDone()) << "Cleared object has \"parsing finished\" state"; + + /* check general functions after object clearing */ + testHdr.Parse(CHECK_HEADER_R); + EXPECT_FALSE(testHdr.GetHeader().empty()) << "Parsed header is empty"; + EXPECT_FALSE(testHdr.GetProtoLine().empty()) << "Parsed header has empty protocol line"; + EXPECT_FALSE(testHdr.GetMimeType().empty()) << "Parsed header has empty MIME-type"; + EXPECT_FALSE(testHdr.GetValue(CHECK_CNT_TYPE_NAME).empty()) << "Parsed header has empty \"" CHECK_CNT_TYPE_NAME "\" parameter"; + EXPECT_FALSE(testHdr.GetValues(CHECK_CNT_TYPE_NAME).empty()) << "Parsed header has no \"" CHECK_CNT_TYPE_NAME "\" parameters"; + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Parsed header has \"parsing not finished\" state"; +} + +TEST(TestHttpHeader, Parse) +{ + CHttpHeader testHdr; + + /* check parsing line-by-line */ + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + EXPECT_FALSE(testHdr.IsHeaderDone()) << "Not completed header has \"parsing finished\" state"; + testHdr.Parse(CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML "\r\n"); + EXPECT_FALSE(testHdr.IsHeaderDone()) << "Not completed header has \"parsing finished\" state"; + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ(CHECK_PROT_LINE_200, testHdr.GetProtoLine().c_str()) << "Wrong protocol line"; + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + + /* check autoclearing when new header is parsed */ + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + EXPECT_FALSE(testHdr.IsHeaderDone()) << "Not completed header has \"parsing finished\" state"; + EXPECT_TRUE(testHdr.GetValues(CHECK_CNT_TYPE_NAME).empty()) << "Cleared header has some parameters"; + testHdr.Clear(); + EXPECT_TRUE(testHdr.GetHeader().empty()) << "Cleared object is not empty"; + + /* general check parsing */ + testHdr.Parse(CHECK_HEADER_SMPL); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STRCASEEQ(CHECK_HEADER_SMPL, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + testHdr.Parse(CHECK_HEADER_L1); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STRCASEEQ(CHECK_HEADER_L1, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_STREQ("Thu, 09 Jan 2014 17:58:30 GMT", testHdr.GetValue("Date").c_str()); // case-sensitive match of value + testHdr.Parse(CHECK_HEADER_L2); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STRCASEEQ(CHECK_HEADER_L2, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_STREQ("Thu, 09 Jan 2014 20:10:28 GMT", testHdr.GetValue("Last-Modified").c_str()); // case-sensitive match of value + testHdr.Parse(CHECK_HEADER_R); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STRCASEEQ(CHECK_HEADER_R, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("Location").c_str()); // case-sensitive match of value + + /* check support for '\n' line endings */ + testHdr.Parse(strReplace(CHECK_HEADER_SMPL, "\r\n", "\n")); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STRCASEEQ(CHECK_HEADER_SMPL, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + testHdr.Parse(strReplace(CHECK_HEADER_L1, "\r\n", "\n")); + EXPECT_STRCASEEQ(CHECK_HEADER_L1, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + testHdr.Parse(strReplace(CHECK_HEADER_L2, "\r\n", "\n")); + EXPECT_STRCASEEQ(CHECK_HEADER_L2, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + testHdr.Parse(CHECK_PROT_LINE_200 "\n" CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML "\r\n"); // mixed "\n" and "\r\n" + testHdr.Parse("\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STRCASEEQ(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML "\r\n\r\n", testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + + /* check trimming of whitespaces for parameter name and value */ + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML "\r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML " \r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME ":" CHECK_CONTENT_TYPE_HTML " \r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME ":\t" CHECK_CONTENT_TYPE_HTML " \t \r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME ":\t " CHECK_CONTENT_TYPE_HTML " \t \r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME "\t:" CHECK_CONTENT_TYPE_HTML " \t \r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME " \t : " CHECK_CONTENT_TYPE_HTML " \t \r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; +} + +TEST(TestHttpHeader, Parse_Multiline) +{ + CHttpHeader testHdr; + + /* Check multiline parameter parsing line-by-line */ + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse(CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\n"); + testHdr.Parse("X-Comment: This\r\n"); // between singleline parameters + testHdr.Parse(" is\r\n"); + testHdr.Parse(" multi\r\n"); + testHdr.Parse(" line\r\n"); + testHdr.Parse(" value\r\n"); + testHdr.Parse(CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_TEXT "\r\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse("X-Comment: This\r\n"); // first parameter + testHdr.Parse(" is\r\n"); + testHdr.Parse(" multi\r\n"); + testHdr.Parse(" line\r\n"); + testHdr.Parse(" value\r\n"); + testHdr.Parse(CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_TEXT "\r\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse(CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\n"); + testHdr.Parse("X-Comment: This\r\n"); // last parameter + testHdr.Parse(" is\r\n"); + testHdr.Parse(" multi\r\n"); + testHdr.Parse(" line\r\n"); + testHdr.Parse(" value\r\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse("X-Comment: This\r\n"); // the only parameter + testHdr.Parse(" is\r\n"); + testHdr.Parse(" multi\r\n"); + testHdr.Parse(" line\r\n"); + testHdr.Parse(" value\r\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse("X-Comment: This\n"); // the only parameter with mixed ending style + testHdr.Parse(" is\r\n"); + testHdr.Parse(" multi\n"); + testHdr.Parse(" line\r\n"); + testHdr.Parse(" value\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + /* Check multiline parameter parsing as one line */ + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\nX-Comment: This\r\n is\r\n multi\r\n line\r\n value\r\n" \ + CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_TEXT "\r\n\r\n"); // between singleline parameters + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nX-Comment: This\r\n is\r\n multi\r\n line\r\n value\r\n" \ + CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_TEXT "\r\n\r\n"); // first parameter + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\nX-Comment: This\r\n is\r\n multi\r\n line\r\n value\r\n\r\n"); // last parameter + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nX-Comment: This\r\n is\r\n multi\r\n line\r\n value\r\n\r\n"); // the only parameter + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nX-Comment: This\n is\r\n multi\r\n line\n value\r\n\n"); // the only parameter with mixed ending style + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + /* Check multiline parameter parsing as mixed one/many lines */ + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nX-Comment: This\n is\r\n multi\r\n"); + testHdr.Parse(" line\n value\r\n\n"); // the only parameter with mixed ending style + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + /* Check parsing of multiline parameter with ':' in value */ + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nX-Comment: This\r\n is:\r\n mul:ti\r\n"); + testHdr.Parse(" :line\r\n valu:e\r\n\n"); // the only parameter + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is: mul:ti :line valu:e", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + /* Check multiline parameter parsing with trimming */ + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse(CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\n"); + testHdr.Parse("Server: Apache/2.4.7 (Unix)\r\n"); // last parameter, line-by-line parsing + testHdr.Parse(" mod_wsgi/3.4 \r\n"); + testHdr.Parse("\tPython/2.7.5\r\n"); + testHdr.Parse("\t \t \tOpenSSL/1.0.1e\r\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_GE(strlen("Apache/2.4.7 (Unix) mod_wsgi/3.4 \tPython/2.7.5\t \t \tOpenSSL/1.0.1e"), testHdr.GetValue("Server").length()) << "Length of miltiline value is greater than length of original string"; + EXPECT_LE(strlen("Apache/2.4.7 (Unix) mod_wsgi/3.4 Python/2.7.5 OpenSSL/1.0.1e"), testHdr.GetValue("Server").length()) << "Length of miltiline value is less than length of trimmed original string"; + EXPECT_STREQ("Apache/2.4.7(Unix)mod_wsgi/3.4Python/2.7.5OpenSSL/1.0.1e", strReplace(strReplace(testHdr.GetValue("Server"), " ", ""), "\t", "").c_str()) << "Multiline value with removed whitespaces does not match original string with removed whitespaces"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse(CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\n"); + testHdr.Parse("Server: Apache/2.4.7 (Unix)\r\n mod_wsgi/3.4 \n"); // last parameter, mixed line-by-line/one line parsing, mixed line ending + testHdr.Parse("\tPython/2.7.5\n\t \t \tOpenSSL/1.0.1e\r\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_GE(strlen("Apache/2.4.7 (Unix) mod_wsgi/3.4 \tPython/2.7.5\t \t \tOpenSSL/1.0.1e"), testHdr.GetValue("Server").length()) << "Length of miltiline value is greater than length of original string"; + EXPECT_LE(strlen("Apache/2.4.7 (Unix) mod_wsgi/3.4 Python/2.7.5 OpenSSL/1.0.1e"), testHdr.GetValue("Server").length()) << "Length of miltiline value is less than length of trimmed original string"; + EXPECT_STREQ("Apache/2.4.7(Unix)mod_wsgi/3.4Python/2.7.5OpenSSL/1.0.1e", strReplace(strReplace(testHdr.GetValue("Server"), " ", ""), "\t", "").c_str()) << "Multiline value with removed whitespaces does not match original string with removed whitespaces"; +} + +TEST(TestHttpHeader, GetValue) +{ + CHttpHeader testHdr; + + /* Check that all parameters values can be retrieved */ + testHdr.Parse(CHECK_HEADER_R); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("nginx/1.4.4", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + EXPECT_STREQ(CHECK_DATE_VALUE2, testHdr.GetValue(CHECK_DATE_NAME).c_str()) << "Wrong parameter value"; + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong parameter value"; + EXPECT_STREQ("150", testHdr.GetValue("Content-Length").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("close", testHdr.GetValue("Connection").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("Location").c_str()) << "Wrong parameter value"; + EXPECT_TRUE(testHdr.GetValue("foo").empty()) << "Some value is returned for non-existed parameter"; + + /* Check that all parameters values can be retrieved in random order */ + testHdr.Parse(CHECK_HEADER_R); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("Location").c_str()) << "Wrong parameter value"; + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong parameter value"; + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("Location").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("close", testHdr.GetValue("Connection").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("nginx/1.4.4", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("150", testHdr.GetValue("Content-Length").c_str()) << "Wrong parameter value"; + EXPECT_STREQ(CHECK_DATE_VALUE2, testHdr.GetValue(CHECK_DATE_NAME).c_str()) << "Wrong parameter value"; + EXPECT_STREQ("nginx/1.4.4", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + EXPECT_TRUE(testHdr.GetValue("foo").empty()) << "Some value is returned for non-existed parameter"; + + /* Check that parameters name is case-insensitive and value is case-sensitive*/ + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("location").c_str()) << "Wrong parameter value for lowercase name"; + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("LOCATION").c_str()) << "Wrong parameter value for UPPERCASE name"; + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("LoCAtIOn").c_str()) << "Wrong parameter value for MiXEdcASe name"; + + /* Check value of last added parameter with the same name is returned */ + testHdr.Parse(CHECK_HEADER_L1); + EXPECT_STREQ("close", testHdr.GetValue("Connection").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("user_country=ot; expires=Thu, 09-Jan-2014 18:58:30 GMT; path=/; domain=.example.com", testHdr.GetValue("Set-Cookie").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("user_country=ot; expires=Thu, 09-Jan-2014 18:58:30 GMT; path=/; domain=.example.com", testHdr.GetValue("set-cookie").c_str()) << "Wrong parameter value for lowercase name"; +} + +TEST(TestHttpHeader, GetValues) +{ + CHttpHeader testHdr; + + /* Check that all parameter values can be retrieved and order of values is correct */ + testHdr.Parse(CHECK_HEADER_L1); + EXPECT_EQ(1U, testHdr.GetValues("Server").size()) << "Wrong number of values for parameter \"Server\""; + EXPECT_STREQ("nginx/1.4.4", testHdr.GetValues("Server")[0].c_str()) << "Wrong parameter value"; + EXPECT_EQ(2U, testHdr.GetValues("Set-Cookie").size()) << "Wrong number of values for parameter \"Set-Cookie\""; + EXPECT_STREQ("PHPSESSID=90857d437518db8f0944ca012761048a; path=/; domain=example.com", testHdr.GetValues("Set-Cookie")[0].c_str()) << "Wrong parameter value"; + EXPECT_STREQ("user_country=ot; expires=Thu, 09-Jan-2014 18:58:30 GMT; path=/; domain=.example.com", testHdr.GetValues("Set-Cookie")[1].c_str()) << "Wrong parameter value"; + EXPECT_TRUE(testHdr.GetValues("foo").empty()) << "Some values are returned for non-existed parameter"; +} + +TEST(TestHttpHeader, AddParam) +{ + CHttpHeader testHdr; + + /* General functionality */ + testHdr.AddParam("server", "Microsoft-IIS/8.0"); + EXPECT_STREQ("Microsoft-IIS/8.0", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + + /* Interfere with parsing */ + EXPECT_FALSE(testHdr.IsHeaderDone()) << "\"AddParam\" set \"parsing finished\" state"; + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nServer: nginx/1.4.4\r\n\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Parsed header has \"parsing not finished\" state"; + EXPECT_STREQ("nginx/1.4.4", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + testHdr.AddParam("server", "Apache/2.4.7"); + EXPECT_STREQ("Apache/2.4.7", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + EXPECT_EQ(3U, testHdr.GetValues("Server").size()) << "Wrong number of values for parameter \"Server\""; + + /* Multiple values */ + testHdr.AddParam("X-foo", "bar1"); + testHdr.AddParam("x-foo", "bar2"); + testHdr.AddParam("x-fOO", "bar3"); + EXPECT_EQ(3U, testHdr.GetValues("X-FOO").size()) << "Wrong number of values for parameter \"X-foo\""; + EXPECT_STREQ("bar1", testHdr.GetValues("X-FOo")[0].c_str()) << "Wrong parameter value"; + EXPECT_STREQ("bar2", testHdr.GetValues("X-fOo")[1].c_str()) << "Wrong parameter value"; + EXPECT_STREQ("bar3", testHdr.GetValues("x-fOo")[2].c_str()) << "Wrong parameter value"; + EXPECT_STREQ("bar3", testHdr.GetValue("x-foo").c_str()) << "Wrong parameter value"; + + /* Overwrite value */ + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Parsed header has \"parsing not finished\" state"; + testHdr.AddParam("x-fOO", "superbar", true); + EXPECT_EQ(1U, testHdr.GetValues("X-FoO").size()) << "Wrong number of values for parameter \"X-foo\""; + EXPECT_STREQ("superbar", testHdr.GetValue("x-foo").c_str()) << "Wrong parameter value"; + + /* Check name trimming */ + testHdr.AddParam("\tx-fOO\t ", "bar"); + EXPECT_EQ(2U, testHdr.GetValues("X-FoO").size()) << "Wrong number of values for parameter \"X-foo\""; + EXPECT_STREQ("bar", testHdr.GetValue("x-foo").c_str()) << "Wrong parameter value"; + testHdr.AddParam(" SerVer \t ", "fakeSrv", true); + EXPECT_EQ(1U, testHdr.GetValues("serveR").size()) << "Wrong number of values for parameter \"Server\""; + EXPECT_STREQ("fakeSrv", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + + /* Check value trimming */ + testHdr.AddParam("X-TestParam", " testValue1"); + EXPECT_STREQ("testValue1", testHdr.GetValue("X-TestParam").c_str()) << "Wrong parameter value"; + testHdr.AddParam("X-TestParam", "\ttestValue2 and more \t "); + EXPECT_STREQ("testValue2 and more", testHdr.GetValue("X-TestParam").c_str()) << "Wrong parameter value"; + + /* Empty name or value */ + testHdr.Clear(); + testHdr.AddParam("X-TestParam", " "); + EXPECT_TRUE(testHdr.GetHeader().empty()) << "Parameter with empty value was added"; + testHdr.AddParam("\t\t", "value"); + EXPECT_TRUE(testHdr.GetHeader().empty()); + testHdr.AddParam(" ", "\t"); + EXPECT_TRUE(testHdr.GetHeader().empty()); +} + +TEST(TestHttpHeader, GetMimeType) +{ + CHttpHeader testHdr; + + /* General functionality */ + EXPECT_TRUE(testHdr.GetMimeType().empty()) << "Newly created object has non-empty MIME-type"; + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nServer: nginx/1.4.4\r\n\r\n"); + EXPECT_TRUE(testHdr.GetMimeType().empty()) << "Non-empty MIME-type for header without MIME-type"; + testHdr.Parse(CHECK_HEADER_SMPL); + EXPECT_STREQ("text/html", testHdr.GetMimeType().c_str()) << "Wrong MIME-type"; + testHdr.Parse(CHECK_HEADER_L1); + EXPECT_STREQ("text/html", testHdr.GetMimeType().c_str()) << "Wrong MIME-type"; + testHdr.Parse(CHECK_HEADER_L2); + EXPECT_STREQ("text/xml", testHdr.GetMimeType().c_str()) << "Wrong MIME-type"; + testHdr.Parse(CHECK_HEADER_R); + EXPECT_STREQ("text/html", testHdr.GetMimeType().c_str()) << "Wrong MIME-type"; + + /* Overwrite by AddParam */ + testHdr.AddParam(CHECK_CNT_TYPE_NAME, CHECK_CONTENT_TYPE_TEXT); + EXPECT_STREQ(CHECK_CONTENT_TYPE_TEXT, testHdr.GetMimeType().c_str()) << "MIME-type was not overwritten by \"AddParam\""; + + /* Correct trimming */ + testHdr.AddParam(CHECK_CNT_TYPE_NAME, " " CHECK_CONTENT_TYPE_TEXT " \t ;foo=bar"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_TEXT, testHdr.GetMimeType().c_str()) << "MIME-type is not trimmed correctly"; +} + + +TEST(TestHttpHeader, GetCharset) +{ + CHttpHeader testHdr; + + /* General functionality */ + EXPECT_TRUE(testHdr.GetCharset().empty()) << "Newly created object has non-empty charset"; + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nServer: nginx/1.4.4\r\n\r\n"); + EXPECT_TRUE(testHdr.GetCharset().empty()) << "Non-empty charset for header without charset"; + testHdr.Parse(CHECK_HEADER_SMPL); + EXPECT_TRUE(testHdr.GetCharset().empty()) << "Non-empty charset for header without charset"; + testHdr.Parse(CHECK_HEADER_L1); + EXPECT_STREQ("WINDOWS-1251", testHdr.GetCharset().c_str()) << "Wrong charset value"; + testHdr.Parse(CHECK_HEADER_L2); + EXPECT_STREQ("UTF-8", testHdr.GetCharset().c_str()) << "Wrong charset value"; + + /* Overwrite by AddParam */ + testHdr.AddParam(CHECK_CNT_TYPE_NAME, CHECK_CONTENT_TYPE_TEXT "; charset=WINDOWS-1252"); + EXPECT_STREQ("WINDOWS-1252", testHdr.GetCharset().c_str()) << "Charset was not overwritten by \"AddParam\""; + + /* Correct trimming */ + testHdr.AddParam(CHECK_CNT_TYPE_NAME, "text/plain;charset=WINDOWS-1251"); + EXPECT_STREQ("WINDOWS-1251", testHdr.GetCharset().c_str()) << "Wrong charset value"; + testHdr.AddParam(CHECK_CNT_TYPE_NAME, "text/plain ;\tcharset=US-AScII\t"); + EXPECT_STREQ("US-ASCII", testHdr.GetCharset().c_str()) << "Wrong charset value"; + testHdr.AddParam(CHECK_CNT_TYPE_NAME, "text/html ; \tcharset=\"uTF-8\"\t"); + EXPECT_STREQ("UTF-8", testHdr.GetCharset().c_str()) << "Wrong charset value"; + testHdr.AddParam(CHECK_CNT_TYPE_NAME, " \ttext/xml\t;\tcharset=uTF-16 "); + EXPECT_STREQ("UTF-16", testHdr.GetCharset().c_str()) << "Wrong charset value"; +} diff --git a/xbmc/utils/test/TestHttpParser.cpp b/xbmc/utils/test/TestHttpParser.cpp new file mode 100644 index 0000000..1eb2932 --- /dev/null +++ b/xbmc/utils/test/TestHttpParser.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/HttpParser.h" + +#include + +TEST(TestHttpParser, General) +{ + HttpParser a; + std::string str = "POST /path/script.cgi HTTP/1.0\r\n" + "From: amejia@xbmc.org\r\n" + "User-Agent: XBMC/snapshot (compatible; MSIE 5.5; Windows NT" + " 4.0)\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: 35\r\n" + "\r\n" + "home=amejia&favorite+flavor=orange\r\n"; + std::string refstr, varstr; + + EXPECT_EQ(a.Done, a.addBytes(str.c_str(), str.length())); + + refstr = "POST"; + varstr = a.getMethod(); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "/path/script.cgi"; + varstr = a.getUri(); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = a.getQueryString(); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "home=amejia&favorite+flavor=orange\r\n"; + varstr = a.getBody(); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "application/x-www-form-urlencoded"; + varstr = a.getValue("content-type"); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + EXPECT_EQ((unsigned)35, a.getContentLength()); +} diff --git a/xbmc/utils/test/TestHttpRangeUtils.cpp b/xbmc/utils/test/TestHttpRangeUtils.cpp new file mode 100644 index 0000000..f988f10 --- /dev/null +++ b/xbmc/utils/test/TestHttpRangeUtils.cpp @@ -0,0 +1,887 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/HttpRangeUtils.h" + +#include + +#define RANGES_START "bytes=" + +static const uint64_t DefaultFirstPosition = 1; +static const uint64_t DefaultLastPosition = 0; +static const uint64_t DefaultLength = 0; +static const void* DefaultData = NULL; + +TEST(TestHttpRange, FirstPosition) +{ + const uint64_t expectedFirstPosition = 25; + + CHttpRange range; + EXPECT_EQ(DefaultFirstPosition, range.GetFirstPosition()); + + range.SetFirstPosition(expectedFirstPosition); + EXPECT_EQ(expectedFirstPosition, range.GetFirstPosition()); +} + +TEST(TestHttpRange, LastPosition) +{ + const uint64_t expectedLastPosition = 25; + + CHttpRange range; + EXPECT_EQ(DefaultLastPosition, range.GetLastPosition()); + + range.SetLastPosition(expectedLastPosition); + EXPECT_EQ(expectedLastPosition, range.GetLastPosition()); +} + +TEST(TestHttpRange, Length) +{ + const uint64_t expectedFirstPosition = 10; + const uint64_t expectedLastPosition = 25; + const uint64_t expectedLength = expectedLastPosition - expectedFirstPosition + 1; + + CHttpRange range; + EXPECT_EQ(DefaultLength, range.GetLength()); + + range.SetFirstPosition(expectedFirstPosition); + range.SetLastPosition(expectedLastPosition); + EXPECT_EQ(expectedLength, range.GetLength()); + + CHttpRange range_length; + range.SetFirstPosition(expectedFirstPosition); + range.SetLength(expectedLength); + EXPECT_EQ(expectedLastPosition, range.GetLastPosition()); + EXPECT_EQ(expectedLength, range.GetLength()); +} + +TEST(TestHttpRange, IsValid) +{ + const uint64_t validFirstPosition = 10; + const uint64_t validLastPosition = 25; + const uint64_t invalidLastPosition = 5; + + CHttpRange range; + EXPECT_FALSE(range.IsValid()); + + range.SetFirstPosition(validFirstPosition); + EXPECT_FALSE(range.IsValid()); + + range.SetLastPosition(invalidLastPosition); + EXPECT_FALSE(range.IsValid()); + + range.SetLastPosition(validLastPosition); + EXPECT_TRUE(range.IsValid()); +} + +TEST(TestHttpRange, Ctor) +{ + const uint64_t validFirstPosition = 10; + const uint64_t validLastPosition = 25; + const uint64_t invalidLastPosition = 5; + const uint64_t validLength = validLastPosition - validFirstPosition + 1; + + CHttpRange range_invalid(validFirstPosition, invalidLastPosition); + EXPECT_EQ(validFirstPosition, range_invalid.GetFirstPosition()); + EXPECT_EQ(invalidLastPosition, range_invalid.GetLastPosition()); + EXPECT_EQ(DefaultLength, range_invalid.GetLength()); + EXPECT_FALSE(range_invalid.IsValid()); + + CHttpRange range_valid(validFirstPosition, validLastPosition); + EXPECT_EQ(validFirstPosition, range_valid.GetFirstPosition()); + EXPECT_EQ(validLastPosition, range_valid.GetLastPosition()); + EXPECT_EQ(validLength, range_valid.GetLength()); + EXPECT_TRUE(range_valid.IsValid()); +} + +TEST(TestHttpResponseRange, SetData) +{ + const uint64_t validFirstPosition = 1; + const uint64_t validLastPosition = 2; + const uint64_t validLength = validLastPosition - validFirstPosition + 1; + const char* validData = "test"; + const void* invalidData = DefaultData; + const size_t validDataLength = strlen(validData); + const size_t invalidDataLength = 1; + + CHttpResponseRange range; + EXPECT_EQ(DefaultData, range.GetData()); + EXPECT_FALSE(range.IsValid()); + + range.SetData(invalidData); + EXPECT_EQ(invalidData, range.GetData()); + EXPECT_FALSE(range.IsValid()); + + range.SetData(validData); + EXPECT_EQ(validData, range.GetData()); + EXPECT_FALSE(range.IsValid()); + + range.SetData(invalidData, 0); + EXPECT_EQ(validData, range.GetData()); + EXPECT_FALSE(range.IsValid()); + + range.SetData(invalidData, invalidDataLength); + EXPECT_EQ(invalidData, range.GetData()); + EXPECT_FALSE(range.IsValid()); + + range.SetData(validData, validDataLength); + EXPECT_EQ(validData, range.GetData()); + EXPECT_EQ(0U, range.GetFirstPosition()); + EXPECT_EQ(validDataLength - 1, range.GetLastPosition()); + EXPECT_EQ(validDataLength, range.GetLength()); + EXPECT_TRUE(range.IsValid()); + + range.SetData(invalidData, 0, 0); + EXPECT_EQ(invalidData, range.GetData()); + EXPECT_FALSE(range.IsValid()); + + range.SetData(validData, validFirstPosition, validLastPosition); + EXPECT_EQ(validData, range.GetData()); + EXPECT_EQ(validFirstPosition, range.GetFirstPosition()); + EXPECT_EQ(validLastPosition, range.GetLastPosition()); + EXPECT_EQ(validLength, range.GetLength()); + EXPECT_TRUE(range.IsValid()); +} + +TEST(TestHttpRanges, Ctor) +{ + CHttpRange range; + uint64_t position; + + CHttpRanges ranges_empty; + + EXPECT_EQ(0U, ranges_empty.Size()); + EXPECT_TRUE(ranges_empty.Get().empty()); + + EXPECT_FALSE(ranges_empty.Get(0, range)); + EXPECT_FALSE(ranges_empty.GetFirst(range)); + EXPECT_FALSE(ranges_empty.GetLast(range)); + + EXPECT_FALSE(ranges_empty.GetFirstPosition(position)); + EXPECT_FALSE(ranges_empty.GetLastPosition(position)); + EXPECT_EQ(0U, ranges_empty.GetLength()); + EXPECT_FALSE(ranges_empty.GetTotalRange(range)); +} + +TEST(TestHttpRanges, GetAll) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + const HttpRanges& ranges_raw_get = ranges.Get(); + ASSERT_EQ(ranges_raw.size(), ranges_raw_get.size()); + + for (size_t i = 0; i < ranges_raw.size(); ++i) + EXPECT_EQ(ranges_raw.at(i), ranges_raw_get.at(i)); +} + +TEST(TestHttpRanges, GetIndex) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + CHttpRange range; + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range_0, range); + + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_1, range); + + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range_2, range); + + EXPECT_FALSE(ranges.Get(3, range)); +} + +TEST(TestHttpRanges, GetFirst) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + CHttpRange range; + EXPECT_TRUE(ranges.GetFirst(range)); + EXPECT_EQ(range_0, range); +} + +TEST(TestHttpRanges, GetLast) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + CHttpRange range; + EXPECT_TRUE(ranges.GetLast(range)); + EXPECT_EQ(range_2, range); +} + +TEST(TestHttpRanges, Size) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges_empty; + EXPECT_EQ(0U, ranges_empty.Size()); + + CHttpRanges ranges(ranges_raw); + EXPECT_EQ(ranges_raw.size(), ranges.Size()); +} + +TEST(TestHttpRanges, GetFirstPosition) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + uint64_t position; + EXPECT_TRUE(ranges.GetFirstPosition(position)); + EXPECT_EQ(range_0.GetFirstPosition(), position); +} + +TEST(TestHttpRanges, GetLastPosition) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + uint64_t position; + EXPECT_TRUE(ranges.GetLastPosition(position)); + EXPECT_EQ(range_2.GetLastPosition(), position); +} + +TEST(TestHttpRanges, GetLength) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + const uint64_t expectedLength = range_0.GetLength() + range_1.GetLength() + range_2.GetLength(); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + EXPECT_EQ(expectedLength, ranges.GetLength()); +} + +TEST(TestHttpRanges, GetTotalRange) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + CHttpRange range_total_expected(range_0.GetFirstPosition(), range_2.GetLastPosition()); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + CHttpRange range_total; + EXPECT_TRUE(ranges.GetTotalRange(range_total)); + EXPECT_EQ(range_total_expected, range_total); +} + +TEST(TestHttpRanges, Add) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + CHttpRanges ranges; + CHttpRange range; + + ranges.Add(range_0); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.GetFirst(range)); + EXPECT_EQ(range_0, range); + EXPECT_TRUE(ranges.GetLast(range)); + EXPECT_EQ(range_0, range); + + ranges.Add(range_1); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.GetFirst(range)); + EXPECT_EQ(range_0, range); + EXPECT_TRUE(ranges.GetLast(range)); + EXPECT_EQ(range_1, range); + + ranges.Add(range_2); + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.GetFirst(range)); + EXPECT_EQ(range_0, range); + EXPECT_TRUE(ranges.GetLast(range)); + EXPECT_EQ(range_2, range); +} + +TEST(TestHttpRanges, Remove) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + CHttpRange range; + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_1, range); + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range_2, range); + + // remove non-existing range + ranges.Remove(ranges.Size()); + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_1, range); + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range_2, range); + + // remove first range + ranges.Remove(0); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range_1, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_2, range); + + // remove last range + ranges.Remove(1); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range_1, range); + + // remove remaining range + ranges.Remove(0); + EXPECT_EQ(0U, ranges.Size()); +} + +TEST(TestHttpRanges, Clear) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + CHttpRange range; + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_1, range); + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range_2, range); + + ranges.Clear(); + EXPECT_EQ(0U, ranges.Size()); +} + +TEST(TestHttpRanges, ParseInvalid) +{ + CHttpRanges ranges; + + // combinations of invalid string and invalid total length + EXPECT_FALSE(ranges.Parse("")); + EXPECT_FALSE(ranges.Parse("", 0)); + EXPECT_FALSE(ranges.Parse("", 1)); + EXPECT_FALSE(ranges.Parse("test", 0)); + EXPECT_FALSE(ranges.Parse(RANGES_START, 0)); + + // empty range definition + EXPECT_FALSE(ranges.Parse(RANGES_START)); + EXPECT_FALSE(ranges.Parse(RANGES_START "-")); + + // bad characters in range definition + EXPECT_FALSE(ranges.Parse(RANGES_START "a")); + EXPECT_FALSE(ranges.Parse(RANGES_START "1a")); + EXPECT_FALSE(ranges.Parse(RANGES_START "1-a")); + EXPECT_FALSE(ranges.Parse(RANGES_START "a-a")); + EXPECT_FALSE(ranges.Parse(RANGES_START "a-1")); + EXPECT_FALSE(ranges.Parse(RANGES_START "--")); + EXPECT_FALSE(ranges.Parse(RANGES_START "1--")); + EXPECT_FALSE(ranges.Parse(RANGES_START "1--2")); + EXPECT_FALSE(ranges.Parse(RANGES_START "--2")); + + // combination of valid and empty range definitions + EXPECT_FALSE(ranges.Parse(RANGES_START "0-1,")); + EXPECT_FALSE(ranges.Parse(RANGES_START ",0-1")); + + // too big start position + EXPECT_FALSE(ranges.Parse(RANGES_START "10-11", 5)); + + // end position smaller than start position + EXPECT_FALSE(ranges.Parse(RANGES_START "1-0")); +} + +TEST(TestHttpRanges, ParseStartOnly) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_(0, totalLength - 1); + const CHttpRange range2_(2, totalLength - 1); + + CHttpRange range; + + CHttpRanges ranges_all; + EXPECT_TRUE(ranges_all.Parse(RANGES_START "0-", totalLength)); + EXPECT_EQ(1U, ranges_all.Size()); + EXPECT_TRUE(ranges_all.Get(0, range)); + EXPECT_EQ(range0_, range); + + CHttpRanges ranges_some; + EXPECT_TRUE(ranges_some.Parse(RANGES_START "2-", totalLength)); + EXPECT_EQ(1U, ranges_some.Size()); + EXPECT_TRUE(ranges_some.Get(0, range)); + EXPECT_EQ(range2_, range); +} + +TEST(TestHttpRanges, ParseFromEnd) +{ + const uint64_t totalLength = 5; + const CHttpRange range_1(totalLength - 1, totalLength - 1); + const CHttpRange range_3(totalLength - 3, totalLength - 1); + + CHttpRange range; + + CHttpRanges ranges_1; + EXPECT_TRUE(ranges_1.Parse(RANGES_START "-1", totalLength)); + EXPECT_EQ(1U, ranges_1.Size()); + EXPECT_TRUE(ranges_1.Get(0, range)); + EXPECT_EQ(range_1, range); + + CHttpRanges ranges_3; + EXPECT_TRUE(ranges_3.Parse(RANGES_START "-3", totalLength)); + EXPECT_EQ(1U, ranges_3.Size()); + EXPECT_TRUE(ranges_3.Get(0, range)); + EXPECT_EQ(range_3, range); +} + +TEST(TestHttpRanges, ParseSingle) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_0(0, 0); + const CHttpRange range0_1(0, 1); + const CHttpRange range0_5(0, totalLength - 1); + const CHttpRange range1_1(1, 1); + const CHttpRange range1_3(1, 3); + const CHttpRange range3_4(3, 4); + const CHttpRange range4_4(4, 4); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-1", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-5", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_5, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "1-1", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range1_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "1-3", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range1_3, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "3-4", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range3_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "4-4", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range4_4, range); +} + +TEST(TestHttpRanges, ParseMulti) +{ + const uint64_t totalLength = 6; + const CHttpRange range0_0(0, 0); + const CHttpRange range0_1(0, 1); + const CHttpRange range1_3(1, 3); + const CHttpRange range2_2(2, 2); + const CHttpRange range4_5(4, 5); + const CHttpRange range5_5(5, 5); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,2-2", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,2-2,4-5", totalLength)); + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_2, range); + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range4_5, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-1,5-5", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range5_5, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "1-3,5-5", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range1_3, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range5_5, range); +} + +TEST(TestHttpRanges, ParseOrderedNotOverlapping) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_0(0, 0); + const CHttpRange range0_1(0, 1); + const CHttpRange range2_2(2, 2); + const CHttpRange range2_(2, totalLength - 1); + const CHttpRange range_1(totalLength - 1, totalLength - 1); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,-1", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,2-2,-1", totalLength)); + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_2, range); + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,2-", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_, range); +} + +TEST(TestHttpRanges, ParseOrderedBackToBack) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_1(0, 1); + const CHttpRange range0_2(0, 2); + const CHttpRange range1_2(1, 2); + const CHttpRange range0_3(0, 3); + const CHttpRange range4_4(4, 4); + const CHttpRange range0_4(0, 4); + const CHttpRange range3_4(3, 4); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,1-1", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,1-1,2-2", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,1-1,2-2,3-3", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_3, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,1-1,2-2,3-3,4-4", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,1-1,3-3,4-4", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range3_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "1-1,2-2,4-4", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range1_2, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range4_4, range); +} + +TEST(TestHttpRanges, ParseOrderedOverlapping) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_0(0, 0); + const CHttpRange range0_1(0, 1); + const CHttpRange range0_2(0, 2); + const CHttpRange range0_3(0, 3); + const CHttpRange range0_4(0, 4); + const CHttpRange range2_4(2, 4); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,0-1", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,0-1,0-2", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,0-1,1-2", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,0-2,1-3", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_3, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-1,1-2,2-3,3-4", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,2-3,2-4,4-4", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_4, range); +} + +TEST(TestHttpRanges, ParseUnorderedNotOverlapping) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_0(0, 0); + const CHttpRange range0_1(0, 1); + const CHttpRange range2_2(2, 2); + const CHttpRange range2_(2, totalLength - 1); + const CHttpRange range_1(totalLength - 1, totalLength - 1); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "-1,0-0", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "2-2,-1,0-0", totalLength)); + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_2, range); + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "2-,0-0", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_, range); +} + +TEST(TestHttpRanges, ParseUnorderedBackToBack) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_0(0, 0); + const CHttpRange range1_1(1, 1); + const CHttpRange range0_1(0, 1); + const CHttpRange range2_2(2, 2); + const CHttpRange range0_2(0, 2); + const CHttpRange range1_2(1, 2); + const CHttpRange range3_3(3, 3); + const CHttpRange range0_3(0, 3); + const CHttpRange range4_4(4, 4); + const CHttpRange range0_4(0, 4); + const CHttpRange range3_4(3, 4); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "1-1,0-0", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "1-1,0-0,2-2", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "2-2,1-1,3-3,0-0", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_3, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "4-4,1-1,0-0,2-2,3-3", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "3-3,0-0,4-4,1-1", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range3_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "4-4,1-1,2-2", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range1_2, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range4_4, range); +} + +TEST(TestHttpRanges, ParseUnorderedOverlapping) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_0(0, 0); + const CHttpRange range0_1(0, 1); + const CHttpRange range0_2(0, 2); + const CHttpRange range0_3(0, 3); + const CHttpRange range0_4(0, 4); + const CHttpRange range2_4(2, 4); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "0-1,0-0", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-2,0-0,0-1", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-1,1-2,0-0", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-2,0-0,1-3", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_3, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "2-3,1-2,0-1,3-4", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "4-4,0-0,2-4,2-3", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_4, range); +} diff --git a/xbmc/utils/test/TestHttpResponse.cpp b/xbmc/utils/test/TestHttpResponse.cpp new file mode 100644 index 0000000..1f66285 --- /dev/null +++ b/xbmc/utils/test/TestHttpResponse.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/HttpResponse.h" + +#include + +TEST(TestHttpResponse, General) +{ + CHttpResponse a(HTTP::POST, HTTP::OK); + std::string response, content, refstr; + + a.AddHeader("date", "Sun, 01 Jul 2012 00:00:00 -0400"); + a.AddHeader("content-type", "text/html"); + content = "\r\n" + " \r\n" + "

XBMC TestHttpResponse Page

\r\n" + "

blah blah blah

\r\n" + " \r\n" + "\r\n"; + a.SetContent(content.c_str(), content.length()); + + response = a.Create();; + EXPECT_EQ((unsigned int)210, response.size()); + + refstr = "HTTP/1.1 200 OK\r\n" + "date: Sun, 01 Jul 2012 00:00:00 -0400\r\n" + "content-type: text/html\r\n" + "Content-Length: 106\r\n" + "\r\n" + "\r\n" + " \r\n" + "

XBMC TestHttpResponse Page

\r\n" + "

blah blah blah

\r\n" + " \r\n" + "\r\n"; + EXPECT_STREQ(refstr.c_str(), response.c_str()); +} diff --git a/xbmc/utils/test/TestJSONVariantParser.cpp b/xbmc/utils/test/TestJSONVariantParser.cpp new file mode 100644 index 0000000..b8556b0 --- /dev/null +++ b/xbmc/utils/test/TestJSONVariantParser.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/JSONVariantParser.h" +#include "utils/Variant.h" + +#include + +TEST(TestJSONVariantParser, CannotParseNullptr) +{ + CVariant variant; + ASSERT_FALSE(CJSONVariantParser::Parse(nullptr, variant)); +} + +TEST(TestJSONVariantParser, CannotParseEmptyString) +{ + CVariant variant; + ASSERT_FALSE(CJSONVariantParser::Parse("", variant)); + ASSERT_FALSE(CJSONVariantParser::Parse(std::string(), variant)); +} + +TEST(TestJSONVariantParser, CannotParseInvalidJson) +{ + CVariant variant; + ASSERT_FALSE(CJSONVariantParser::Parse("{", variant)); + ASSERT_FALSE(CJSONVariantParser::Parse("}", variant)); + ASSERT_FALSE(CJSONVariantParser::Parse("[", variant)); + ASSERT_FALSE(CJSONVariantParser::Parse("]", variant)); + ASSERT_FALSE(CJSONVariantParser::Parse("foo", variant)); +} + +TEST(TestJSONVariantParser, CanParseNull) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("null", variant)); + ASSERT_TRUE(variant.isNull()); +} + +TEST(TestJSONVariantParser, CanParseBoolean) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("true", variant)); + ASSERT_TRUE(variant.isBoolean()); + ASSERT_TRUE(variant.asBoolean()); + + ASSERT_TRUE(CJSONVariantParser::Parse("false", variant)); + ASSERT_TRUE(variant.isBoolean()); + ASSERT_FALSE(variant.asBoolean()); +} + +TEST(TestJSONVariantParser, CanParseSignedInteger) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("-1", variant)); + ASSERT_TRUE(variant.isInteger()); + ASSERT_EQ(-1, variant.asInteger()); +} + +TEST(TestJSONVariantParser, CanParseUnsignedInteger) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("0", variant)); + ASSERT_TRUE(variant.isUnsignedInteger()); + ASSERT_EQ(0U, variant.asUnsignedInteger()); + + ASSERT_TRUE(CJSONVariantParser::Parse("1", variant)); + ASSERT_TRUE(variant.isUnsignedInteger()); + ASSERT_EQ(1U, variant.asUnsignedInteger()); +} + +TEST(TestJSONVariantParser, CanParseSignedInteger64) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("-4294967296", variant)); + ASSERT_TRUE(variant.isInteger()); + ASSERT_EQ(-4294967296, variant.asInteger()); +} + +TEST(TestJSONVariantParser, CanParseUnsignedInteger64) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("4294967296", variant)); + ASSERT_TRUE(variant.isUnsignedInteger()); + ASSERT_EQ(4294967296U, variant.asUnsignedInteger()); +} + +TEST(TestJSONVariantParser, CanParseDouble) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("0.0", variant)); + ASSERT_TRUE(variant.isDouble()); + ASSERT_EQ(0.0, variant.asDouble()); + + ASSERT_TRUE(CJSONVariantParser::Parse("1.0", variant)); + ASSERT_TRUE(variant.isDouble()); + ASSERT_EQ(1.0, variant.asDouble()); + + ASSERT_TRUE(CJSONVariantParser::Parse("-1.0", variant)); + ASSERT_TRUE(variant.isDouble()); + ASSERT_EQ(-1.0, variant.asDouble()); +} + +TEST(TestJSONVariantParser, CanParseString) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("\"\"", variant)); + ASSERT_TRUE(variant.isString()); + ASSERT_TRUE(variant.empty()); + + ASSERT_TRUE(CJSONVariantParser::Parse("\"foo\"", variant)); + ASSERT_TRUE(variant.isString()); + ASSERT_STREQ("foo", variant.asString().c_str()); + + ASSERT_TRUE(CJSONVariantParser::Parse("\"foo bar\"", variant)); + ASSERT_TRUE(variant.isString()); + ASSERT_STREQ("foo bar", variant.asString().c_str()); +} + +TEST(TestJSONVariantParser, CanParseObject) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("{}", variant)); + ASSERT_TRUE(variant.isObject()); + ASSERT_TRUE(variant.empty()); + + variant.clear(); + ASSERT_TRUE(CJSONVariantParser::Parse("{ \"foo\": \"bar\" }", variant)); + ASSERT_TRUE(variant.isObject()); + ASSERT_TRUE(variant.isMember("foo")); + ASSERT_TRUE(variant["foo"].isString()); + ASSERT_STREQ("bar", variant["foo"].asString().c_str()); + + variant.clear(); + ASSERT_TRUE(CJSONVariantParser::Parse("{ \"foo\": \"bar\", \"bar\": true }", variant)); + ASSERT_TRUE(variant.isObject()); + ASSERT_TRUE(variant.isMember("foo")); + ASSERT_TRUE(variant["foo"].isString()); + ASSERT_STREQ("bar", variant["foo"].asString().c_str()); + ASSERT_TRUE(variant.isMember("bar")); + ASSERT_TRUE(variant["bar"].isBoolean()); + ASSERT_TRUE(variant["bar"].asBoolean()); + + variant.clear(); + ASSERT_TRUE(CJSONVariantParser::Parse("{ \"foo\": { \"sub-foo\": \"bar\" } }", variant)); + ASSERT_TRUE(variant.isObject()); + ASSERT_TRUE(variant.isMember("foo")); + ASSERT_TRUE(variant["foo"].isObject()); + ASSERT_TRUE(variant["foo"].isMember("sub-foo")); + ASSERT_TRUE(variant["foo"]["sub-foo"].isString()); + ASSERT_STREQ("bar", variant["foo"]["sub-foo"].asString().c_str()); +} + +TEST(TestJSONVariantParser, CanParseArray) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("[]", variant)); + ASSERT_TRUE(variant.isArray()); + ASSERT_TRUE(variant.empty()); + + variant.clear(); + ASSERT_TRUE(CJSONVariantParser::Parse("[ true ]", variant)); + ASSERT_TRUE(variant.isArray()); + ASSERT_EQ(1U, variant.size()); + ASSERT_TRUE(variant[0].isBoolean()); + ASSERT_TRUE(variant[0].asBoolean()); + + variant.clear(); + ASSERT_TRUE(CJSONVariantParser::Parse("[ true, \"foo\" ]", variant)); + ASSERT_TRUE(variant.isArray()); + ASSERT_EQ(2U, variant.size()); + ASSERT_TRUE(variant[0].isBoolean()); + ASSERT_TRUE(variant[0].asBoolean()); + ASSERT_TRUE(variant[1].isString()); + ASSERT_STREQ("foo", variant[1].asString().c_str()); + + variant.clear(); + ASSERT_TRUE(CJSONVariantParser::Parse("[ { \"foo\": \"bar\" } ]", variant)); + ASSERT_TRUE(variant.isArray()); + ASSERT_EQ(1U, variant.size()); + ASSERT_TRUE(variant[0].isObject()); + ASSERT_TRUE(variant[0].isMember("foo")); + ASSERT_TRUE(variant[0]["foo"].isString()); + ASSERT_STREQ("bar", variant[0]["foo"].asString().c_str()); +} diff --git a/xbmc/utils/test/TestJSONVariantWriter.cpp b/xbmc/utils/test/TestJSONVariantWriter.cpp new file mode 100644 index 0000000..0772a4d --- /dev/null +++ b/xbmc/utils/test/TestJSONVariantWriter.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/JSONVariantWriter.h" +#include "utils/Variant.h" + +#include + +TEST(TestJSONVariantWriter, CanWriteNull) +{ + CVariant variant; + std::string str; + + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("null", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteBoolean) +{ + CVariant variant(true); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("true", str.c_str()); + + variant = false; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("false", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteSignedInteger) +{ + CVariant variant(-1); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("-1", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteUnsignedInteger) +{ + CVariant variant(0); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("0", str.c_str()); + + variant = 1; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("1", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteSignedInteger64) +{ + CVariant variant(static_cast(-4294967296LL)); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("-4294967296", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteUnsignedInteger64) +{ + CVariant variant(static_cast(4294967296LL)); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("4294967296", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteDouble) +{ + CVariant variant(0.0); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("0.0", str.c_str()); + + variant = 1.0; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("1.0", str.c_str()); + + variant = -1.0; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("-1.0", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteString) +{ + CVariant variant(""); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("\"\"", str.c_str()); + + variant = "foo"; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("\"foo\"", str.c_str()); + + variant = "foo bar"; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("\"foo bar\"", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteObject) +{ + CVariant variant(CVariant::VariantTypeObject); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("{}", str.c_str()); + + variant.clear(); + variant["foo"] = "bar"; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("{\n\t\"foo\": \"bar\"\n}", str.c_str()); + + variant.clear(); + variant["foo"] = "bar"; + variant["bar"] = true; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("{\n\t\"bar\": true,\n\t\"foo\": \"bar\"\n}", str.c_str()); + + variant.clear(); + variant["foo"]["sub-foo"] = "bar"; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("{\n\t\"foo\": {\n\t\t\"sub-foo\": \"bar\"\n\t}\n}", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteArray) +{ + CVariant variant(CVariant::VariantTypeArray); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("[]", str.c_str()); + + variant.clear(); + variant.push_back(true); + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("[\n\ttrue\n]", str.c_str()); + + variant.clear(); + variant.push_back(true); + variant.push_back("foo"); + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("[\n\ttrue,\n\t\"foo\"\n]", str.c_str()); + + variant.clear(); + CVariant obj(CVariant::VariantTypeObject); + obj["foo"] = "bar"; + variant.push_back(obj); + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("[\n\t{\n\t\t\"foo\": \"bar\"\n\t}\n]", str.c_str()); +} diff --git a/xbmc/utils/test/TestJobManager.cpp b/xbmc/utils/test/TestJobManager.cpp new file mode 100644 index 0000000..40165e9 --- /dev/null +++ b/xbmc/utils/test/TestJobManager.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "test/MtTestUtils.h" +#include "utils/Job.h" +#include "utils/JobManager.h" +#include "utils/XTimeUtils.h" + +#include + +#include + +using namespace ConditionPoll; + +struct Flags +{ + std::atomic lingerAtWork{true}; + std::atomic started{false}; + std::atomic finished{false}; + std::atomic wasCanceled{false}; +}; + +class DummyJob : public CJob +{ + Flags* m_flags; +public: + inline DummyJob(Flags* flags) : m_flags(flags) + { + } + + bool DoWork() override + { + m_flags->started = true; + while (m_flags->lingerAtWork) + std::this_thread::yield(); + + if (ShouldCancel(0,0)) + m_flags->wasCanceled = true; + + m_flags->finished = true; + return true; + } +}; + +class ReallyDumbJob : public CJob +{ + Flags* m_flags; +public: + inline ReallyDumbJob(Flags* flags) : m_flags(flags) {} + + bool DoWork() override + { + m_flags->finished = true; + return true; + } +}; + +class TestJobManager : public testing::Test +{ +protected: + TestJobManager() = default; + + ~TestJobManager() override + { + /* Always cancel jobs test completion */ + CJobManager::GetInstance().CancelJobs(); + CJobManager::GetInstance().Restart(); + } +}; + +TEST_F(TestJobManager, AddJob) +{ + Flags* flags = new Flags(); + ReallyDumbJob* job = new ReallyDumbJob(flags); + CJobManager::GetInstance().AddJob(job, NULL); + ASSERT_TRUE(poll([flags]() -> bool { return flags->finished; })); + delete flags; +} + +TEST_F(TestJobManager, CancelJob) +{ + unsigned int id; + Flags* flags = new Flags(); + DummyJob* job = new DummyJob(flags); + id = CJobManager::GetInstance().AddJob(job, NULL); + + // wait for the worker thread to be entered + ASSERT_TRUE(poll([flags]() -> bool { return flags->started; })); + + // cancel the job + CJobManager::GetInstance().CancelJob(id); + + // let the worker thread continue + flags->lingerAtWork = false; + + // make sure the job finished. + ASSERT_TRUE(poll([flags]() -> bool { return flags->finished; })); + + // ... and that it was canceled. + EXPECT_TRUE(flags->wasCanceled); + delete flags; +} + +namespace +{ +struct JobControlPackage +{ + JobControlPackage() + { + // We're not ready to wait yet + jobCreatedMutex.lock(); + } + + ~JobControlPackage() + { + jobCreatedMutex.unlock(); + } + + bool ready = false; + XbmcThreads::ConditionVariable jobCreatedCond; + CCriticalSection jobCreatedMutex; +}; + +class BroadcastingJob : + public CJob +{ +public: + + BroadcastingJob(JobControlPackage &package) : + m_package(package), + m_finish(false) + { + } + + void FinishAndStopBlocking() + { + CSingleLock lock(m_blockMutex); + + m_finish = true; + m_block.notifyAll(); + } + + const char * GetType() const override + { + return "BroadcastingJob"; + } + + bool DoWork() override + { + { + CSingleLock lock(m_package.jobCreatedMutex); + + m_package.ready = true; + m_package.jobCreatedCond.notifyAll(); + } + + CSingleLock blockLock(m_blockMutex); + + // Block until we're told to go away + while (!m_finish) + m_block.wait(m_blockMutex); + return true; + } + +private: + + JobControlPackage &m_package; + + XbmcThreads::ConditionVariable m_block; + CCriticalSection m_blockMutex; + bool m_finish; +}; + +BroadcastingJob * +WaitForJobToStartProcessing(CJob::PRIORITY priority, JobControlPackage &package) +{ + BroadcastingJob* job = new BroadcastingJob(package); + CJobManager::GetInstance().AddJob(job, NULL, priority); + + // We're now ready to wait, wait and then unblock once ready + while (!package.ready) + package.jobCreatedCond.wait(package.jobCreatedMutex); + + return job; +} +} + +TEST_F(TestJobManager, PauseLowPriorityJob) +{ + JobControlPackage package; + BroadcastingJob *job (WaitForJobToStartProcessing(CJob::PRIORITY_LOW_PAUSABLE, package)); + + EXPECT_TRUE(CJobManager::GetInstance().IsProcessing(CJob::PRIORITY_LOW_PAUSABLE)); + CJobManager::GetInstance().PauseJobs(); + EXPECT_FALSE(CJobManager::GetInstance().IsProcessing(CJob::PRIORITY_LOW_PAUSABLE)); + CJobManager::GetInstance().UnPauseJobs(); + EXPECT_TRUE(CJobManager::GetInstance().IsProcessing(CJob::PRIORITY_LOW_PAUSABLE)); + + job->FinishAndStopBlocking(); +} + +TEST_F(TestJobManager, IsProcessing) +{ + JobControlPackage package; + BroadcastingJob *job (WaitForJobToStartProcessing(CJob::PRIORITY_LOW_PAUSABLE, package)); + + EXPECT_EQ(0, CJobManager::GetInstance().IsProcessing("")); + + job->FinishAndStopBlocking(); +} diff --git a/xbmc/utils/test/TestLabelFormatter.cpp b/xbmc/utils/test/TestLabelFormatter.cpp new file mode 100644 index 0000000..0989fec --- /dev/null +++ b/xbmc/utils/test/TestLabelFormatter.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "filesystem/File.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "test/TestUtils.h" +#include "utils/LabelFormatter.h" + +#include + +/* Set default settings used by CLabelFormatter. */ +class TestLabelFormatter : public testing::Test +{ +protected: + TestLabelFormatter() = default; + + ~TestLabelFormatter() override + { + CServiceBroker::GetSettingsComponent()->GetSettings()->Unload(); + } +}; + +TEST_F(TestLabelFormatter, FormatLabel) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destpath; + LABEL_MASKS labelMasks; + CLabelFormatter formatter("", labelMasks.m_strLabel2File); + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + + formatter.FormatLabel(item.get()); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); +} + +TEST_F(TestLabelFormatter, FormatLabel2) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destpath; + LABEL_MASKS labelMasks; + CLabelFormatter formatter("", labelMasks.m_strLabel2File); + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + + formatter.FormatLabel2(item.get()); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); +} diff --git a/xbmc/utils/test/TestLangCodeExpander.cpp b/xbmc/utils/test/TestLangCodeExpander.cpp new file mode 100644 index 0000000..7a6dde1 --- /dev/null +++ b/xbmc/utils/test/TestLangCodeExpander.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/LangCodeExpander.h" + +#include + +TEST(TestLangCodeExpander, ConvertISO6391ToISO6392B) +{ + std::string refstr, varstr; + + refstr = "eng"; + g_LangCodeExpander.ConvertISO6391ToISO6392B("en", varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestLangCodeExpander, ConvertToISO6392B) +{ + std::string refstr, varstr; + + refstr = "eng"; + g_LangCodeExpander.ConvertToISO6392B("en", varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} diff --git a/xbmc/utils/test/TestLocale.cpp b/xbmc/utils/test/TestLocale.cpp new file mode 100644 index 0000000..f5193ed --- /dev/null +++ b/xbmc/utils/test/TestLocale.cpp @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/Locale.h" +#include "utils/StringUtils.h" + +#include + +static const std::string TerritorySeparator = "_"; +static const std::string CodesetSeparator = "."; +static const std::string ModifierSeparator = "@"; + +static const std::string LanguageCodeEnglish = "en"; +static const std::string TerritoryCodeBritain = "GB"; +static const std::string CodesetUtf8 = "UTF-8"; +static const std::string ModifierLatin = "latin"; + +TEST(TestLocale, DefaultLocale) +{ + CLocale locale; + ASSERT_FALSE(locale.IsValid()); + ASSERT_STREQ("", locale.GetLanguageCode().c_str()); + ASSERT_STREQ("", locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ("", locale.ToString().c_str()); +} + +TEST(TestLocale, LanguageLocale) +{ + CLocale locale(LanguageCodeEnglish); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ("", locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageTerritoryLocale) +{ + const std::string strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, TerritoryCodeBritain); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageCodesetLocale) +{ + const std::string strLocale = LanguageCodeEnglish + CodesetSeparator + CodesetUtf8; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, "", CodesetUtf8); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ("", locale.GetTerritoryCode().c_str()); + ASSERT_STREQ(CodesetUtf8.c_str(), locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageModifierLocale) +{ + const std::string strLocale = LanguageCodeEnglish + ModifierSeparator + ModifierLatin; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, "", "", ModifierLatin); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ("", locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ(ModifierLatin.c_str(), locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageTerritoryCodesetLocale) +{ + const std::string strLocaleShort = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleShortLC = strLocaleShort; + StringUtils::ToLower(strLocaleShortLC); + const std::string strLocale = strLocaleShort + CodesetSeparator + CodesetUtf8; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, TerritoryCodeBritain, CodesetUtf8); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ(CodesetUtf8.c_str(), locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocaleShort.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleShortLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageTerritoryModifierLocale) +{ + const std::string strLocaleShort = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleShortLC = strLocaleShort; + StringUtils::ToLower(strLocaleShortLC); + const std::string strLocale = strLocaleShort + ModifierSeparator + ModifierLatin; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, TerritoryCodeBritain, "", ModifierLatin); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ(ModifierLatin.c_str(), locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocaleShort.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleShortLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageTerritoryCodesetModifierLocale) +{ + const std::string strLocaleShort = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleShortLC = strLocaleShort; + StringUtils::ToLower(strLocaleShortLC); + const std::string strLocale = strLocaleShort + CodesetSeparator + CodesetUtf8 + ModifierSeparator + ModifierLatin; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, TerritoryCodeBritain, CodesetUtf8, ModifierLatin); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ(CodesetUtf8.c_str(), locale.GetCodeset().c_str()); + ASSERT_STREQ(ModifierLatin.c_str(), locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocaleShort.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleShortLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, FullStringLocale) +{ + const std::string strLocaleShort = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleShortLC = strLocaleShort; + StringUtils::ToLower(strLocaleShortLC); + const std::string strLocale = strLocaleShort + CodesetSeparator + CodesetUtf8 + ModifierSeparator + ModifierLatin; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ(CodesetUtf8.c_str(), locale.GetCodeset().c_str()); + ASSERT_STREQ(ModifierLatin.c_str(), locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocaleShort.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleShortLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, FromString) +{ + std::string strLocale = ""; + CLocale locale = CLocale::FromString(strLocale); + ASSERT_FALSE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + CodesetSeparator + CodesetUtf8; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + ModifierSeparator + ModifierLatin; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + CodesetSeparator + CodesetUtf8; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + ModifierSeparator + ModifierLatin; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + CodesetSeparator + CodesetUtf8 + ModifierSeparator + ModifierLatin; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); +} + +TEST(TestLocale, EmptyLocale) +{ + ASSERT_FALSE(CLocale::Empty.IsValid()); + ASSERT_STREQ("", CLocale::Empty.GetLanguageCode().c_str()); + ASSERT_STREQ("", CLocale::Empty.GetTerritoryCode().c_str()); + ASSERT_STREQ("", CLocale::Empty.GetCodeset().c_str()); + ASSERT_STREQ("", CLocale::Empty.GetModifier().c_str()); + ASSERT_STREQ("", CLocale::Empty.ToString().c_str()); +} + +TEST(TestLocale, Equals) +{ + std::string strLocale = ""; + CLocale locale; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish); + strLocale = LanguageCodeEnglish; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, TerritoryCodeBritain); + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, "", CodesetUtf8); + strLocale = LanguageCodeEnglish + CodesetSeparator + CodesetUtf8; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, "", "", ModifierLatin); + strLocale = LanguageCodeEnglish + ModifierSeparator + ModifierLatin; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, TerritoryCodeBritain, CodesetUtf8); + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + CodesetSeparator + CodesetUtf8; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, TerritoryCodeBritain, "", ModifierLatin); + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + ModifierSeparator + ModifierLatin; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, TerritoryCodeBritain, CodesetUtf8, ModifierLatin); + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + CodesetSeparator + CodesetUtf8 + ModifierSeparator + ModifierLatin; + ASSERT_TRUE(locale.Equals(strLocale)); +} diff --git a/xbmc/utils/test/TestMathUtils.cpp b/xbmc/utils/test/TestMathUtils.cpp new file mode 100644 index 0000000..d60cc3f --- /dev/null +++ b/xbmc/utils/test/TestMathUtils.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/MathUtils.h" + +#include + +TEST(TestMathUtils, round_int) +{ + int refval, varval, i; + + for (i = -8; i < 8; ++i) + { + double d = 0.25*i; + refval = (i < 0) ? (i - 1) / 4 : (i + 2) / 4; + varval = MathUtils::round_int(d); + EXPECT_EQ(refval, varval); + } +} + +TEST(TestMathUtils, truncate_int) +{ + int refval, varval, i; + + for (i = -8; i < 8; ++i) + { + double d = 0.25*i; + refval = i / 4; + varval = MathUtils::truncate_int(d); + EXPECT_EQ(refval, varval); + } +} + +TEST(TestMathUtils, abs) +{ + int64_t refval, varval; + + refval = 5; + varval = MathUtils::abs(-5); + EXPECT_EQ(refval, varval); +} + +TEST(TestMathUtils, bitcount) +{ + unsigned refval, varval; + + refval = 10; + varval = MathUtils::bitcount(0x03FF); + EXPECT_EQ(refval, varval); + + refval = 8; + varval = MathUtils::bitcount(0x2AD5); + EXPECT_EQ(refval, varval); +} diff --git a/xbmc/utils/test/TestMime.cpp b/xbmc/utils/test/TestMime.cpp new file mode 100644 index 0000000..7ef82c3 --- /dev/null +++ b/xbmc/utils/test/TestMime.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "FileItem.h" +#include "utils/Mime.h" + +#include + +TEST(TestMime, GetMimeType_string) +{ + EXPECT_STREQ("video/avi", CMime::GetMimeType("avi").c_str()); + EXPECT_STRNE("video/x-msvideo", CMime::GetMimeType("avi").c_str()); + EXPECT_STRNE("video/avi", CMime::GetMimeType("xvid").c_str()); +} + +TEST(TestMime, GetMimeType_CFileItem) +{ + std::string refstr, varstr; + CFileItem item("testfile.mp4", false); + + refstr = "video/mp4"; + varstr = CMime::GetMimeType(item); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} diff --git a/xbmc/utils/test/TestPOUtils.cpp b/xbmc/utils/test/TestPOUtils.cpp new file mode 100644 index 0000000..5808c31 --- /dev/null +++ b/xbmc/utils/test/TestPOUtils.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "test/TestUtils.h" +#include "utils/POUtils.h" + +#include + + +TEST(TestPOUtils, General) +{ + CPODocument a; + + EXPECT_TRUE(a.LoadFile(XBMC_REF_FILE_PATH("xbmc/utils/test/data/language/Spanish/strings.po"))); + + EXPECT_TRUE(a.GetNextEntry()); + EXPECT_EQ(ID_FOUND, a.GetEntryType()); + EXPECT_EQ((uint32_t)0, a.GetEntryID()); + a.ParseEntry(false); + EXPECT_STREQ("", a.GetMsgctxt().c_str()); + EXPECT_STREQ("Programs", a.GetMsgid().c_str()); + EXPECT_STREQ("Programas", a.GetMsgstr().c_str()); + EXPECT_STREQ("", a.GetPlurMsgstr(0).c_str()); + + EXPECT_TRUE(a.GetNextEntry()); + EXPECT_EQ(ID_FOUND, a.GetEntryType()); + EXPECT_EQ((uint32_t)1, a.GetEntryID()); + a.ParseEntry(false); + EXPECT_STREQ("", a.GetMsgctxt().c_str()); + EXPECT_STREQ("Pictures", a.GetMsgid().c_str()); + EXPECT_STREQ("Imágenes", a.GetMsgstr().c_str()); + EXPECT_STREQ("", a.GetPlurMsgstr(0).c_str()); + + EXPECT_TRUE(a.GetNextEntry()); + EXPECT_EQ(ID_FOUND, a.GetEntryType()); + EXPECT_EQ((uint32_t)2, a.GetEntryID()); + a.ParseEntry(false); + EXPECT_STREQ("", a.GetMsgctxt().c_str()); + EXPECT_STREQ("Music", a.GetMsgid().c_str()); + EXPECT_STREQ("Música", a.GetMsgstr().c_str()); + EXPECT_STREQ("", a.GetPlurMsgstr(0).c_str()); +} diff --git a/xbmc/utils/test/TestRegExp.cpp b/xbmc/utils/test/TestRegExp.cpp new file mode 100644 index 0000000..3a3df8f --- /dev/null +++ b/xbmc/utils/test/TestRegExp.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +/** @todo gtest/gtest.h needs to come in before utils/RegExp.h. + * Investigate why. + */ +#include "CompileInfo.h" +#include "ServiceBroker.h" +#include "filesystem/File.h" +#include "filesystem/SpecialProtocol.h" +#include "utils/RegExp.h" +#include "utils/StringUtils.h" +#include "utils/log.h" + +#include + +TEST(TestRegExp, RegFind) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^Test.*")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + + EXPECT_TRUE(regex.RegComp("^string.*")); + EXPECT_EQ(-1, regex.RegFind("Test string.")); +} + +TEST(TestRegExp, GetReplaceString) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_STREQ("string", regex.GetReplaceString("\\2").c_str()); +} + +TEST(TestRegExp, GetFindLen) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_EQ(12, regex.GetFindLen()); +} + +TEST(TestRegExp, GetSubCount) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_EQ(2, regex.GetSubCount()); +} + +TEST(TestRegExp, GetSubStart) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_EQ(0, regex.GetSubStart(0)); + EXPECT_EQ(0, regex.GetSubStart(1)); + EXPECT_EQ(5, regex.GetSubStart(2)); +} + +TEST(TestRegExp, GetCaptureTotal) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_EQ(2, regex.GetCaptureTotal()); +} + +TEST(TestRegExp, GetMatch) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_STREQ("Test string.", regex.GetMatch(0).c_str()); + EXPECT_STREQ("Test", regex.GetMatch(1).c_str()); + EXPECT_STREQ("string", regex.GetMatch(2).c_str()); +} + +TEST(TestRegExp, GetPattern) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_STREQ("^(Test)\\s*(.*)\\.", regex.GetPattern().c_str()); +} + +TEST(TestRegExp, GetNamedSubPattern) +{ + CRegExp regex; + std::string match; + + EXPECT_TRUE(regex.RegComp("^(?Test)\\s*(?.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_TRUE(regex.GetNamedSubPattern("first", match)); + EXPECT_STREQ("Test", match.c_str()); + EXPECT_TRUE(regex.GetNamedSubPattern("second", match)); + EXPECT_STREQ("string", match.c_str()); +} + +TEST(TestRegExp, operatorEqual) +{ + CRegExp regex, regexcopy; + std::string match; + + EXPECT_TRUE(regex.RegComp("^(?Test)\\s*(?.*)\\.")); + regexcopy = regex; + EXPECT_EQ(0, regexcopy.RegFind("Test string.")); + EXPECT_TRUE(regexcopy.GetNamedSubPattern("first", match)); + EXPECT_STREQ("Test", match.c_str()); + EXPECT_TRUE(regexcopy.GetNamedSubPattern("second", match)); + EXPECT_STREQ("string", match.c_str()); +} + +class TestRegExpLog : public testing::Test +{ +protected: + TestRegExpLog() = default; + ~TestRegExpLog() override { CServiceBroker::GetLogging().Uninitialize(); } +}; + +TEST_F(TestRegExpLog, DumpOvector) +{ + CRegExp regex; + std::string logfile, logstring; + char buf[100]; + ssize_t bytesread; + XFILE::CFile file; + + std::string appName = CCompileInfo::GetAppName(); + StringUtils::ToLower(appName); + logfile = CSpecialProtocol::TranslatePath("special://temp/") + appName + ".log"; + CServiceBroker::GetLogging().Initialize( + CSpecialProtocol::TranslatePath("special://temp/").c_str()); + EXPECT_TRUE(XFILE::CFile::Exists(logfile)); + + EXPECT_TRUE(regex.RegComp("^(?Test)\\s*(?.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + regex.DumpOvector(LOGDEBUG); + CServiceBroker::GetLogging().Uninitialize(); + + EXPECT_TRUE(file.Open(logfile)); + while ((bytesread = file.Read(buf, sizeof(buf) - 1)) > 0) + { + buf[bytesread] = '\0'; + logstring.append(buf); + } + file.Close(); + EXPECT_FALSE(logstring.empty()); + + EXPECT_STREQ("\xEF\xBB\xBF", logstring.substr(0, 3).c_str()); + + EXPECT_TRUE(regex.RegComp(".*DEBUG : regexp ovector=\\{\\[0,12\\],\\[0,4\\]," + "\\[5,11\\]\\}.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + + EXPECT_TRUE(XFILE::CFile::Delete(logfile)); +} diff --git a/xbmc/utils/test/TestRingBuffer.cpp b/xbmc/utils/test/TestRingBuffer.cpp new file mode 100644 index 0000000..e2fd2d5 --- /dev/null +++ b/xbmc/utils/test/TestRingBuffer.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/RingBuffer.h" + +#include + +TEST(TestRingBuffer, General) +{ + CRingBuffer a; + char data[20]; + unsigned int i; + + EXPECT_TRUE(a.Create(20)); + EXPECT_EQ((unsigned int)20, a.getSize()); + memset(data, 0, sizeof(data)); + for (i = 0; i < a.getSize(); i++) + EXPECT_TRUE(a.WriteData(data, 1)); + a.Clear(); + + memcpy(data, "0123456789", sizeof("0123456789")); + EXPECT_TRUE(a.WriteData(data, sizeof("0123456789"))); + EXPECT_STREQ("0123456789", a.getBuffer()); + + memset(data, 0, sizeof(data)); + EXPECT_TRUE(a.ReadData(data, 5)); + EXPECT_STREQ("01234", data); +} diff --git a/xbmc/utils/test/TestScraperParser.cpp b/xbmc/utils/test/TestScraperParser.cpp new file mode 100644 index 0000000..50744b4 --- /dev/null +++ b/xbmc/utils/test/TestScraperParser.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "test/TestUtils.h" +#include "utils/ScraperParser.h" + +#include + +TEST(TestScraperParser, General) +{ + CScraperParser a; + + a.Clear(); + EXPECT_TRUE( + a.Load(XBMC_REF_FILE_PATH("/addons/metadata.themoviedb.org/tmdb.xml"))); + + EXPECT_STREQ( + XBMC_REF_FILE_PATH("/addons/metadata.themoviedb.org/tmdb.xml").c_str(), + a.GetFilename().c_str()); + EXPECT_STREQ("UTF-8", a.GetSearchStringEncoding().c_str()); +} diff --git a/xbmc/utils/test/TestScraperUrl.cpp b/xbmc/utils/test/TestScraperUrl.cpp new file mode 100644 index 0000000..1feb181 --- /dev/null +++ b/xbmc/utils/test/TestScraperUrl.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/ScraperUrl.h" + +#include + +TEST(TestScraperUrl, General) +{ + CScraperUrl a; + std::string xmlstring; + + xmlstring = "\n" + " \n" + " \n" + " \n" + " \n" + "\n"; + EXPECT_TRUE(a.ParseFromData(xmlstring)); + + const auto url = a.GetFirstUrlByType(); + EXPECT_STREQ("blah", url.m_spoof.c_str()); + EXPECT_STREQ("someurl", url.m_url.c_str()); + EXPECT_STREQ("", url.m_cache.c_str()); + EXPECT_EQ(CScraperUrl::UrlType::General, url.m_type); + EXPECT_FALSE(url.m_post); + EXPECT_TRUE(url.m_isgz); + EXPECT_EQ(-1, url.m_season); +} diff --git a/xbmc/utils/test/TestSortUtils.cpp b/xbmc/utils/test/TestSortUtils.cpp new file mode 100644 index 0000000..dac3c62 --- /dev/null +++ b/xbmc/utils/test/TestSortUtils.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/SortUtils.h" +#include "utils/Variant.h" + +#include + +TEST(TestSortUtils, Sort_SortBy) +{ + SortItems items; + + CVariant variant1("M Artist"); + SortItemPtr item1(new SortItem()); + (*item1)[FieldArtist] = variant1; + CVariant variant2("B Artist"); + SortItemPtr item2(new SortItem()); + (*item2)[FieldArtist] = variant2; + CVariant variant3("R Artist"); + SortItemPtr item3(new SortItem()); + (*item3)[FieldArtist] = variant3; + CVariant variant4("R Artist"); + SortItemPtr item4(new SortItem()); + (*item4)[FieldArtist] = variant4; + CVariant variant5("I Artist"); + SortItemPtr item5(new SortItem()); + (*item5)[FieldArtist] = variant5; + CVariant variant6("A Artist"); + SortItemPtr item6(new SortItem()); + (*item6)[FieldArtist] = variant6; + CVariant variant7("G Artist"); + SortItemPtr item7(new SortItem()); + (*item7)[FieldArtist] = variant7; + + items.push_back(item1); + items.push_back(item2); + items.push_back(item3); + items.push_back(item4); + items.push_back(item5); + items.push_back(item6); + items.push_back(item7); + + SortUtils::Sort(SortByArtist, SortOrderAscending, SortAttributeNone, items); + + EXPECT_STREQ("A Artist", (*items.at(0))[FieldArtist].asString().c_str()); + EXPECT_STREQ("B Artist", (*items.at(1))[FieldArtist].asString().c_str()); + EXPECT_STREQ("G Artist", (*items.at(2))[FieldArtist].asString().c_str()); + EXPECT_STREQ("I Artist", (*items.at(3))[FieldArtist].asString().c_str()); + EXPECT_STREQ("M Artist", (*items.at(4))[FieldArtist].asString().c_str()); + EXPECT_STREQ("R Artist", (*items.at(5))[FieldArtist].asString().c_str()); + EXPECT_STREQ("R Artist", (*items.at(6))[FieldArtist].asString().c_str()); +} + +TEST(TestSortUtils, Sort_SortDescription) +{ + SortItems items; + + CVariant variant1("M Artist"); + SortItemPtr item1(new SortItem()); + (*item1)[FieldArtist] = variant1; + CVariant variant2("B Artist"); + SortItemPtr item2(new SortItem()); + (*item2)[FieldArtist] = variant2; + CVariant variant3("R Artist"); + SortItemPtr item3(new SortItem()); + (*item3)[FieldArtist] = variant3; + CVariant variant4("R Artist"); + SortItemPtr item4(new SortItem()); + (*item4)[FieldArtist] = variant4; + CVariant variant5("I Artist"); + SortItemPtr item5(new SortItem()); + (*item5)[FieldArtist] = variant5; + CVariant variant6("A Artist"); + SortItemPtr item6(new SortItem()); + (*item6)[FieldArtist] = variant6; + CVariant variant7("G Artist"); + SortItemPtr item7(new SortItem()); + (*item7)[FieldArtist] = variant7; + + items.push_back(item1); + items.push_back(item2); + items.push_back(item3); + items.push_back(item4); + items.push_back(item5); + items.push_back(item6); + items.push_back(item7); + + SortDescription desc; + desc.sortBy = SortByArtist; + SortUtils::Sort(desc, items); + + EXPECT_STREQ("A Artist", (*items.at(0))[FieldArtist].asString().c_str()); + EXPECT_STREQ("B Artist", (*items.at(1))[FieldArtist].asString().c_str()); + EXPECT_STREQ("G Artist", (*items.at(2))[FieldArtist].asString().c_str()); + EXPECT_STREQ("I Artist", (*items.at(3))[FieldArtist].asString().c_str()); + EXPECT_STREQ("M Artist", (*items.at(4))[FieldArtist].asString().c_str()); + EXPECT_STREQ("R Artist", (*items.at(5))[FieldArtist].asString().c_str()); + EXPECT_STREQ("R Artist", (*items.at(6))[FieldArtist].asString().c_str()); +} + +TEST(TestSortUtils, GetFieldsForSorting) +{ + Fields fields; + + fields = SortUtils::GetFieldsForSorting(SortByArtist); + Fields::iterator it; + it = fields.find(FieldAlbum); + EXPECT_EQ(FieldAlbum, *it); + it = fields.find(FieldArtist); + EXPECT_EQ(FieldArtist, *it); + it = fields.find(FieldArtistSort); + EXPECT_EQ(FieldArtistSort, *it); + it = fields.find(FieldYear); + EXPECT_EQ(FieldYear, *it); + it = fields.find(FieldTrackNumber); + EXPECT_EQ(FieldTrackNumber, *it); + EXPECT_EQ((unsigned int)5, fields.size()); +} diff --git a/xbmc/utils/test/TestStopwatch.cpp b/xbmc/utils/test/TestStopwatch.cpp new file mode 100644 index 0000000..966afc5 --- /dev/null +++ b/xbmc/utils/test/TestStopwatch.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "threads/Thread.h" +#include "utils/Stopwatch.h" + +#include + +class CTestStopWatchThread : public CThread +{ +public: + CTestStopWatchThread() : + CThread("TestStopWatch"){} +}; + +TEST(TestStopWatch, Initialization) +{ + CStopWatch a; + EXPECT_FALSE(a.IsRunning()); + EXPECT_EQ(0.0f, a.GetElapsedSeconds()); + EXPECT_EQ(0.0f, a.GetElapsedMilliseconds()); +} + +TEST(TestStopWatch, Start) +{ + CStopWatch a; + a.Start(); + EXPECT_TRUE(a.IsRunning()); +} + +TEST(TestStopWatch, Stop) +{ + CStopWatch a; + a.Start(); + a.Stop(); + EXPECT_FALSE(a.IsRunning()); +} + +TEST(TestStopWatch, ElapsedTime) +{ + CStopWatch a; + CTestStopWatchThread thread; + a.Start(); + thread.Sleep(1); + EXPECT_GT(a.GetElapsedSeconds(), 0.0f); + EXPECT_GT(a.GetElapsedMilliseconds(), 0.0f); +} + +TEST(TestStopWatch, Reset) +{ + CStopWatch a; + CTestStopWatchThread thread; + a.StartZero(); + thread.Sleep(2); + EXPECT_GT(a.GetElapsedMilliseconds(), 1); + thread.Sleep(3); + a.Reset(); + EXPECT_LT(a.GetElapsedMilliseconds(), 5); +} diff --git a/xbmc/utils/test/TestStreamDetails.cpp b/xbmc/utils/test/TestStreamDetails.cpp new file mode 100644 index 0000000..7842eee --- /dev/null +++ b/xbmc/utils/test/TestStreamDetails.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/StreamDetails.h" + +#include + +TEST(TestStreamDetails, General) +{ + CStreamDetails a; + CStreamDetailVideo *video = new CStreamDetailVideo(); + CStreamDetailAudio *audio = new CStreamDetailAudio(); + CStreamDetailSubtitle *subtitle = new CStreamDetailSubtitle(); + + video->m_iWidth = 1920; + video->m_iHeight = 1080; + video->m_fAspect = 2.39f; + video->m_iDuration = 30; + video->m_strCodec = "h264"; + video->m_strStereoMode = "left_right"; + video->m_strLanguage = "eng"; + + audio->m_iChannels = 2; + audio->m_strCodec = "aac"; + audio->m_strLanguage = "eng"; + + subtitle->m_strLanguage = "eng"; + + a.AddStream(video); + a.AddStream(audio); + + EXPECT_TRUE(a.HasItems()); + + EXPECT_EQ(1, a.GetStreamCount(CStreamDetail::VIDEO)); + EXPECT_EQ(1, a.GetVideoStreamCount()); + EXPECT_STREQ("", a.GetVideoCodec().c_str()); + EXPECT_EQ(0.0f, a.GetVideoAspect()); + EXPECT_EQ(0, a.GetVideoWidth()); + EXPECT_EQ(0, a.GetVideoHeight()); + EXPECT_EQ(0, a.GetVideoDuration()); + EXPECT_STREQ("", a.GetStereoMode().c_str()); + + EXPECT_EQ(1, a.GetStreamCount(CStreamDetail::AUDIO)); + EXPECT_EQ(1, a.GetAudioStreamCount()); + + EXPECT_EQ(0, a.GetStreamCount(CStreamDetail::SUBTITLE)); + EXPECT_EQ(0, a.GetSubtitleStreamCount()); + + a.AddStream(subtitle); + EXPECT_EQ(1, a.GetStreamCount(CStreamDetail::SUBTITLE)); + EXPECT_EQ(1, a.GetSubtitleStreamCount()); + + a.DetermineBestStreams(); + EXPECT_STREQ("h264", a.GetVideoCodec().c_str()); + EXPECT_EQ(2.39f, a.GetVideoAspect()); + EXPECT_EQ(1920, a.GetVideoWidth()); + EXPECT_EQ(1080, a.GetVideoHeight()); + EXPECT_EQ(30, a.GetVideoDuration()); + EXPECT_STREQ("left_right", a.GetStereoMode().c_str()); +} + +TEST(TestStreamDetails, VideoDimsToResolutionDescription) +{ + EXPECT_STREQ("1080", + CStreamDetails::VideoDimsToResolutionDescription(1920, 1080).c_str()); +} + +TEST(TestStreamDetails, VideoAspectToAspectDescription) +{ + EXPECT_STREQ("2.40", CStreamDetails::VideoAspectToAspectDescription(2.39f).c_str()); +} diff --git a/xbmc/utils/test/TestStreamUtils.cpp b/xbmc/utils/test/TestStreamUtils.cpp new file mode 100644 index 0000000..e23f958 --- /dev/null +++ b/xbmc/utils/test/TestStreamUtils.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/StreamUtils.h" + +#include + +TEST(TestStreamUtils, General) +{ + EXPECT_EQ(0, StreamUtils::GetCodecPriority("")); + EXPECT_EQ(1, StreamUtils::GetCodecPriority("ac3")); + EXPECT_EQ(2, StreamUtils::GetCodecPriority("dca")); + EXPECT_EQ(3, StreamUtils::GetCodecPriority("eac3")); + EXPECT_EQ(4, StreamUtils::GetCodecPriority("dtshd_hra")); + EXPECT_EQ(5, StreamUtils::GetCodecPriority("dtshd_ma")); + EXPECT_EQ(6, StreamUtils::GetCodecPriority("truehd")); + EXPECT_EQ(7, StreamUtils::GetCodecPriority("flac")); +} diff --git a/xbmc/utils/test/TestStringUtils.cpp b/xbmc/utils/test/TestStringUtils.cpp new file mode 100644 index 0000000..0a063cc --- /dev/null +++ b/xbmc/utils/test/TestStringUtils.cpp @@ -0,0 +1,605 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/StringUtils.h" + +#include + +#include +enum class ECG +{ + A, + B +}; + +enum EG +{ + C, + D +}; + +namespace test_enum +{ +enum class ECN +{ + A = 1, + B +}; +enum EN +{ + C = 1, + D +}; +} +TEST(TestStringUtils, Format) +{ + std::string refstr = "test 25 2.7 ff FF"; + + std::string varstr = + StringUtils::Format("%s %d %.1f %x %02X", "test", 25, 2.743f, 0x00ff, 0x00ff); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + varstr = StringUtils::Format("", "test", 25, 2.743f, 0x00ff, 0x00ff); + EXPECT_STREQ("", varstr.c_str()); +} + +TEST(TestStringUtils, FormatEnum) +{ + const char* zero = "0"; + const char* one = "1"; + + std::string varstr = StringUtils::Format("{}", ECG::A); + EXPECT_STREQ(zero, varstr.c_str()); + + varstr = StringUtils::Format("{}", EG::C); + EXPECT_STREQ(zero, varstr.c_str()); + + varstr = StringUtils::Format("{}", test_enum::ECN::A); + EXPECT_STREQ(one, varstr.c_str()); + + varstr = StringUtils::Format("{}", test_enum::EN::C); + EXPECT_STREQ(one, varstr.c_str()); +} + +TEST(TestStringUtils, FormatEnumWidth) +{ + const char* one = "01"; + + std::string varstr = StringUtils::Format("{:02d}", ECG::B); + EXPECT_STREQ(one, varstr.c_str()); + + varstr = StringUtils::Format("%02d", EG::D); + EXPECT_STREQ(one, varstr.c_str()); +} + +TEST(TestStringUtils, ToUpper) +{ + std::string refstr = "TEST"; + + std::string varstr = "TeSt"; + StringUtils::ToUpper(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, ToLower) +{ + std::string refstr = "test"; + + std::string varstr = "TeSt"; + StringUtils::ToLower(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, ToCapitalize) +{ + std::string refstr = "Test"; + std::string varstr = "test"; + StringUtils::ToCapitalize(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "Just A Test"; + varstr = "just a test"; + StringUtils::ToCapitalize(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "Test -1;2:3, String For Case"; + varstr = "test -1;2:3, string for Case"; + StringUtils::ToCapitalize(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = " JuST Another\t\tTEst:\nWoRKs "; + varstr = " juST another\t\ttEst:\nwoRKs "; + StringUtils::ToCapitalize(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "N.Y.P.D"; + varstr = "n.y.p.d"; + StringUtils::ToCapitalize(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "N-Y-P-D"; + varstr = "n-y-p-d"; + StringUtils::ToCapitalize(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, EqualsNoCase) +{ + std::string refstr = "TeSt"; + + EXPECT_TRUE(StringUtils::EqualsNoCase(refstr, "TeSt")); + EXPECT_TRUE(StringUtils::EqualsNoCase(refstr, "tEsT")); +} + +TEST(TestStringUtils, Left) +{ + std::string refstr, varstr; + std::string origstr = "test"; + + refstr = ""; + varstr = StringUtils::Left(origstr, 0); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "te"; + varstr = StringUtils::Left(origstr, 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "test"; + varstr = StringUtils::Left(origstr, 10); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, Mid) +{ + std::string refstr, varstr; + std::string origstr = "test"; + + refstr = ""; + varstr = StringUtils::Mid(origstr, 0, 0); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "te"; + varstr = StringUtils::Mid(origstr, 0, 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "test"; + varstr = StringUtils::Mid(origstr, 0, 10); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "st"; + varstr = StringUtils::Mid(origstr, 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "st"; + varstr = StringUtils::Mid(origstr, 2, 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "es"; + varstr = StringUtils::Mid(origstr, 1, 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, Right) +{ + std::string refstr, varstr; + std::string origstr = "test"; + + refstr = ""; + varstr = StringUtils::Right(origstr, 0); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "st"; + varstr = StringUtils::Right(origstr, 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "test"; + varstr = StringUtils::Right(origstr, 10); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, Trim) +{ + std::string refstr = "test test"; + + std::string varstr = " test test "; + StringUtils::Trim(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, TrimLeft) +{ + std::string refstr = "test test "; + + std::string varstr = " test test "; + StringUtils::TrimLeft(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, TrimRight) +{ + std::string refstr = " test test"; + + std::string varstr = " test test "; + StringUtils::TrimRight(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, Replace) +{ + std::string refstr = "text text"; + + std::string varstr = "test test"; + EXPECT_EQ(StringUtils::Replace(varstr, 's', 'x'), 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + EXPECT_EQ(StringUtils::Replace(varstr, 's', 'x'), 0); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + varstr = "test test"; + EXPECT_EQ(StringUtils::Replace(varstr, "s", "x"), 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + EXPECT_EQ(StringUtils::Replace(varstr, "s", "x"), 0); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, StartsWith) +{ + std::string refstr = "test"; + + EXPECT_FALSE(StringUtils::StartsWithNoCase(refstr, "x")); + + EXPECT_TRUE(StringUtils::StartsWith(refstr, "te")); + EXPECT_TRUE(StringUtils::StartsWith(refstr, "test")); + EXPECT_FALSE(StringUtils::StartsWith(refstr, "Te")); + + EXPECT_TRUE(StringUtils::StartsWithNoCase(refstr, "Te")); + EXPECT_TRUE(StringUtils::StartsWithNoCase(refstr, "TesT")); +} + +TEST(TestStringUtils, EndsWith) +{ + std::string refstr = "test"; + + EXPECT_FALSE(StringUtils::EndsWithNoCase(refstr, "x")); + + EXPECT_TRUE(StringUtils::EndsWith(refstr, "st")); + EXPECT_TRUE(StringUtils::EndsWith(refstr, "test")); + EXPECT_FALSE(StringUtils::EndsWith(refstr, "sT")); + + EXPECT_TRUE(StringUtils::EndsWithNoCase(refstr, "sT")); + EXPECT_TRUE(StringUtils::EndsWithNoCase(refstr, "TesT")); +} + +TEST(TestStringUtils, Join) +{ + std::string refstr, varstr; + std::vector strarray; + + strarray.emplace_back("a"); + strarray.emplace_back("b"); + strarray.emplace_back("c"); + strarray.emplace_back("de"); + strarray.emplace_back(","); + strarray.emplace_back("fg"); + strarray.emplace_back(","); + refstr = "a,b,c,de,,,fg,,"; + varstr = StringUtils::Join(strarray, ","); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, Split) +{ + std::vector varresults; + + // test overload with string as delimiter + varresults = StringUtils::Split("g,h,ij,k,lm,,n", ","); + EXPECT_STREQ("g", varresults.at(0).c_str()); + EXPECT_STREQ("h", varresults.at(1).c_str()); + EXPECT_STREQ("ij", varresults.at(2).c_str()); + EXPECT_STREQ("k", varresults.at(3).c_str()); + EXPECT_STREQ("lm", varresults.at(4).c_str()); + EXPECT_STREQ("", varresults.at(5).c_str()); + EXPECT_STREQ("n", varresults.at(6).c_str()); + + EXPECT_TRUE(StringUtils::Split("", "|").empty()); + + EXPECT_EQ(4U, StringUtils::Split("a bc d ef ghi ", " ", 4).size()); + EXPECT_STREQ("d ef ghi ", StringUtils::Split("a bc d ef ghi ", " ", 4).at(3).c_str()) << "Last part must include rest of the input string"; + EXPECT_EQ(7U, StringUtils::Split("a bc d ef ghi ", " ").size()) << "Result must be 7 strings including two empty strings"; + EXPECT_STREQ("bc", StringUtils::Split("a bc d ef ghi ", " ").at(1).c_str()); + EXPECT_STREQ("", StringUtils::Split("a bc d ef ghi ", " ").at(2).c_str()); + EXPECT_STREQ("", StringUtils::Split("a bc d ef ghi ", " ").at(6).c_str()); + + EXPECT_EQ(2U, StringUtils::Split("a bc d ef ghi ", " ").size()); + EXPECT_EQ(2U, StringUtils::Split("a bc d ef ghi ", " ", 10).size()); + EXPECT_STREQ("a bc", StringUtils::Split("a bc d ef ghi ", " ", 10).at(0).c_str()); + + EXPECT_EQ(1U, StringUtils::Split("a bc d ef ghi ", " z").size()); + EXPECT_STREQ("a bc d ef ghi ", StringUtils::Split("a bc d ef ghi ", " z").at(0).c_str()); + + EXPECT_EQ(1U, StringUtils::Split("a bc d ef ghi ", "").size()); + EXPECT_STREQ("a bc d ef ghi ", StringUtils::Split("a bc d ef ghi ", "").at(0).c_str()); + + // test overload with char as delimiter + EXPECT_EQ(4U, StringUtils::Split("a bc d ef ghi ", ' ', 4).size()); + EXPECT_STREQ("d ef ghi ", StringUtils::Split("a bc d ef ghi ", ' ', 4).at(3).c_str()); + EXPECT_EQ(7U, StringUtils::Split("a bc d ef ghi ", ' ').size()) << "Result must be 7 strings including two empty strings"; + EXPECT_STREQ("bc", StringUtils::Split("a bc d ef ghi ", ' ').at(1).c_str()); + EXPECT_STREQ("", StringUtils::Split("a bc d ef ghi ", ' ').at(2).c_str()); + EXPECT_STREQ("", StringUtils::Split("a bc d ef ghi ", ' ').at(6).c_str()); + + EXPECT_EQ(1U, StringUtils::Split("a bc d ef ghi ", 'z').size()); + EXPECT_STREQ("a bc d ef ghi ", StringUtils::Split("a bc d ef ghi ", 'z').at(0).c_str()); + + EXPECT_EQ(1U, StringUtils::Split("a bc d ef ghi ", "").size()); + EXPECT_STREQ("a bc d ef ghi ", StringUtils::Split("a bc d ef ghi ", 'z').at(0).c_str()); +} + +TEST(TestStringUtils, FindNumber) +{ + EXPECT_EQ(3, StringUtils::FindNumber("aabcaadeaa", "aa")); + EXPECT_EQ(1, StringUtils::FindNumber("aabcaadeaa", "b")); +} + +TEST(TestStringUtils, AlphaNumericCompare) +{ + int64_t ref, var; + + ref = 0; + var = StringUtils::AlphaNumericCompare(L"123abc", L"abc123"); + EXPECT_LT(var, ref); +} + +TEST(TestStringUtils, TimeStringToSeconds) +{ + EXPECT_EQ(77455, StringUtils::TimeStringToSeconds("21:30:55")); + EXPECT_EQ(7*60, StringUtils::TimeStringToSeconds("7 min")); + EXPECT_EQ(7*60, StringUtils::TimeStringToSeconds("7 min\t")); + EXPECT_EQ(154*60, StringUtils::TimeStringToSeconds(" 154 min")); + EXPECT_EQ(1*60+1, StringUtils::TimeStringToSeconds("1:01")); + EXPECT_EQ(4*60+3, StringUtils::TimeStringToSeconds("4:03")); + EXPECT_EQ(2*3600+4*60+3, StringUtils::TimeStringToSeconds("2:04:03")); + EXPECT_EQ(2*3600+4*60+3, StringUtils::TimeStringToSeconds(" 2:4:3")); + EXPECT_EQ(2*3600+4*60+3, StringUtils::TimeStringToSeconds(" \t\t 02:04:03 \n ")); + EXPECT_EQ(1*3600+5*60+2, StringUtils::TimeStringToSeconds("01:05:02:04:03 \n ")); + EXPECT_EQ(0, StringUtils::TimeStringToSeconds("blah")); + EXPECT_EQ(0, StringUtils::TimeStringToSeconds("ля-ля")); +} + +TEST(TestStringUtils, RemoveCRLF) +{ + std::string refstr, varstr; + + refstr = "test\r\nstring\nblah blah"; + varstr = "test\r\nstring\nblah blah\n"; + StringUtils::RemoveCRLF(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, utf8_strlen) +{ + size_t ref, var; + + ref = 9; + var = StringUtils::utf8_strlen("test_UTF8"); + EXPECT_EQ(ref, var); +} + +TEST(TestStringUtils, SecondsToTimeString) +{ + std::string ref, var; + + ref = "21:30:55"; + var = StringUtils::SecondsToTimeString(77455); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST(TestStringUtils, IsNaturalNumber) +{ + EXPECT_TRUE(StringUtils::IsNaturalNumber("10")); + EXPECT_TRUE(StringUtils::IsNaturalNumber(" 10")); + EXPECT_TRUE(StringUtils::IsNaturalNumber("0")); + EXPECT_FALSE(StringUtils::IsNaturalNumber(" 1 0")); + EXPECT_FALSE(StringUtils::IsNaturalNumber("1.0")); + EXPECT_FALSE(StringUtils::IsNaturalNumber("1.1")); + EXPECT_FALSE(StringUtils::IsNaturalNumber("0x1")); + EXPECT_FALSE(StringUtils::IsNaturalNumber("blah")); + EXPECT_FALSE(StringUtils::IsNaturalNumber("120 h")); + EXPECT_FALSE(StringUtils::IsNaturalNumber(" ")); + EXPECT_FALSE(StringUtils::IsNaturalNumber("")); +} + +TEST(TestStringUtils, IsInteger) +{ + EXPECT_TRUE(StringUtils::IsInteger("10")); + EXPECT_TRUE(StringUtils::IsInteger(" -10")); + EXPECT_TRUE(StringUtils::IsInteger("0")); + EXPECT_FALSE(StringUtils::IsInteger(" 1 0")); + EXPECT_FALSE(StringUtils::IsInteger("1.0")); + EXPECT_FALSE(StringUtils::IsInteger("1.1")); + EXPECT_FALSE(StringUtils::IsInteger("0x1")); + EXPECT_FALSE(StringUtils::IsInteger("blah")); + EXPECT_FALSE(StringUtils::IsInteger("120 h")); + EXPECT_FALSE(StringUtils::IsInteger(" ")); + EXPECT_FALSE(StringUtils::IsInteger("")); +} + +TEST(TestStringUtils, SizeToString) +{ + std::string ref, var; + + ref = "2.00 GB"; + var = StringUtils::SizeToString(2147483647); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST(TestStringUtils, EmptyString) +{ + EXPECT_STREQ("", StringUtils::Empty.c_str()); +} + +TEST(TestStringUtils, FindWords) +{ + size_t ref, var; + + ref = 5; + var = StringUtils::FindWords("test string", "string"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("12345string", "string"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("apple2012", "2012"); + EXPECT_EQ(ref, var); + ref = -1; + var = StringUtils::FindWords("12345string", "ring"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("12345string", "345"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("apple2012", "e2012"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("apple2012", "12"); + EXPECT_EQ(ref, var); +} + +TEST(TestStringUtils, FindWords_NonAscii) +{ + size_t ref, var; + + ref = 6; + var = StringUtils::FindWords("我的视频", "视频"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("我的视频", "视"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("Apple ple", "ple"); + EXPECT_EQ(ref, var); + ref = 7; + var = StringUtils::FindWords("Äpfel.pfel", "pfel"); + EXPECT_EQ(ref, var); +} + +TEST(TestStringUtils, FindEndBracket) +{ + int ref, var; + + ref = 11; + var = StringUtils::FindEndBracket("atest testbb test", 'a', 'b'); + EXPECT_EQ(ref, var); +} + +TEST(TestStringUtils, DateStringToYYYYMMDD) +{ + int ref, var; + + ref = 20120706; + var = StringUtils::DateStringToYYYYMMDD("2012-07-06"); + EXPECT_EQ(ref, var); +} + +TEST(TestStringUtils, WordToDigits) +{ + std::string ref, var; + + ref = "8378 787464"; + var = "test string"; + StringUtils::WordToDigits(var); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST(TestStringUtils, CreateUUID) +{ + std::cout << "CreateUUID(): " << StringUtils::CreateUUID() << std::endl; +} + +TEST(TestStringUtils, ValidateUUID) +{ + EXPECT_TRUE(StringUtils::ValidateUUID(StringUtils::CreateUUID())); +} + +TEST(TestStringUtils, CompareFuzzy) +{ + double ref, var; + + ref = 6.25f; + var = StringUtils::CompareFuzzy("test string", "string test"); + EXPECT_EQ(ref, var); +} + +TEST(TestStringUtils, FindBestMatch) +{ + double refdouble, vardouble; + int refint, varint; + std::vector strarray; + + refint = 3; + refdouble = 0.5625f; + strarray.emplace_back(""); + strarray.emplace_back("a"); + strarray.emplace_back("e"); + strarray.emplace_back("es"); + strarray.emplace_back("t"); + varint = StringUtils::FindBestMatch("test", strarray, vardouble); + EXPECT_EQ(refint, varint); + EXPECT_EQ(refdouble, vardouble); +} + +TEST(TestStringUtils, Paramify) +{ + const char *input = "some, very \\ odd \"string\""; + const char *ref = "\"some, very \\\\ odd \\\"string\\\"\""; + + std::string result = StringUtils::Paramify(input); + EXPECT_STREQ(ref, result.c_str()); +} + +TEST(TestStringUtils, sortstringbyname) +{ + std::vector strarray; + strarray.emplace_back("B"); + strarray.emplace_back("c"); + strarray.emplace_back("a"); + std::sort(strarray.begin(), strarray.end(), sortstringbyname()); + + EXPECT_STREQ("a", strarray[0].c_str()); + EXPECT_STREQ("B", strarray[1].c_str()); + EXPECT_STREQ("c", strarray[2].c_str()); +} + +TEST(TestStringUtils, FileSizeFormat) +{ + EXPECT_STREQ("0B", StringUtils::FormatFileSize(0).c_str()); + + EXPECT_STREQ("999B", StringUtils::FormatFileSize(999).c_str()); + EXPECT_STREQ("0.98kB", StringUtils::FormatFileSize(1000).c_str()); + + EXPECT_STREQ("1.00kB", StringUtils::FormatFileSize(1024).c_str()); + EXPECT_STREQ("9.99kB", StringUtils::FormatFileSize(10229).c_str()); + + EXPECT_STREQ("10.1kB", StringUtils::FormatFileSize(10387).c_str()); + EXPECT_STREQ("99.9kB", StringUtils::FormatFileSize(102297).c_str()); + + EXPECT_STREQ("100kB", StringUtils::FormatFileSize(102400).c_str()); + EXPECT_STREQ("999kB", StringUtils::FormatFileSize(1023431).c_str()); + + EXPECT_STREQ("0.98MB", StringUtils::FormatFileSize(1023897).c_str()); + EXPECT_STREQ("0.98MB", StringUtils::FormatFileSize(1024000).c_str()); + + //Last unit should overflow the 3 digit limit + EXPECT_STREQ("5432PB", StringUtils::FormatFileSize(6115888293969133568).c_str()); +} + +TEST(TestStringUtils, ToHexadecimal) +{ + EXPECT_STREQ("", StringUtils::ToHexadecimal("").c_str()); + EXPECT_STREQ("616263", StringUtils::ToHexadecimal("abc").c_str()); + std::string a{"a\0b\n", 4}; + EXPECT_STREQ("6100620a", StringUtils::ToHexadecimal(a).c_str()); + std::string nul{"\0", 1}; + EXPECT_STREQ("00", StringUtils::ToHexadecimal(nul).c_str()); + std::string ff{"\xFF", 1}; + EXPECT_STREQ("ff", StringUtils::ToHexadecimal(ff).c_str()); +} diff --git a/xbmc/utils/test/TestSystemInfo.cpp b/xbmc/utils/test/TestSystemInfo.cpp new file mode 100644 index 0000000..1f2b0a1 --- /dev/null +++ b/xbmc/utils/test/TestSystemInfo.cpp @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "GUIInfoManager.h" +#include "ServiceBroker.h" +#include "settings/Settings.h" +#include "utils/CPUInfo.h" +#include "utils/SystemInfo.h" +#if defined(TARGET_WINDOWS) +#include "platform/win32/CharsetConverter.h" +#endif + +#include + +class TestSystemInfo : public testing::Test +{ +protected: + TestSystemInfo() { CServiceBroker::RegisterCPUInfo(CCPUInfo::GetCPUInfo()); } + ~TestSystemInfo() { CServiceBroker::UnregisterCPUInfo(); } +}; + +TEST_F(TestSystemInfo, Print_System_Info) +{ + std::cout << "'GetKernelName(false)': \"" << g_sysinfo.GetKernelName(true) << "\"\n"; + std::cout << "'GetKernelVersion()': \"" << g_sysinfo.GetKernelVersion() << "\"\n"; + std::cout << "'GetKernelVersionFull()': \"" << g_sysinfo.GetKernelVersionFull() << "\"\n"; + std::cout << "'GetOsPrettyNameWithVersion()': \"" << g_sysinfo.GetOsPrettyNameWithVersion() << "\"\n"; + std::cout << "'GetOsName(false)': \"" << g_sysinfo.GetOsName(false) << "\"\n"; + std::cout << "'GetOsVersion()': \"" << g_sysinfo.GetOsVersion() << "\"\n"; + std::cout << "'GetKernelCpuFamily()': \"" << g_sysinfo.GetKernelCpuFamily() << "\"\n"; + std::cout << "'GetKernelBitness()': \"" << g_sysinfo.GetKernelBitness() << "\"\n"; + std::cout << "'GetBuildTargetPlatformName()': \"" << g_sysinfo.GetBuildTargetPlatformName() << "\"\n"; + std::cout << "'GetBuildTargetPlatformVersionDecoded()': \"" << g_sysinfo.GetBuildTargetPlatformVersionDecoded() << "\"\n"; + std::cout << "'GetBuildTargetPlatformVersion()': \"" << g_sysinfo.GetBuildTargetPlatformVersion() << "\"\n"; + std::cout << "'GetBuildTargetCpuFamily()': \"" << g_sysinfo.GetBuildTargetCpuFamily() << "\"\n"; + std::cout << "'GetXbmcBitness()': \"" << g_sysinfo.GetXbmcBitness() << "\"\n"; + std::cout << "'GetUsedCompilerNameAndVer()': \"" << g_sysinfo.GetUsedCompilerNameAndVer() << "\"\n"; + std::cout << "'GetManufacturerName()': \"" << g_sysinfo.GetManufacturerName() << "\"\n"; + std::cout << "'GetModelName()': \"" << g_sysinfo.GetModelName() << "\"\n"; + std::cout << "'GetUserAgent()': \"" << g_sysinfo.GetUserAgent() << "\"\n"; +} + +TEST_F(TestSystemInfo, GetKernelName) +{ + EXPECT_FALSE(g_sysinfo.GetKernelName(true).empty()) << "'GetKernelName(true)' must not return empty kernel name"; + EXPECT_FALSE(g_sysinfo.GetKernelName(false).empty()) << "'GetKernelName(false)' must not return empty kernel name"; + EXPECT_STRCASENE("Unknown kernel", g_sysinfo.GetKernelName(true).c_str()) << "'GetKernelName(true)' must not return 'Unknown kernel'"; + EXPECT_STRCASENE("Unknown kernel", g_sysinfo.GetKernelName(false).c_str()) << "'GetKernelName(false)' must not return 'Unknown kernel'"; +#ifndef TARGET_DARWIN + EXPECT_EQ(g_sysinfo.GetBuildTargetPlatformName(), g_sysinfo.GetKernelName(true)) << "'GetKernelName(true)' must match GetBuildTargetPlatformName()"; + EXPECT_EQ(g_sysinfo.GetBuildTargetPlatformName(), g_sysinfo.GetKernelName(false)) << "'GetKernelName(false)' must match GetBuildTargetPlatformName()"; +#endif // !TARGET_DARWIN +#if defined(TARGET_WINDOWS) + EXPECT_NE(std::string::npos, g_sysinfo.GetKernelName(true).find("Windows")) << "'GetKernelName(true)' must contain 'Windows'"; + EXPECT_NE(std::string::npos, g_sysinfo.GetKernelName(false).find("Windows")) << "'GetKernelName(false)' must contain 'Windows'"; +#elif defined(TARGET_FREEBSD) + EXPECT_STREQ("FreeBSD", g_sysinfo.GetKernelName(true).c_str()) << "'GetKernelName(true)' must return 'FreeBSD'"; + EXPECT_STREQ("FreeBSD", g_sysinfo.GetKernelName(false).c_str()) << "'GetKernelName(false)' must return 'FreeBSD'"; +#elif defined(TARGET_DARWIN) + EXPECT_STREQ("Darwin", g_sysinfo.GetKernelName(true).c_str()) << "'GetKernelName(true)' must return 'Darwin'"; + EXPECT_STREQ("Darwin", g_sysinfo.GetKernelName(false).c_str()) << "'GetKernelName(false)' must return 'Darwin'"; +#elif defined(TARGET_LINUX) + EXPECT_STREQ("Linux", g_sysinfo.GetKernelName(true).c_str()) << "'GetKernelName(true)' must return 'Linux'"; + EXPECT_STREQ("Linux", g_sysinfo.GetKernelName(false).c_str()) << "'GetKernelName(false)' must return 'Linux'"; +#endif +} + +TEST_F(TestSystemInfo, GetKernelVersionFull) +{ + EXPECT_FALSE(g_sysinfo.GetKernelVersionFull().empty()) << "'GetKernelVersionFull()' must not return empty string"; + EXPECT_STRNE("0.0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0.0'"; + EXPECT_STRNE("0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0'"; + EXPECT_EQ(0U, g_sysinfo.GetKernelVersionFull().find_first_of("0123456789")) << "'GetKernelVersionFull()' must not return version not starting from digit"; +} + +TEST_F(TestSystemInfo, GetKernelVersion) +{ + EXPECT_FALSE(g_sysinfo.GetKernelVersion().empty()) << "'GetKernelVersion()' must not return empty string"; + EXPECT_STRNE("0.0.0", g_sysinfo.GetKernelVersion().c_str()) << "'GetKernelVersion()' must not return '0.0.0'"; + EXPECT_STRNE("0.0", g_sysinfo.GetKernelVersion().c_str()) << "'GetKernelVersion()' must not return '0.0'"; + EXPECT_EQ(0U, g_sysinfo.GetKernelVersion().find_first_of("0123456789")) << "'GetKernelVersion()' must not return version not starting from digit"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetKernelVersion().find_first_not_of("0123456789.")) << "'GetKernelVersion()' must not return version with not only digits and dots"; +} + +TEST_F(TestSystemInfo, GetOsName) +{ + EXPECT_FALSE(g_sysinfo.GetOsName(true).empty()) << "'GetOsName(true)' must not return empty OS name"; + EXPECT_FALSE(g_sysinfo.GetOsName(false).empty()) << "'GetOsName(false)' must not return empty OS name"; + EXPECT_STRCASENE("Unknown OS", g_sysinfo.GetOsName(true).c_str()) << "'GetOsName(true)' must not return 'Unknown OS'"; + EXPECT_STRCASENE("Unknown OS", g_sysinfo.GetOsName(false).c_str()) << "'GetOsName(false)' must not return 'Unknown OS'"; +#if defined(TARGET_WINDOWS) + EXPECT_NE(std::string::npos, g_sysinfo.GetOsName(true).find("Windows")) << "'GetOsName(true)' must contain 'Windows'"; + EXPECT_NE(std::string::npos, g_sysinfo.GetOsName(false).find("Windows")) << "'GetOsName(false)' must contain 'Windows'"; +#elif defined(TARGET_FREEBSD) + EXPECT_STREQ("FreeBSD", g_sysinfo.GetOsName(true).c_str()) << "'GetOsName(true)' must return 'FreeBSD'"; + EXPECT_STREQ("FreeBSD", g_sysinfo.GetOsName(false).c_str()) << "'GetOsName(false)' must return 'FreeBSD'"; +#elif defined(TARGET_DARWIN_IOS) + EXPECT_STREQ("iOS", g_sysinfo.GetOsName(true).c_str()) << "'GetOsName(true)' must return 'iOS'"; + EXPECT_STREQ("iOS", g_sysinfo.GetOsName(false).c_str()) << "'GetOsName(false)' must return 'iOS'"; +#elif defined(TARGET_DARWIN_TVOS) + EXPECT_STREQ("tvOS", g_sysinfo.GetOsName(true).c_str()) << "'GetOsName(true)' must return 'tvOS'"; + EXPECT_STREQ("tvOS", g_sysinfo.GetOsName(false).c_str()) + << "'GetOsName(false)' must return 'tvOS'"; +#elif defined(TARGET_DARWIN_OSX) + EXPECT_STREQ("OS X", g_sysinfo.GetOsName(true).c_str()) << "'GetOsName(true)' must return 'OS X'"; + EXPECT_STREQ("OS X", g_sysinfo.GetOsName(false).c_str()) << "'GetOsName(false)' must return 'OS X'"; +#elif defined(TARGET_ANDROID) + EXPECT_STREQ("Android", g_sysinfo.GetOsName(true).c_str()) << "'GetOsName(true)' must return 'Android'"; + EXPECT_STREQ("Android", g_sysinfo.GetOsName(false).c_str()) << "'GetOsName(false)' must return 'Android'"; +#endif +#ifdef TARGET_DARWIN + EXPECT_EQ(g_sysinfo.GetBuildTargetPlatformName(), g_sysinfo.GetOsName(true)) << "'GetOsName(true)' must match GetBuildTargetPlatformName()"; + EXPECT_EQ(g_sysinfo.GetBuildTargetPlatformName(), g_sysinfo.GetOsName(false)) << "'GetOsName(false)' must match GetBuildTargetPlatformName()"; +#endif // TARGET_DARWIN +} + +TEST_F(TestSystemInfo, DISABLED_GetOsVersion) +{ + EXPECT_FALSE(g_sysinfo.GetOsVersion().empty()) << "'GetOsVersion()' must not return empty string"; + EXPECT_STRNE("0.0.0", g_sysinfo.GetOsVersion().c_str()) << "'GetOsVersion()' must not return '0.0.0'"; + EXPECT_STRNE("0.0", g_sysinfo.GetOsVersion().c_str()) << "'GetOsVersion()' must not return '0.0'"; + EXPECT_EQ(0U, g_sysinfo.GetOsVersion().find_first_of("0123456789")) << "'GetOsVersion()' must not return version not starting from digit"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetOsVersion().find_first_not_of("0123456789.")) << "'GetOsVersion()' must not return version with not only digits and dots"; +} + +TEST_F(TestSystemInfo, GetOsPrettyNameWithVersion) +{ + EXPECT_FALSE(g_sysinfo.GetOsPrettyNameWithVersion().empty()) << "'GetOsPrettyNameWithVersion()' must not return empty string"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetOsPrettyNameWithVersion().find("Unknown")) << "'GetOsPrettyNameWithVersion()' must not contain 'Unknown'"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetOsPrettyNameWithVersion().find("unknown")) << "'GetOsPrettyNameWithVersion()' must not contain 'unknown'"; +#ifdef TARGET_WINDOWS + EXPECT_NE(std::string::npos, g_sysinfo.GetOsPrettyNameWithVersion().find("Windows")) << "'GetOsPrettyNameWithVersion()' must contain 'Windows'"; +#else // ! TARGET_WINDOWS + EXPECT_NE(std::string::npos, g_sysinfo.GetOsPrettyNameWithVersion().find(g_sysinfo.GetOsVersion())) << "'GetOsPrettyNameWithVersion()' must contain OS version"; +#endif // ! TARGET_WINDOWS +} + +TEST_F(TestSystemInfo, GetManufacturerName) +{ + EXPECT_STRCASENE("unknown", g_sysinfo.GetManufacturerName().c_str()) << "'GetManufacturerName()' must return empty string instead of 'Unknown'"; +} + +TEST_F(TestSystemInfo, GetModelName) +{ + EXPECT_STRCASENE("unknown", g_sysinfo.GetModelName().c_str()) << "'GetModelName()' must return empty string instead of 'Unknown'"; +} + +#ifndef TARGET_WINDOWS +TEST_F(TestSystemInfo, IsAeroDisabled) +{ + EXPECT_FALSE(g_sysinfo.IsAeroDisabled()) << "'IsAeroDisabled()' must return 'false'"; +} +#endif // ! TARGET_WINDOWS + +TEST_F(TestSystemInfo, IsWindowsVersion) +{ + EXPECT_FALSE(g_sysinfo.IsWindowsVersion(CSysInfo::WindowsVersionUnknown)) << "'IsWindowsVersion()' must return 'false' for 'WindowsVersionUnknown'"; +#ifndef TARGET_WINDOWS + EXPECT_FALSE(g_sysinfo.IsWindowsVersion(CSysInfo::WindowsVersionWin7)) << "'IsWindowsVersion()' must return 'false'"; +#endif // ! TARGET_WINDOWS +} + +TEST_F(TestSystemInfo, IsWindowsVersionAtLeast) +{ + EXPECT_FALSE(g_sysinfo.IsWindowsVersionAtLeast(CSysInfo::WindowsVersionUnknown)) << "'IsWindowsVersionAtLeast()' must return 'false' for 'WindowsVersionUnknown'"; + EXPECT_FALSE(g_sysinfo.IsWindowsVersionAtLeast(CSysInfo::WindowsVersionFuture)) << "'IsWindowsVersionAtLeast()' must return 'false' for 'WindowsVersionFuture'"; +#ifndef TARGET_WINDOWS + EXPECT_FALSE(g_sysinfo.IsWindowsVersion(CSysInfo::WindowsVersionWin7)) << "'IsWindowsVersionAtLeast()' must return 'false'"; +#endif // ! TARGET_WINDOWS +} + +TEST_F(TestSystemInfo, GetWindowsVersion) +{ +#ifdef TARGET_WINDOWS + EXPECT_NE(CSysInfo::WindowsVersionUnknown, g_sysinfo.GetWindowsVersion()) << "'GetWindowsVersion()' must not return 'WindowsVersionUnknown'"; + EXPECT_NE(CSysInfo::WindowsVersionFuture, g_sysinfo.GetWindowsVersion()) << "'GetWindowsVersion()' must not return 'WindowsVersionFuture'"; +#else // ! TARGET_WINDOWS + EXPECT_EQ(CSysInfo::WindowsVersionUnknown, g_sysinfo.GetWindowsVersion()) << "'GetWindowsVersion()' must return 'WindowsVersionUnknown'"; +#endif // ! TARGET_WINDOWS +} + +TEST_F(TestSystemInfo, GetKernelBitness) +{ + EXPECT_TRUE(g_sysinfo.GetKernelBitness() == 32 || g_sysinfo.GetKernelBitness() == 64) << "'GetKernelBitness()' must return '32' or '64', but not '" << g_sysinfo.GetKernelBitness() << "'"; + EXPECT_LE(g_sysinfo.GetXbmcBitness(), g_sysinfo.GetKernelBitness()) << "'GetKernelBitness()' must be greater or equal to 'GetXbmcBitness()'"; +} + +TEST_F(TestSystemInfo, GetKernelCpuFamily) +{ + EXPECT_STRNE("unknown CPU family", g_sysinfo.GetKernelCpuFamily().c_str()) << "'GetKernelCpuFamily()' must not return 'unknown CPU family'"; +#if defined(__thumb__) || defined(_M_ARMT) || defined(__arm__) || defined(_M_ARM) || defined (__aarch64__) + EXPECT_STREQ("ARM", g_sysinfo.GetKernelCpuFamily().c_str()) << "'GetKernelCpuFamily()' must return 'ARM'"; +#else // ! ARM + EXPECT_EQ(g_sysinfo.GetBuildTargetCpuFamily(), g_sysinfo.GetKernelCpuFamily()) << "'GetKernelCpuFamily()' must match 'GetBuildTargetCpuFamily()'"; +#endif // ! ARM +} + +TEST_F(TestSystemInfo, GetXbmcBitness) +{ + EXPECT_TRUE(g_sysinfo.GetXbmcBitness() == 32 || g_sysinfo.GetXbmcBitness() == 64) << "'GetXbmcBitness()' must return '32' or '64', but not '" << g_sysinfo.GetXbmcBitness() << "'"; + EXPECT_GE(g_sysinfo.GetKernelBitness(), g_sysinfo.GetXbmcBitness()) << "'GetXbmcBitness()' must be not greater than 'GetKernelBitness()'"; +} + +TEST_F(TestSystemInfo, GetUserAgent) +{ + EXPECT_STREQ(g_sysinfo.GetAppName().c_str(), g_sysinfo.GetUserAgent().substr(0, g_sysinfo.GetAppName().size()).c_str()) << "'GetUserAgent()' string must start with app name'"; + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find('(')) << "'GetUserAgent()' must contain brackets around second parameter"; + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find(')')) << "'GetUserAgent()' must contain brackets around second parameter"; + EXPECT_EQ(g_sysinfo.GetUserAgent().find(' '), g_sysinfo.GetUserAgent().find(" (")) << "Second parameter in 'GetUserAgent()' string must be in brackets"; + EXPECT_EQ(g_sysinfo.GetUserAgent().find(" (") + 1, g_sysinfo.GetUserAgent().find('(')) << "'GetUserAgent()' string must not contain any opening brackets before second parameter"; + EXPECT_GT(g_sysinfo.GetUserAgent().find(')'), g_sysinfo.GetUserAgent().find('(')) << "'GetUserAgent()' string must not contain any closing brackets before second parameter"; + EXPECT_EQ(g_sysinfo.GetUserAgent().find(") "), g_sysinfo.GetUserAgent().find(')')) << "'GetUserAgent()' string must not contain any closing brackets before end of second parameter"; +#if defined(TARGET_WINDOWS) + EXPECT_EQ(g_sysinfo.GetUserAgent().find('('), g_sysinfo.GetUserAgent().find("(Windows")) << "Second parameter in 'GetUserAgent()' string must start from `Windows`"; + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find("Windows")) << "'GetUserAgent()' must contain 'Windows'"; +#elif defined(TARGET_DARWIN_IOS) + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find("like Mac OS X")) << "'GetUserAgent()' must contain ' like Mac OS X'"; + EXPECT_TRUE(g_sysinfo.GetUserAgent().find("CPU OS ") != std::string::npos || g_sysinfo.GetUserAgent().find("CPU iPhone OS ") != std::string::npos) << "'GetUserAgent()' must contain 'CPU OS ' or 'CPU iPhone OS '"; +#elif defined(TARGET_DARWIN_TVOS) + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find("like Mac OS X")) + << "'GetUserAgent()' must contain ' like Mac OS X'"; + EXPECT_TRUE(g_sysinfo.GetUserAgent().find("CPU TVOS ") != std::string::npos) + << "'GetUserAgent()' must contain 'CPU TVOS '"; +#elif defined(TARGET_DARWIN_OSX) + EXPECT_EQ(g_sysinfo.GetUserAgent().find('('), g_sysinfo.GetUserAgent().find("(Macintosh; ")) << "Second parameter in 'GetUserAgent()' string must start from 'Macintosh; '"; +#elif defined(TARGET_ANDROID) + EXPECT_EQ(g_sysinfo.GetUserAgent().find('('), g_sysinfo.GetUserAgent().find("(Linux; Android ")) << "Second parameter in 'GetUserAgent()' string must start from 'Linux; Android '"; +#elif defined(TARGET_POSIX) + EXPECT_EQ(g_sysinfo.GetUserAgent().find('('), g_sysinfo.GetUserAgent().find("(X11; ")) << "Second parameter in 'GetUserAgent()' string must start from 'X11; '"; +#if defined(TARGET_FREEBSD) + EXPECT_EQ(g_sysinfo.GetUserAgent().find('('), g_sysinfo.GetUserAgent().find("(X11; FreeBSD ")) << "Second parameter in 'GetUserAgent()' string must start from 'X11; FreeBSD '"; +#elif defined(TARGET_LINUX) + EXPECT_EQ(g_sysinfo.GetUserAgent().find('('), g_sysinfo.GetUserAgent().find("(X11; Linux ")) << "Second parameter in 'GetUserAgent()' string must start from 'X11; Linux '"; +#endif // defined(TARGET_LINUX) +#endif // defined(TARGET_POSIX) + +#ifdef TARGET_RASPBERRY_PI + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find(" XBMC_HW_RaspberryPi/")) << "'GetUserAgent()' must contain ' XBMC_HW_RaspberryPi/'"; +#endif // TARGET_RASPBERRY_PI + + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find(" App_Bitness/")) << "'GetUserAgent()' must contain ' App_Bitness/'"; + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find(" Version/")) << "'GetUserAgent()' must contain ' Version/'"; +} + +TEST_F(TestSystemInfo, GetBuildTargetPlatformName) +{ + EXPECT_EQ(std::string::npos, g_sysinfo.GetBuildTargetPlatformName().find("Unknown")) << "'GetBuildTargetPlatformName()' must not contain 'Unknown', actual value: '" << g_sysinfo.GetBuildTargetPlatformName() << "'"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetBuildTargetPlatformName().find("unknown")) << "'GetBuildTargetPlatformName()' must not contain 'unknown', actual value: '" << g_sysinfo.GetBuildTargetPlatformName() << "'"; +} + +TEST_F(TestSystemInfo, GetBuildTargetPlatformVersion) +{ + EXPECT_EQ(std::string::npos, g_sysinfo.GetBuildTargetPlatformVersion().find("Unknown")) << "'GetBuildTargetPlatformVersion()' must not contain 'Unknown', actual value: '" << g_sysinfo.GetBuildTargetPlatformVersion() << "'"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetBuildTargetPlatformVersion().find("unknown")) << "'GetBuildTargetPlatformVersion()' must not contain 'unknown', actual value: '" << g_sysinfo.GetBuildTargetPlatformVersion() << "'"; +} + +TEST_F(TestSystemInfo, GetBuildTargetPlatformVersionDecoded) +{ + EXPECT_EQ(std::string::npos, g_sysinfo.GetBuildTargetPlatformVersionDecoded().find("Unknown")) << "'GetBuildTargetPlatformVersionDecoded()' must not contain 'Unknown', actual value: '" << g_sysinfo.GetBuildTargetPlatformVersion() << "'"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetBuildTargetPlatformVersionDecoded().find("unknown")) << "'GetBuildTargetPlatformVersionDecoded()' must not contain 'unknown', actual value: '" << g_sysinfo.GetBuildTargetPlatformVersion() << "'"; +#ifdef TARGET_ANDROID + EXPECT_STREQ("API level ", g_sysinfo.GetBuildTargetPlatformVersionDecoded().substr(0, 10).c_str()) << "'GetBuildTargetPlatformVersionDecoded()' must start from 'API level '"; +#else + EXPECT_STREQ("version ", g_sysinfo.GetBuildTargetPlatformVersionDecoded().substr(0, 8).c_str()) << "'GetBuildTargetPlatformVersionDecoded()' must start from 'version'"; +#endif +} + +TEST_F(TestSystemInfo, GetBuildTargetCpuFamily) +{ + EXPECT_STRNE("unknown CPU family", g_sysinfo.GetBuildTargetCpuFamily().c_str()) << "'GetBuildTargetCpuFamily()' must not return 'unknown CPU family'"; +#if defined(__thumb__) || defined(_M_ARMT) || defined(__arm__) || defined(_M_ARM) || defined (__aarch64__) + EXPECT_STREQ("ARM", g_sysinfo.GetBuildTargetCpuFamily().substr(0, 3).c_str()) << "'GetKernelCpuFamily()' string must start from 'ARM'"; +#else // ! ARM + EXPECT_EQ(g_sysinfo.GetKernelCpuFamily(), g_sysinfo.GetBuildTargetCpuFamily()) << "'GetBuildTargetCpuFamily()' must match 'GetKernelCpuFamily()'"; +#endif // ! ARM +} + +TEST_F(TestSystemInfo, GetUsedCompilerNameAndVer) +{ + EXPECT_STRNE("unknown compiler", g_sysinfo.GetUsedCompilerNameAndVer().c_str()) << "'GetUsedCompilerNameAndVer()' must not return 'unknown compiler'"; +} + +TEST_F(TestSystemInfo, GetDiskSpace) +{ + int iTotal, iTotalFree, iTotalUsed, iPercentFree, iPercentUsed; + + iTotal = iTotalFree = iTotalUsed = iPercentFree = iPercentUsed = 0; + EXPECT_TRUE(g_sysinfo.GetDiskSpace("*", iTotal, iTotalFree, iTotalUsed, iPercentFree, iPercentUsed)) << "'GetDiskSpace()' return 'false' for disk '*'"; + EXPECT_NE(0, iTotal) << "'GetDiskSpace()' return zero total space for disk '*'"; + EXPECT_EQ(iTotal, iTotalFree + iTotalUsed) << "'GetDiskSpace()' return 'TotalFree + TotalUsed' not equal to 'Total' for disk '*'"; + EXPECT_EQ(100, iPercentFree + iPercentUsed) << "'GetDiskSpace()' return 'PercentFree + PercentUsed' not equal to '100' for disk '*'"; + + iTotal = iTotalFree = iTotalUsed = iPercentFree = iPercentUsed = 0; + EXPECT_TRUE(g_sysinfo.GetDiskSpace("", iTotal, iTotalFree, iTotalUsed, iPercentFree, iPercentUsed)) << "'GetDiskSpace()' return 'false' for disk ''"; + EXPECT_NE(0, iTotal) << "'GetDiskSpace()' return zero total space for disk ''"; + EXPECT_EQ(iTotal, iTotalFree + iTotalUsed) << "'GetDiskSpace()' return 'TotalFree + TotalUsed' not equal to 'Total' for disk ''"; + EXPECT_EQ(100, iPercentFree + iPercentUsed) << "'GetDiskSpace()' return 'PercentFree + PercentUsed' not equal to '100' for disk ''"; + +#ifdef TARGET_WINDOWS + using KODI::PLATFORM::WINDOWS::FromW; + wchar_t sysDrive[300]; + DWORD res = GetEnvironmentVariableW(L"SystemDrive", sysDrive, sizeof(sysDrive) / sizeof(wchar_t)); + std::string sysDriveLtr; + if (res != 0 && res <= sizeof(sysDrive) / sizeof(wchar_t)) + sysDriveLtr.assign(FromW(sysDrive), 0, 1); + else + sysDriveLtr = "C"; // fallback + + iTotal = iTotalFree = iTotalUsed = iPercentFree = iPercentUsed = 0; + EXPECT_TRUE(g_sysinfo.GetDiskSpace(sysDriveLtr, iTotal, iTotalFree, iTotalUsed, iPercentFree, iPercentUsed)) << "'GetDiskSpace()' return 'false' for disk '" << sysDriveLtr << ":'"; + EXPECT_NE(0, iTotal) << "'GetDiskSpace()' return zero total space for disk '" << sysDriveLtr << ":'"; + EXPECT_EQ(iTotal, iTotalFree + iTotalUsed) << "'GetDiskSpace()' return 'TotalFree + TotalUsed' not equal to 'Total' for disk '" << sysDriveLtr << ":'"; + EXPECT_EQ(100, iPercentFree + iPercentUsed) << "'GetDiskSpace()' return 'PercentFree + PercentUsed' not equal to '100' for disk '" << sysDriveLtr << ":'"; +#elif defined(TARGET_POSIX) + iTotal = iTotalFree = iTotalUsed = iPercentFree = iPercentUsed = 0; + EXPECT_TRUE(g_sysinfo.GetDiskSpace("/", iTotal, iTotalFree, iTotalUsed, iPercentFree, iPercentUsed)) << "'GetDiskSpace()' return 'false' for directory '/'"; + EXPECT_NE(0, iTotal) << "'GetDiskSpace()' return zero total space for directory '/'"; + EXPECT_EQ(iTotal, iTotalFree + iTotalUsed) << "'GetDiskSpace()' return 'TotalFree + TotalUsed' not equal to 'Total' for directory '/'"; + EXPECT_EQ(100, iPercentFree + iPercentUsed) << "'GetDiskSpace()' return 'PercentFree + PercentUsed' not equal to '100' for directory '/'"; +#endif +} diff --git a/xbmc/utils/test/TestURIUtils.cpp b/xbmc/utils/test/TestURIUtils.cpp new file mode 100644 index 0000000..7122fe9 --- /dev/null +++ b/xbmc/utils/test/TestURIUtils.cpp @@ -0,0 +1,585 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ServiceBroker.h" +#include "URL.h" +#include "filesystem/MultiPathDirectory.h" +#include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" +#include "utils/URIUtils.h" + +#include + +#include + +using namespace XFILE; + +class TestURIUtils : public testing::Test +{ +protected: + TestURIUtils() = default; + ~TestURIUtils() override + { + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_pathSubstitutions.clear(); + } +}; + +TEST_F(TestURIUtils, PathHasParent) +{ + EXPECT_TRUE(URIUtils::PathHasParent("/path/to/movie.avi", "/path/to/")); + EXPECT_FALSE(URIUtils::PathHasParent("/path/to/movie.avi", "/path/2/")); +} + +TEST_F(TestURIUtils, GetDirectory) +{ + EXPECT_STREQ("/path/to/", URIUtils::GetDirectory("/path/to/movie.avi").c_str()); + EXPECT_STREQ("/path/to/", URIUtils::GetDirectory("/path/to/").c_str()); + EXPECT_STREQ("/path/to/|option=foo", URIUtils::GetDirectory("/path/to/movie.avi|option=foo").c_str()); + EXPECT_STREQ("/path/to/|option=foo", URIUtils::GetDirectory("/path/to/|option=foo").c_str()); + EXPECT_STREQ("", URIUtils::GetDirectory("movie.avi").c_str()); + EXPECT_STREQ("", URIUtils::GetDirectory("movie.avi|option=foo").c_str()); + EXPECT_STREQ("", URIUtils::GetDirectory("").c_str()); + + // Make sure it works when assigning to the same str as the reference parameter + std::string var = "/path/to/movie.avi|option=foo"; + var = URIUtils::GetDirectory(var); + EXPECT_STREQ("/path/to/|option=foo", var.c_str()); +} + +TEST_F(TestURIUtils, GetExtension) +{ + EXPECT_STREQ(".avi", + URIUtils::GetExtension("/path/to/movie.avi").c_str()); +} + +TEST_F(TestURIUtils, HasExtension) +{ + EXPECT_TRUE (URIUtils::HasExtension("/path/to/movie.AvI")); + EXPECT_FALSE(URIUtils::HasExtension("/path/to/movie")); + EXPECT_FALSE(URIUtils::HasExtension("/path/.to/movie")); + EXPECT_FALSE(URIUtils::HasExtension("")); + + EXPECT_TRUE (URIUtils::HasExtension("/path/to/movie.AvI", ".avi")); + EXPECT_FALSE(URIUtils::HasExtension("/path/to/movie.AvI", ".mkv")); + EXPECT_FALSE(URIUtils::HasExtension("/path/.avi/movie", ".avi")); + EXPECT_FALSE(URIUtils::HasExtension("", ".avi")); + + EXPECT_TRUE (URIUtils::HasExtension("/path/movie.AvI", ".avi|.mkv|.mp4")); + EXPECT_TRUE (URIUtils::HasExtension("/path/movie.AvI", ".mkv|.avi|.mp4")); + EXPECT_FALSE(URIUtils::HasExtension("/path/movie.AvI", ".mpg|.mkv|.mp4")); + EXPECT_FALSE(URIUtils::HasExtension("/path.mkv/movie.AvI", ".mpg|.mkv|.mp4")); + EXPECT_FALSE(URIUtils::HasExtension("", ".avi|.mkv|.mp4")); +} + +TEST_F(TestURIUtils, GetFileName) +{ + EXPECT_STREQ("movie.avi", + URIUtils::GetFileName("/path/to/movie.avi").c_str()); +} + +TEST_F(TestURIUtils, RemoveExtension) +{ + std::string ref, var; + + /* NOTE: CSettings need to be set to find other extensions. */ + ref = "/path/to/file"; + var = "/path/to/file.xml"; + URIUtils::RemoveExtension(var); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, ReplaceExtension) +{ + std::string ref, var; + + ref = "/path/to/file.xsd"; + var = URIUtils::ReplaceExtension("/path/to/file.xml", ".xsd"); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, Split) +{ + std::string refpath, reffile, varpath, varfile; + + refpath = "/path/to/"; + reffile = "movie.avi"; + URIUtils::Split("/path/to/movie.avi", varpath, varfile); + EXPECT_STREQ(refpath.c_str(), varpath.c_str()); + EXPECT_STREQ(reffile.c_str(), varfile.c_str()); + + std::string varpathOptional, varfileOptional; + + refpath = "/path/to/"; + reffile = "movie?movie.avi"; + URIUtils::Split("/path/to/movie?movie.avi", varpathOptional, varfileOptional); + EXPECT_STREQ(refpath.c_str(), varpathOptional.c_str()); + EXPECT_STREQ(reffile.c_str(), varfileOptional.c_str()); + + refpath = "file:///path/to/"; + reffile = "movie.avi"; + URIUtils::Split("file:///path/to/movie.avi?showinfo=true", varpathOptional, varfileOptional); + EXPECT_STREQ(refpath.c_str(), varpathOptional.c_str()); + EXPECT_STREQ(reffile.c_str(), varfileOptional.c_str()); +} + +TEST_F(TestURIUtils, SplitPath) +{ + std::vector strarray; + + strarray = URIUtils::SplitPath("http://www.test.com/path/to/movie.avi"); + + EXPECT_STREQ("http://www.test.com/", strarray.at(0).c_str()); + EXPECT_STREQ("path", strarray.at(1).c_str()); + EXPECT_STREQ("to", strarray.at(2).c_str()); + EXPECT_STREQ("movie.avi", strarray.at(3).c_str()); +} + +TEST_F(TestURIUtils, SplitPathLocal) +{ +#ifndef TARGET_LINUX + const char *path = "C:\\path\\to\\movie.avi"; +#else + const char *path = "/path/to/movie.avi"; +#endif + std::vector strarray; + + strarray = URIUtils::SplitPath(path); + +#ifndef TARGET_LINUX + EXPECT_STREQ("C:", strarray.at(0).c_str()); +#else + EXPECT_STREQ("", strarray.at(0).c_str()); +#endif + EXPECT_STREQ("path", strarray.at(1).c_str()); + EXPECT_STREQ("to", strarray.at(2).c_str()); + EXPECT_STREQ("movie.avi", strarray.at(3).c_str()); +} + +TEST_F(TestURIUtils, GetCommonPath) +{ + std::string ref, var; + + ref = "/path/"; + var = "/path/2/movie.avi"; + URIUtils::GetCommonPath(var, "/path/to/movie.avi"); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, GetParentPath) +{ + std::string ref, var; + + ref = "/path/to/"; + var = URIUtils::GetParentPath("/path/to/movie.avi"); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + var.clear(); + EXPECT_TRUE(URIUtils::GetParentPath("/path/to/movie.avi", var)); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, SubstitutePath) +{ + std::string from, to, ref, var; + + from = "C:\\My Videos"; + to = "https://myserver/some%20other%20path"; + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_pathSubstitutions.push_back(std::make_pair(from, to)); + + from = "/this/path1"; + to = "/some/other/path2"; + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_pathSubstitutions.push_back(std::make_pair(from, to)); + + from = "davs://otherserver/my%20music%20path"; + to = "D:\\Local Music\\MP3 Collection"; + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_pathSubstitutions.push_back(std::make_pair(from, to)); + + ref = "https://myserver/some%20other%20path/sub%20dir/movie%20name.avi"; + var = URIUtils::SubstitutePath("C:\\My Videos\\sub dir\\movie name.avi"); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "C:\\My Videos\\sub dir\\movie name.avi"; + var = URIUtils::SubstitutePath("https://myserver/some%20other%20path/sub%20dir/movie%20name.avi", true); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "D:\\Local Music\\MP3 Collection\\Phil Collins\\Some CD\\01 - Two Hearts.mp3"; + var = URIUtils::SubstitutePath("davs://otherserver/my%20music%20path/Phil%20Collins/Some%20CD/01%20-%20Two%20Hearts.mp3"); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "davs://otherserver/my%20music%20path/Phil%20Collins/Some%20CD/01%20-%20Two%20Hearts.mp3"; + var = URIUtils::SubstitutePath("D:\\Local Music\\MP3 Collection\\Phil Collins\\Some CD\\01 - Two Hearts.mp3", true); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/some/other/path2/to/movie.avi"; + var = URIUtils::SubstitutePath("/this/path1/to/movie.avi"); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/this/path1/to/movie.avi"; + var = URIUtils::SubstitutePath("/some/other/path2/to/movie.avi", true); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/no/translation path/"; + var = URIUtils::SubstitutePath(ref); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/no/translation path/"; + var = URIUtils::SubstitutePath(ref, true); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "c:\\no\\translation path"; + var = URIUtils::SubstitutePath(ref); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "c:\\no\\translation path"; + var = URIUtils::SubstitutePath(ref, true); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, IsAddonsPath) +{ + EXPECT_TRUE(URIUtils::IsAddonsPath("addons://path/to/addons")); +} + +TEST_F(TestURIUtils, IsSourcesPath) +{ + EXPECT_TRUE(URIUtils::IsSourcesPath("sources://path/to/sources")); +} + +TEST_F(TestURIUtils, IsCDDA) +{ + EXPECT_TRUE(URIUtils::IsCDDA("cdda://path/to/cdda")); +} + +TEST_F(TestURIUtils, IsDOSPath) +{ + EXPECT_TRUE(URIUtils::IsDOSPath("C://path/to/dosfile")); +} + +TEST_F(TestURIUtils, IsDVD) +{ + EXPECT_TRUE(URIUtils::IsDVD("dvd://path/in/video_ts.ifo")); +#if defined(TARGET_WINDOWS) + EXPECT_TRUE(URIUtils::IsDVD("dvd://path/in/file")); +#else + EXPECT_TRUE(URIUtils::IsDVD("iso9660://path/in/video_ts.ifo")); + EXPECT_TRUE(URIUtils::IsDVD("udf://path/in/video_ts.ifo")); + EXPECT_TRUE(URIUtils::IsDVD("dvd://1")); +#endif +} + +TEST_F(TestURIUtils, IsFTP) +{ + EXPECT_TRUE(URIUtils::IsFTP("ftp://path/in/ftp")); +} + +TEST_F(TestURIUtils, IsHD) +{ + EXPECT_TRUE(URIUtils::IsHD("/path/to/file")); + EXPECT_TRUE(URIUtils::IsHD("file:///path/to/file")); + EXPECT_TRUE(URIUtils::IsHD("special://path/to/file")); + EXPECT_TRUE(URIUtils::IsHD("stack://path/to/file")); + EXPECT_TRUE(URIUtils::IsHD("zip://path/to/file")); +} + +TEST_F(TestURIUtils, IsInArchive) +{ + EXPECT_TRUE(URIUtils::IsInArchive("zip://path/to/file")); +} + +TEST_F(TestURIUtils, IsInRAR) +{ + EXPECT_TRUE(URIUtils::IsInRAR("rar://path/to/file")); +} + +TEST_F(TestURIUtils, IsInternetStream) +{ + CURL url1("http://path/to/file"); + CURL url2("https://path/to/file"); + EXPECT_TRUE(URIUtils::IsInternetStream(url1)); + EXPECT_TRUE(URIUtils::IsInternetStream(url2)); +} + +TEST_F(TestURIUtils, IsInZIP) +{ + EXPECT_TRUE(URIUtils::IsInZIP("zip://path/to/file")); +} + +TEST_F(TestURIUtils, IsISO9660) +{ + EXPECT_TRUE(URIUtils::IsISO9660("iso9660://path/to/file")); +} + +TEST_F(TestURIUtils, IsLiveTV) +{ + EXPECT_TRUE(URIUtils::IsLiveTV("whatever://path/to/file.pvr")); +} + +TEST_F(TestURIUtils, IsMultiPath) +{ + EXPECT_TRUE(URIUtils::IsMultiPath("multipath://path/to/file")); +} + +TEST_F(TestURIUtils, IsMusicDb) +{ + EXPECT_TRUE(URIUtils::IsMusicDb("musicdb://path/to/file")); +} + +TEST_F(TestURIUtils, IsNfs) +{ + EXPECT_TRUE(URIUtils::IsNfs("nfs://path/to/file")); + EXPECT_TRUE(URIUtils::IsNfs("stack://nfs://path/to/file")); +} + +TEST_F(TestURIUtils, IsOnDVD) +{ + EXPECT_TRUE(URIUtils::IsOnDVD("dvd://path/to/file")); + EXPECT_TRUE(URIUtils::IsOnDVD("udf://path/to/file")); + EXPECT_TRUE(URIUtils::IsOnDVD("iso9660://path/to/file")); + EXPECT_TRUE(URIUtils::IsOnDVD("cdda://path/to/file")); +} + +TEST_F(TestURIUtils, IsOnLAN) +{ + std::vector multiVec; + multiVec.emplace_back("smb://path/to/file"); + EXPECT_TRUE(URIUtils::IsOnLAN(CMultiPathDirectory::ConstructMultiPath(multiVec))); + EXPECT_TRUE(URIUtils::IsOnLAN("stack://smb://path/to/file")); + EXPECT_TRUE(URIUtils::IsOnLAN("smb://path/to/file")); + EXPECT_FALSE(URIUtils::IsOnLAN("plugin://path/to/file")); + EXPECT_TRUE(URIUtils::IsOnLAN("upnp://path/to/file")); +} + +TEST_F(TestURIUtils, IsPlugin) +{ + EXPECT_TRUE(URIUtils::IsPlugin("plugin://path/to/file")); +} + +TEST_F(TestURIUtils, IsScript) +{ + EXPECT_TRUE(URIUtils::IsScript("script://path/to/file")); +} + +TEST_F(TestURIUtils, IsRAR) +{ + EXPECT_TRUE(URIUtils::IsRAR("/path/to/rarfile.rar")); + EXPECT_TRUE(URIUtils::IsRAR("/path/to/rarfile.cbr")); + EXPECT_FALSE(URIUtils::IsRAR("/path/to/file")); + EXPECT_FALSE(URIUtils::IsRAR("rar://path/to/file")); +} + +TEST_F(TestURIUtils, IsRemote) +{ + EXPECT_TRUE(URIUtils::IsRemote("http://path/to/file")); + EXPECT_TRUE(URIUtils::IsRemote("https://path/to/file")); + EXPECT_FALSE(URIUtils::IsRemote("addons://user/")); + EXPECT_FALSE(URIUtils::IsRemote("sources://video/")); + EXPECT_FALSE(URIUtils::IsRemote("videodb://movies/titles")); + EXPECT_FALSE(URIUtils::IsRemote("musicdb://genres/")); + EXPECT_FALSE(URIUtils::IsRemote("library://video/")); + EXPECT_FALSE(URIUtils::IsRemote("androidapp://app")); + EXPECT_FALSE(URIUtils::IsRemote("plugin://plugin.video.id")); +} + +TEST_F(TestURIUtils, IsSmb) +{ + EXPECT_TRUE(URIUtils::IsSmb("smb://path/to/file")); + EXPECT_TRUE(URIUtils::IsSmb("stack://smb://path/to/file")); +} + +TEST_F(TestURIUtils, IsSpecial) +{ + EXPECT_TRUE(URIUtils::IsSpecial("special://path/to/file")); + EXPECT_TRUE(URIUtils::IsSpecial("stack://special://path/to/file")); +} + +TEST_F(TestURIUtils, IsStack) +{ + EXPECT_TRUE(URIUtils::IsStack("stack://path/to/file")); +} + +TEST_F(TestURIUtils, IsUPnP) +{ + EXPECT_TRUE(URIUtils::IsUPnP("upnp://path/to/file")); +} + +TEST_F(TestURIUtils, IsURL) +{ + EXPECT_TRUE(URIUtils::IsURL("someprotocol://path/to/file")); + EXPECT_FALSE(URIUtils::IsURL("/path/to/file")); +} + +TEST_F(TestURIUtils, IsVideoDb) +{ + EXPECT_TRUE(URIUtils::IsVideoDb("videodb://path/to/file")); +} + +TEST_F(TestURIUtils, IsZIP) +{ + EXPECT_TRUE(URIUtils::IsZIP("/path/to/zipfile.zip")); + EXPECT_TRUE(URIUtils::IsZIP("/path/to/zipfile.cbz")); + EXPECT_FALSE(URIUtils::IsZIP("/path/to/file")); + EXPECT_FALSE(URIUtils::IsZIP("zip://path/to/file")); +} + +TEST_F(TestURIUtils, IsBluray) +{ + EXPECT_TRUE(URIUtils::IsBluray("bluray://path/to/file")); +} + +TEST_F(TestURIUtils, AddSlashAtEnd) +{ + std::string ref, var; + + ref = "bluray://path/to/file/"; + var = "bluray://path/to/file/"; + URIUtils::AddSlashAtEnd(var); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, HasSlashAtEnd) +{ + EXPECT_TRUE(URIUtils::HasSlashAtEnd("bluray://path/to/file/")); + EXPECT_FALSE(URIUtils::HasSlashAtEnd("bluray://path/to/file")); +} + +TEST_F(TestURIUtils, RemoveSlashAtEnd) +{ + std::string ref, var; + + ref = "bluray://path/to/file"; + var = "bluray://path/to/file/"; + URIUtils::RemoveSlashAtEnd(var); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, CreateArchivePath) +{ + std::string ref, var; + + ref = "zip://%2fpath%2fto%2f/file"; + var = URIUtils::CreateArchivePath("zip", CURL("/path/to/"), "file").Get(); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, AddFileToFolder) +{ + std::string ref = "/path/to/file"; + std::string var = URIUtils::AddFileToFolder("/path/to", "file"); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/path/to/file/and/more"; + var = URIUtils::AddFileToFolder("/path", "to", "file", "and", "more"); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, HasParentInHostname) +{ + EXPECT_TRUE(URIUtils::HasParentInHostname(CURL("zip://"))); + EXPECT_TRUE(URIUtils::HasParentInHostname(CURL("bluray://"))); +} + +TEST_F(TestURIUtils, HasEncodedHostname) +{ + EXPECT_TRUE(URIUtils::HasEncodedHostname(CURL("zip://"))); + EXPECT_TRUE(URIUtils::HasEncodedHostname(CURL("bluray://"))); + EXPECT_TRUE(URIUtils::HasEncodedHostname(CURL("musicsearch://"))); +} + +TEST_F(TestURIUtils, HasEncodedFilename) +{ + EXPECT_TRUE(URIUtils::HasEncodedFilename(CURL("shout://"))); + EXPECT_TRUE(URIUtils::HasEncodedFilename(CURL("dav://"))); + EXPECT_TRUE(URIUtils::HasEncodedFilename(CURL("rss://"))); + EXPECT_TRUE(URIUtils::HasEncodedFilename(CURL("davs://"))); +} + +TEST_F(TestURIUtils, GetRealPath) +{ + std::string ref; + + ref = "/path/to/file/"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath(ref).c_str()); + + ref = "path/to/file"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("../path/to/file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("./path/to/file").c_str()); + + ref = "/path/to/file"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath(ref).c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("/path/to/./file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("/./path/to/./file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("/path/to/some/../file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("/../path/to/some/../file").c_str()); + + ref = "/path/to"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("/path/to/some/../file/..").c_str()); + +#ifdef TARGET_WINDOWS + ref = "\\\\path\\to\\file\\"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath(ref).c_str()); + + ref = "path\\to\\file"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("..\\path\\to\\file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath(".\\path\\to\\file").c_str()); + + ref = "\\\\path\\to\\file"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath(ref).c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("\\\\path\\to\\.\\file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("\\\\.\\path/to\\.\\file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("\\\\path\\to\\some\\..\\file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("\\\\..\\path\\to\\some\\..\\file").c_str()); + + ref = "\\\\path\\to"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("\\\\path\\to\\some\\..\\file\\..").c_str()); +#endif + + // test rar/zip paths + ref = "zip://%2fpath%2fto%2fzip/subpath/to/file"; + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath(ref).c_str()); + + // test rar/zip paths + ref = "zip://%2fpath%2fto%2fzip/subpath/to/file"; + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://%2fpath%2fto%2fzip/../subpath/to/file").c_str()); + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://%2fpath%2fto%2fzip/./subpath/to/file").c_str()); + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://%2fpath%2fto%2fzip/subpath/to/./file").c_str()); + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://%2fpath%2fto%2fzip/subpath/to/some/../file").c_str()); + + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://%2fpath%2fto%2f.%2fzip/subpath/to/file").c_str()); + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://%2fpath%2fto%2fsome%2f..%2fzip/subpath/to/file").c_str()); + + // test zip/zip path + ref ="zip://zip%3a%2f%2f%252Fpath%252Fto%252Fzip%2fpath%2fto%2fzip/subpath/to/file"; + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://zip%3a%2f%2f%252Fpath%252Fto%252Fsome%252F..%252Fzip%2fpath%2fto%2fsome%2f..%2fzip/subpath/to/some/../file").c_str()); +} + +TEST_F(TestURIUtils, UpdateUrlEncoding) +{ + std::string oldUrl = "stack://zip://%2fpath%2fto%2farchive%2fsome%2darchive%2dfile%2eCD1%2ezip/video.avi , zip://%2fpath%2fto%2farchive%2fsome%2darchive%2dfile%2eCD2%2ezip/video.avi"; + std::string newUrl = "stack://zip://%2fpath%2fto%2farchive%2fsome-archive-file.CD1.zip/video.avi , zip://%2fpath%2fto%2farchive%2fsome-archive-file.CD2.zip/video.avi"; + + EXPECT_TRUE(URIUtils::UpdateUrlEncoding(oldUrl)); + EXPECT_STRCASEEQ(newUrl.c_str(), oldUrl.c_str()); + + oldUrl = "zip://%2fpath%2fto%2farchive%2fsome%2darchive%2efile%2ezip/video.avi"; + newUrl = "zip://%2fpath%2fto%2farchive%2fsome-archive.file.zip/video.avi"; + + EXPECT_TRUE(URIUtils::UpdateUrlEncoding(oldUrl)); + EXPECT_STRCASEEQ(newUrl.c_str(), oldUrl.c_str()); + + oldUrl = "/path/to/some/long%2dnamed%2efile"; + newUrl = "/path/to/some/long%2dnamed%2efile"; + + EXPECT_FALSE(URIUtils::UpdateUrlEncoding(oldUrl)); + EXPECT_STRCASEEQ(newUrl.c_str(), oldUrl.c_str()); + + oldUrl = "/path/to/some/long-named.file"; + newUrl = "/path/to/some/long-named.file"; + + EXPECT_FALSE(URIUtils::UpdateUrlEncoding(oldUrl)); + EXPECT_STRCASEEQ(newUrl.c_str(), oldUrl.c_str()); +} diff --git a/xbmc/utils/test/TestUrlOptions.cpp b/xbmc/utils/test/TestUrlOptions.cpp new file mode 100644 index 0000000..f684fe5 --- /dev/null +++ b/xbmc/utils/test/TestUrlOptions.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/UrlOptions.h" +#include "utils/Variant.h" + +#include + +TEST(TestUrlOptions, Clear) +{ + const char *key = "foo"; + + CUrlOptions urlOptions; + urlOptions.AddOption(key, "bar"); + EXPECT_TRUE(urlOptions.HasOption(key)); + + urlOptions.Clear(); + EXPECT_FALSE(urlOptions.HasOption(key)); +} + +TEST(TestUrlOptions, AddOption) +{ + const char *keyChar = "char"; + const char *keyString = "string"; + const char *keyEmpty = "empty"; + const char *keyInt = "int"; + const char *keyFloat = "float"; + const char *keyDouble = "double"; + const char *keyBool = "bool"; + + const char *valueChar = "valueChar"; + const std::string valueString = "valueString"; + const char *valueEmpty = ""; + int valueInt = 1; + float valueFloat = 1.0f; + double valueDouble = 1.0; + bool valueBool = true; + + CVariant variantValue; + + CUrlOptions urlOptions; + urlOptions.AddOption(keyChar, valueChar); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyChar, variantValue)); + EXPECT_TRUE(variantValue.isString()); + EXPECT_STREQ(valueChar, variantValue.asString().c_str()); + } + + urlOptions.AddOption(keyString, valueString); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyString, variantValue)); + EXPECT_TRUE(variantValue.isString()); + EXPECT_STREQ(valueString.c_str(), variantValue.asString().c_str()); + } + + urlOptions.AddOption(keyEmpty, valueEmpty); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyEmpty, variantValue)); + EXPECT_TRUE(variantValue.isString()); + EXPECT_STREQ(valueEmpty, variantValue.asString().c_str()); + } + + urlOptions.AddOption(keyInt, valueInt); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyInt, variantValue)); + EXPECT_TRUE(variantValue.isInteger()); + EXPECT_EQ(valueInt, (int)variantValue.asInteger()); + } + + urlOptions.AddOption(keyFloat, valueFloat); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyFloat, variantValue)); + EXPECT_TRUE(variantValue.isDouble()); + EXPECT_EQ(valueFloat, variantValue.asFloat()); + } + + urlOptions.AddOption(keyDouble, valueDouble); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyDouble, variantValue)); + EXPECT_TRUE(variantValue.isDouble()); + EXPECT_EQ(valueDouble, variantValue.asDouble()); + } + + urlOptions.AddOption(keyBool, valueBool); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyBool, variantValue)); + EXPECT_TRUE(variantValue.isBoolean()); + EXPECT_EQ(valueBool, variantValue.asBoolean()); + } +} + +TEST(TestUrlOptions, AddOptions) +{ + std::string ref = "foo=bar&key=value"; + + CUrlOptions urlOptions(ref); + { + CVariant value; + EXPECT_TRUE(urlOptions.GetOption("foo", value)); + EXPECT_TRUE(value.isString()); + EXPECT_STREQ("bar", value.asString().c_str()); + } + { + CVariant value; + EXPECT_TRUE(urlOptions.GetOption("key", value)); + EXPECT_TRUE(value.isString()); + EXPECT_STREQ("value", value.asString().c_str()); + } + + ref = "foo=bar&key"; + urlOptions.Clear(); + urlOptions.AddOptions(ref); + { + CVariant value; + EXPECT_TRUE(urlOptions.GetOption("foo", value)); + EXPECT_TRUE(value.isString()); + EXPECT_STREQ("bar", value.asString().c_str()); + } + { + CVariant value; + EXPECT_TRUE(urlOptions.GetOption("key", value)); + EXPECT_TRUE(value.isString()); + EXPECT_TRUE(value.empty()); + } +} + +TEST(TestUrlOptions, RemoveOption) +{ + const char *key = "foo"; + + CUrlOptions urlOptions; + urlOptions.AddOption(key, "bar"); + EXPECT_TRUE(urlOptions.HasOption(key)); + + urlOptions.RemoveOption(key); + EXPECT_FALSE(urlOptions.HasOption(key)); +} + +TEST(TestUrlOptions, HasOption) +{ + const char *key = "foo"; + + CUrlOptions urlOptions; + urlOptions.AddOption(key, "bar"); + EXPECT_TRUE(urlOptions.HasOption(key)); + EXPECT_FALSE(urlOptions.HasOption("bar")); +} + +TEST(TestUrlOptions, GetOptions) +{ + const char *key1 = "foo"; + const char *key2 = "key"; + const char *value1 = "bar"; + const char *value2 = "value"; + + CUrlOptions urlOptions; + urlOptions.AddOption(key1, value1); + urlOptions.AddOption(key2, value2); + const CUrlOptions::UrlOptions &options = urlOptions.GetOptions(); + EXPECT_FALSE(options.empty()); + EXPECT_EQ(2U, options.size()); + + CUrlOptions::UrlOptions::const_iterator it1 = options.find(key1); + EXPECT_TRUE(it1 != options.end()); + CUrlOptions::UrlOptions::const_iterator it2 = options.find(key2); + EXPECT_TRUE(it2 != options.end()); + EXPECT_FALSE(options.find("wrong") != options.end()); + EXPECT_TRUE(it1->second.isString()); + EXPECT_TRUE(it2->second.isString()); + EXPECT_STREQ(value1, it1->second.asString().c_str()); + EXPECT_STREQ(value2, it2->second.asString().c_str()); +} + +TEST(TestUrlOptions, GetOptionsString) +{ + const char *ref = "foo=bar&key"; + + CUrlOptions urlOptions(ref); + std::string value = urlOptions.GetOptionsString(); + EXPECT_STREQ(ref, value.c_str()); +} diff --git a/xbmc/utils/test/TestVariant.cpp b/xbmc/utils/test/TestVariant.cpp new file mode 100644 index 0000000..3c96cd0 --- /dev/null +++ b/xbmc/utils/test/TestVariant.cpp @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/Variant.h" + +#include + +TEST(TestVariant, VariantTypeInteger) +{ + CVariant a((int)0), b((int64_t)1); + + EXPECT_TRUE(a.isInteger()); + EXPECT_EQ(CVariant::VariantTypeInteger, a.type()); + EXPECT_TRUE(b.isInteger()); + EXPECT_EQ(CVariant::VariantTypeInteger, b.type()); + + EXPECT_EQ((int64_t)1, b.asInteger()); +} + +TEST(TestVariant, VariantTypeUnsignedInteger) +{ + CVariant a((unsigned int)0), b((uint64_t)1); + + EXPECT_TRUE(a.isUnsignedInteger()); + EXPECT_EQ(CVariant::VariantTypeUnsignedInteger, a.type()); + EXPECT_TRUE(b.isUnsignedInteger()); + EXPECT_EQ(CVariant::VariantTypeUnsignedInteger, b.type()); + + EXPECT_EQ((uint64_t)1, b.asUnsignedInteger()); +} + +TEST(TestVariant, VariantTypeBoolean) +{ + CVariant a(true); + + EXPECT_TRUE(a.isBoolean()); + EXPECT_EQ(CVariant::VariantTypeBoolean, a.type()); + + EXPECT_TRUE(a.asBoolean()); +} + +TEST(TestVariant, VariantTypeString) +{ + CVariant a("VariantTypeString"); + CVariant b("VariantTypeString2", sizeof("VariantTypeString2") - 1); + std::string str("VariantTypeString3"); + CVariant c(str); + + EXPECT_TRUE(a.isString()); + EXPECT_EQ(CVariant::VariantTypeString, a.type()); + EXPECT_TRUE(b.isString()); + EXPECT_EQ(CVariant::VariantTypeString, b.type()); + EXPECT_TRUE(c.isString()); + EXPECT_EQ(CVariant::VariantTypeString, c.type()); + + EXPECT_STREQ("VariantTypeString", a.asString().c_str()); + EXPECT_STREQ("VariantTypeString2", b.asString().c_str()); + EXPECT_STREQ("VariantTypeString3", c.asString().c_str()); +} + +TEST(TestVariant, VariantTypeWideString) +{ + CVariant a(L"VariantTypeWideString"); + CVariant b(L"VariantTypeWideString2", sizeof(L"VariantTypeWideString2") - 1); + std::wstring str(L"VariantTypeWideString3"); + CVariant c(str); + + EXPECT_TRUE(a.isWideString()); + EXPECT_EQ(CVariant::VariantTypeWideString, a.type()); + EXPECT_TRUE(b.isWideString()); + EXPECT_EQ(CVariant::VariantTypeWideString, b.type()); + EXPECT_TRUE(c.isWideString()); + EXPECT_EQ(CVariant::VariantTypeWideString, c.type()); + + EXPECT_STREQ(L"VariantTypeWideString", a.asWideString().c_str()); + EXPECT_STREQ(L"VariantTypeWideString2", b.asWideString().c_str()); + EXPECT_STREQ(L"VariantTypeWideString3", c.asWideString().c_str()); +} + +TEST(TestVariant, VariantTypeDouble) +{ + CVariant a((float)0.0f), b((double)0.1f); + + EXPECT_TRUE(a.isDouble()); + EXPECT_EQ(CVariant::VariantTypeDouble, a.type()); + EXPECT_TRUE(b.isDouble()); + EXPECT_EQ(CVariant::VariantTypeDouble, b.type()); + + EXPECT_EQ((float)0.0f, a.asDouble()); + EXPECT_EQ((double)0.1f, b.asDouble()); +} + +TEST(TestVariant, VariantTypeArray) +{ + std::vector strarray; + strarray.emplace_back("string1"); + strarray.emplace_back("string2"); + strarray.emplace_back("string3"); + strarray.emplace_back("string4"); + CVariant a(strarray); + + EXPECT_TRUE(a.isArray()); + EXPECT_EQ(CVariant::VariantTypeArray, a.type()); +} + +TEST(TestVariant, VariantTypeObject) +{ + CVariant a; + a["key"] = "value"; + + EXPECT_TRUE(a.isObject()); + EXPECT_EQ(CVariant::VariantTypeObject, a.type()); +} + +TEST(TestVariant, VariantTypeNull) +{ + CVariant a; + + EXPECT_TRUE(a.isNull()); + EXPECT_EQ(CVariant::VariantTypeNull, a.type()); +} + +TEST(TestVariant, VariantFromMap) +{ + std::map strMap; + strMap["key"] = "value"; + CVariant a = strMap; + + EXPECT_TRUE(a.isObject()); + EXPECT_TRUE(a.size() == 1); + EXPECT_EQ(CVariant::VariantTypeObject, a.type()); + EXPECT_TRUE(a.isMember("key")); + EXPECT_TRUE(a["key"].isString()); + EXPECT_STREQ(a["key"].asString().c_str(), "value"); + + std::map variantMap; + variantMap["key"] = CVariant("value"); + CVariant b = variantMap; + + EXPECT_TRUE(b.isObject()); + EXPECT_TRUE(b.size() == 1); + EXPECT_EQ(CVariant::VariantTypeObject, b.type()); + EXPECT_TRUE(b.isMember("key")); + EXPECT_TRUE(b["key"].isString()); + EXPECT_STREQ(b["key"].asString().c_str(), "value"); +} + +TEST(TestVariant, operatorTest) +{ + std::vector strarray; + strarray.emplace_back("string1"); + CVariant a, b, c(strarray), d; + a["key"] = "value"; + b = a; + c[0] = "value2"; + d = c; + + EXPECT_TRUE(a.isObject()); + EXPECT_EQ(CVariant::VariantTypeObject, a.type()); + EXPECT_TRUE(b.isObject()); + EXPECT_EQ(CVariant::VariantTypeObject, b.type()); + EXPECT_TRUE(c.isArray()); + EXPECT_EQ(CVariant::VariantTypeArray, c.type()); + EXPECT_TRUE(d.isArray()); + EXPECT_EQ(CVariant::VariantTypeArray, d.type()); + + EXPECT_TRUE(a == b); + EXPECT_TRUE(c == d); + EXPECT_FALSE(a == d); + + EXPECT_STREQ("value", a["key"].asString().c_str()); + EXPECT_STREQ("value2", c[0].asString().c_str()); +} + +TEST(TestVariant, push_back) +{ + CVariant a, b("variant1"), c("variant2"), d("variant3"); + a.push_back(b); + a.push_back(c); + a.push_back(d); + + EXPECT_TRUE(a.isArray()); + EXPECT_EQ(CVariant::VariantTypeArray, a.type()); + EXPECT_STREQ("variant1", a[0].asString().c_str()); + EXPECT_STREQ("variant2", a[1].asString().c_str()); + EXPECT_STREQ("variant3", a[2].asString().c_str()); +} + +TEST(TestVariant, append) +{ + CVariant a, b("variant1"), c("variant2"), d("variant3"); + a.append(b); + a.append(c); + a.append(d); + + EXPECT_TRUE(a.isArray()); + EXPECT_EQ(CVariant::VariantTypeArray, a.type()); + EXPECT_STREQ("variant1", a[0].asString().c_str()); + EXPECT_STREQ("variant2", a[1].asString().c_str()); + EXPECT_STREQ("variant3", a[2].asString().c_str()); +} + +TEST(TestVariant, c_str) +{ + CVariant a("variant"); + + EXPECT_STREQ("variant", a.c_str()); +} + +TEST(TestVariant, swap) +{ + CVariant a((int)0), b("variant"); + + EXPECT_TRUE(a.isInteger()); + EXPECT_TRUE(b.isString()); + + a.swap(b); + EXPECT_TRUE(b.isInteger()); + EXPECT_TRUE(a.isString()); +} + +TEST(TestVariant, iterator_array) +{ + std::vector strarray; + strarray.emplace_back("string"); + strarray.emplace_back("string"); + strarray.emplace_back("string"); + strarray.emplace_back("string"); + CVariant a(strarray); + + EXPECT_TRUE(a.isArray()); + EXPECT_EQ(CVariant::VariantTypeArray, a.type()); + + for (auto it = a.begin_array(); it != a.end_array(); it++) + { + EXPECT_STREQ("string", it->c_str()); + } + + for (auto const_it = a.begin_array(); const_it != a.end_array(); const_it++) + { + EXPECT_STREQ("string", const_it->c_str()); + } +} + +TEST(TestVariant, iterator_map) +{ + CVariant a; + a["key1"] = "string"; + a["key2"] = "string"; + a["key3"] = "string"; + a["key4"] = "string"; + + EXPECT_TRUE(a.isObject()); + EXPECT_EQ(CVariant::VariantTypeObject, a.type()); + + for (auto it = a.begin_map(); it != a.end_map(); it++) + { + EXPECT_STREQ("string", it->second.c_str()); + } + + for (auto const_it = a.begin_map(); const_it != a.end_map(); const_it++) + { + EXPECT_STREQ("string", const_it->second.c_str()); + } +} + +TEST(TestVariant, size) +{ + std::vector strarray; + strarray.emplace_back("string"); + strarray.emplace_back("string"); + strarray.emplace_back("string"); + strarray.emplace_back("string"); + CVariant a(strarray); + + EXPECT_EQ((unsigned int)4, a.size()); +} + +TEST(TestVariant, empty) +{ + std::vector strarray; + CVariant a(strarray); + + EXPECT_TRUE(a.empty()); +} + +TEST(TestVariant, clear) +{ + std::vector strarray; + strarray.emplace_back("string"); + strarray.emplace_back("string"); + strarray.emplace_back("string"); + strarray.emplace_back("string"); + CVariant a(strarray); + + EXPECT_FALSE(a.empty()); + a.clear(); + EXPECT_TRUE(a.empty()); +} + +TEST(TestVariant, erase) +{ + std::vector strarray; + strarray.emplace_back("string1"); + strarray.emplace_back("string2"); + strarray.emplace_back("string3"); + strarray.emplace_back("string4"); + CVariant a, b(strarray); + a["key1"] = "string1"; + a["key2"] = "string2"; + a["key3"] = "string3"; + a["key4"] = "string4"; + + EXPECT_STREQ("string2", a["key2"].c_str()); + EXPECT_STREQ("string2", b[1].c_str()); + a.erase("key2"); + b.erase(1); + EXPECT_FALSE(a["key2"].c_str()); + EXPECT_STREQ("string3", b[1].c_str()); +} + +TEST(TestVariant, isMember) +{ + CVariant a; + a["key1"] = "string1"; + + EXPECT_TRUE(a.isMember("key1")); + EXPECT_FALSE(a.isMember("key2")); +} diff --git a/xbmc/utils/test/TestXBMCTinyXML.cpp b/xbmc/utils/test/TestXBMCTinyXML.cpp new file mode 100644 index 0000000..b3f84eb --- /dev/null +++ b/xbmc/utils/test/TestXBMCTinyXML.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "test/TestUtils.h" +#include "utils/StringUtils.h" +#include "utils/XBMCTinyXML.h" + +#include + +TEST(TestXBMCTinyXML, ParseFromString) +{ + bool retval = false; + // scraper results with unescaped & + CXBMCTinyXML doc; + std::string data("
" + "http://api.themoviedb.org/3/movie/12244" + "?api_key=57983e31fb435df4df77afb854740ea9" + "&language=en???
"); + doc.Parse(data); + TiXmlNode *root = doc.RootElement(); + if (root && root->ValueStr() == "details") + { + TiXmlElement *url = root->FirstChildElement("url"); + if (url && url->FirstChild()) + { + retval = (url->FirstChild()->ValueStr() == "http://api.themoviedb.org/3/movie/12244?api_key=57983e31fb435df4df77afb854740ea9&language=en???"); + } + } + EXPECT_TRUE(retval); +} + +TEST(TestXBMCTinyXML, ParseFromFileHandle) +{ + bool retval = false; + // scraper results with unescaped & + CXBMCTinyXML doc; + FILE *f = fopen(XBMC_REF_FILE_PATH("/xbmc/utils/test/CXBMCTinyXML-test.xml").c_str(), "r"); + ASSERT_NE(nullptr, f); + doc.LoadFile(f); + fclose(f); + TiXmlNode *root = doc.RootElement(); + if (root && root->ValueStr() == "details") + { + TiXmlElement *url = root->FirstChildElement("url"); + if (url && url->FirstChild()) + { + std::string str = url->FirstChild()->ValueStr(); + retval = (StringUtils::Trim(str) == "http://api.themoviedb.org/3/movie/12244?api_key=57983e31fb435df4df77afb854740ea9&language=en???"); + } + } + EXPECT_TRUE(retval); +} diff --git a/xbmc/utils/test/TestXMLUtils.cpp b/xbmc/utils/test/TestXMLUtils.cpp new file mode 100644 index 0000000..1a807ff --- /dev/null +++ b/xbmc/utils/test/TestXMLUtils.cpp @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "XBDateTime.h" +#include "utils/StringUtils.h" +#include "utils/XMLUtils.h" + +#include + +TEST(TestXMLUtils, GetHex) +{ + CXBMCTinyXML a; + uint32_t ref, val; + + a.Parse(std::string("0xFF")); + EXPECT_TRUE(XMLUtils::GetHex(a.RootElement(), "node", val)); + + ref = 0xFF; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, GetUInt) +{ + CXBMCTinyXML a; + uint32_t ref, val; + + a.Parse(std::string("1000")); + EXPECT_TRUE(XMLUtils::GetUInt(a.RootElement(), "node", val)); + + ref = 1000; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, GetLong) +{ + CXBMCTinyXML a; + long ref, val; + + a.Parse(std::string("1000")); + EXPECT_TRUE(XMLUtils::GetLong(a.RootElement(), "node", val)); + + ref = 1000; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, GetFloat) +{ + CXBMCTinyXML a; + float ref, val; + + a.Parse(std::string("1000.1f")); + EXPECT_TRUE(XMLUtils::GetFloat(a.RootElement(), "node", val)); + EXPECT_TRUE(XMLUtils::GetFloat(a.RootElement(), "node", val, 1000.0f, + 1000.2f)); + ref = 1000.1f; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, GetDouble) +{ + CXBMCTinyXML a; + double val; + std::string refstr, valstr; + + a.Parse(std::string("1000.1f")); + EXPECT_TRUE(XMLUtils::GetDouble(a.RootElement(), "node", val)); + + refstr = "1000.100000"; + valstr = StringUtils::Format("%f", val); + EXPECT_STREQ(refstr.c_str(), valstr.c_str()); +} + +TEST(TestXMLUtils, GetInt) +{ + CXBMCTinyXML a; + int ref, val; + + a.Parse(std::string("1000")); + EXPECT_TRUE(XMLUtils::GetInt(a.RootElement(), "node", val)); + EXPECT_TRUE(XMLUtils::GetInt(a.RootElement(), "node", val, 999, 1001)); + + ref = 1000; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, GetBoolean) +{ + CXBMCTinyXML a; + bool ref, val; + + a.Parse(std::string("true")); + EXPECT_TRUE(XMLUtils::GetBoolean(a.RootElement(), "node", val)); + + ref = true; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, GetString) +{ + CXBMCTinyXML a; + std::string ref, val; + + a.Parse(std::string("some string")); + EXPECT_TRUE(XMLUtils::GetString(a.RootElement(), "node", val)); + + ref = "some string"; + EXPECT_STREQ(ref.c_str(), val.c_str()); +} + +TEST(TestXMLUtils, GetAdditiveString) +{ + CXBMCTinyXML a, b; + std::string ref, val; + + a.Parse(std::string("\n" + " some string1\n" + " some string2\n" + " some string3\n" + " some string4\n" + " some string5\n" + "\n")); + EXPECT_TRUE(XMLUtils::GetAdditiveString(a.RootElement(), "node", ",", val)); + + ref = "some string1,some string2,some string3,some string4,some string5"; + EXPECT_STREQ(ref.c_str(), val.c_str()); + + val.clear(); + b.Parse(std::string("\n" + " some string1\n" + " some string2\n" + " some string3\n" + " some string4\n" + " some string5\n" + "\n")); + EXPECT_TRUE(XMLUtils::GetAdditiveString(b.RootElement(), "node", ",", val)); + + ref = "some string3,some string4,some string5"; + EXPECT_STREQ(ref.c_str(), val.c_str()); +} + +TEST(TestXMLUtils, GetStringArray) +{ + CXBMCTinyXML a; + std::vector strarray; + + a.Parse(std::string("\n" + " some string1\n" + " some string2\n" + " some string3\n" + " some string4\n" + " some string5\n" + "\n")); + EXPECT_TRUE(XMLUtils::GetStringArray(a.RootElement(), "node", strarray)); + + EXPECT_STREQ("some string1", strarray.at(0).c_str()); + EXPECT_STREQ("some string2", strarray.at(1).c_str()); + EXPECT_STREQ("some string3", strarray.at(2).c_str()); + EXPECT_STREQ("some string4", strarray.at(3).c_str()); + EXPECT_STREQ("some string5", strarray.at(4).c_str()); +} + +TEST(TestXMLUtils, GetPath) +{ + CXBMCTinyXML a, b; + std::string ref, val; + + a.Parse(std::string("special://xbmc/")); + EXPECT_TRUE(XMLUtils::GetPath(a.RootElement(), "node", val)); + + ref = "special://xbmc/"; + EXPECT_STREQ(ref.c_str(), val.c_str()); + + val.clear(); + b.Parse(std::string("special://xbmcbin/")); + EXPECT_TRUE(XMLUtils::GetPath(b.RootElement(), "node", val)); + + ref = "special://xbmcbin/"; + EXPECT_STREQ(ref.c_str(), val.c_str()); +} + +TEST(TestXMLUtils, GetDate) +{ + CXBMCTinyXML a; + CDateTime ref, val; + + a.Parse(std::string("2012-07-08")); + EXPECT_TRUE(XMLUtils::GetDate(a.RootElement(), "node", val)); + ref.SetDate(2012, 7, 8); + EXPECT_TRUE(ref == val); +} + +TEST(TestXMLUtils, GetDateTime) +{ + CXBMCTinyXML a; + CDateTime ref, val; + + a.Parse(std::string("2012-07-08 01:02:03")); + EXPECT_TRUE(XMLUtils::GetDateTime(a.RootElement(), "node", val)); + ref.SetDateTime(2012, 7, 8, 1, 2, 3); + EXPECT_TRUE(ref == val); +} + +TEST(TestXMLUtils, SetString) +{ + CXBMCTinyXML a; + std::string ref, val; + + a.Parse(std::string("")); + XMLUtils::SetString(a.RootElement(), "node", "some string"); + EXPECT_TRUE(XMLUtils::GetString(a.RootElement(), "node", val)); + + ref = "some string"; + EXPECT_STREQ(ref.c_str(), val.c_str()); +} + +TEST(TestXMLUtils, SetAdditiveString) +{ + CXBMCTinyXML a; + std::string ref, val; + + a.Parse(std::string("")); + XMLUtils::SetAdditiveString(a.RootElement(), "node", ",", + "some string1,some string2,some string3,some string4,some string5"); + EXPECT_TRUE(XMLUtils::GetAdditiveString(a.RootElement(), "node", ",", val)); + + ref = "some string1,some string2,some string3,some string4,some string5"; + EXPECT_STREQ(ref.c_str(), val.c_str()); +} + +TEST(TestXMLUtils, SetStringArray) +{ + CXBMCTinyXML a; + std::vector strarray; + strarray.emplace_back("some string1"); + strarray.emplace_back("some string2"); + strarray.emplace_back("some string3"); + strarray.emplace_back("some string4"); + strarray.emplace_back("some string5"); + + a.Parse(std::string("")); + XMLUtils::SetStringArray(a.RootElement(), "node", strarray); + EXPECT_TRUE(XMLUtils::GetStringArray(a.RootElement(), "node", strarray)); + + EXPECT_STREQ("some string1", strarray.at(0).c_str()); + EXPECT_STREQ("some string2", strarray.at(1).c_str()); + EXPECT_STREQ("some string3", strarray.at(2).c_str()); + EXPECT_STREQ("some string4", strarray.at(3).c_str()); + EXPECT_STREQ("some string5", strarray.at(4).c_str()); +} + +TEST(TestXMLUtils, SetInt) +{ + CXBMCTinyXML a; + int ref, val; + + a.Parse(std::string("")); + XMLUtils::SetInt(a.RootElement(), "node", 1000); + EXPECT_TRUE(XMLUtils::GetInt(a.RootElement(), "node", val)); + + ref = 1000; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, SetFloat) +{ + CXBMCTinyXML a; + float ref, val; + + a.Parse(std::string("")); + XMLUtils::SetFloat(a.RootElement(), "node", 1000.1f); + EXPECT_TRUE(XMLUtils::GetFloat(a.RootElement(), "node", val)); + + ref = 1000.1f; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, SetBoolean) +{ + CXBMCTinyXML a; + bool ref, val; + + a.Parse(std::string("")); + XMLUtils::SetBoolean(a.RootElement(), "node", true); + EXPECT_TRUE(XMLUtils::GetBoolean(a.RootElement(), "node", val)); + + ref = true; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, SetHex) +{ + CXBMCTinyXML a; + uint32_t ref, val; + + a.Parse(std::string("")); + XMLUtils::SetHex(a.RootElement(), "node", 0xFF); + EXPECT_TRUE(XMLUtils::GetHex(a.RootElement(), "node", val)); + + ref = 0xFF; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, SetPath) +{ + CXBMCTinyXML a; + std::string ref, val; + + a.Parse(std::string("")); + XMLUtils::SetPath(a.RootElement(), "node", "special://xbmc/"); + EXPECT_TRUE(XMLUtils::GetPath(a.RootElement(), "node", val)); + + ref = "special://xbmc/"; + EXPECT_STREQ(ref.c_str(), val.c_str()); +} + +TEST(TestXMLUtils, SetLong) +{ + CXBMCTinyXML a; + long ref, val; + + a.Parse(std::string("")); + XMLUtils::SetLong(a.RootElement(), "node", 1000); + EXPECT_TRUE(XMLUtils::GetLong(a.RootElement(), "node", val)); + + ref = 1000; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, SetDate) +{ + CXBMCTinyXML a; + CDateTime ref, val; + + a.Parse(std::string("")); + ref.SetDate(2012, 7, 8); + XMLUtils::SetDate(a.RootElement(), "node", ref); + EXPECT_TRUE(XMLUtils::GetDate(a.RootElement(), "node", val)); + EXPECT_TRUE(ref == val); +} + +TEST(TestXMLUtils, SetDateTime) +{ + CXBMCTinyXML a; + CDateTime ref, val; + + a.Parse(std::string("")); + ref.SetDateTime(2012, 7, 8, 1, 2, 3); + XMLUtils::SetDateTime(a.RootElement(), "node", ref); + EXPECT_TRUE(XMLUtils::GetDateTime(a.RootElement(), "node", val)); + EXPECT_TRUE(ref == val); +} diff --git a/xbmc/utils/test/Testlog.cpp b/xbmc/utils/test/Testlog.cpp new file mode 100644 index 0000000..7405c02 --- /dev/null +++ b/xbmc/utils/test/Testlog.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "CompileInfo.h" +#include "ServiceBroker.h" +#include "filesystem/File.h" +#include "filesystem/SpecialProtocol.h" +#include "test/TestUtils.h" +#include "utils/RegExp.h" +#include "utils/StringUtils.h" +#include "utils/log.h" + +#include + +#include + +class Testlog : public testing::Test +{ +protected: + Testlog() = default; + ~Testlog() override { CServiceBroker::GetLogging().Uninitialize(); } +}; + +TEST_F(Testlog, Log) +{ + std::string logfile, logstring; + char buf[100]; + ssize_t bytesread; + XFILE::CFile file; + CRegExp regex; + + std::string appName = CCompileInfo::GetAppName(); + StringUtils::ToLower(appName); + logfile = CSpecialProtocol::TranslatePath("special://temp/") + appName + ".log"; + CServiceBroker::GetLogging().Initialize( + CSpecialProtocol::TranslatePath("special://temp/").c_str()); + EXPECT_TRUE(XFILE::CFile::Exists(logfile)); + + CLog::Log(LOGDEBUG, "debug log message"); + CLog::Log(LOGINFO, "info log message"); + CLog::Log(LOGNOTICE, "notice log message"); + CLog::Log(LOGWARNING, "warning log message"); + CLog::Log(LOGERROR, "error log message"); + CLog::Log(LOGSEVERE, "severe log message"); + CLog::Log(LOGFATAL, "fatal log message"); + CLog::Log(LOGNONE, "none type log message"); + CServiceBroker::GetLogging().Uninitialize(); + + EXPECT_TRUE(file.Open(logfile)); + while ((bytesread = file.Read(buf, sizeof(buf) - 1)) > 0) + { + buf[bytesread] = '\0'; + logstring.append(buf); + } + file.Close(); + EXPECT_FALSE(logstring.empty()); + + EXPECT_STREQ("\xEF\xBB\xBF", logstring.substr(0, 3).c_str()); + + EXPECT_TRUE(regex.RegComp(".*DEBUG : debug log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + EXPECT_TRUE(regex.RegComp(".*INFO : info log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + EXPECT_TRUE(regex.RegComp(".*INFO : notice log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + EXPECT_TRUE(regex.RegComp(".*WARNING : warning log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + EXPECT_TRUE(regex.RegComp(".*ERROR : error log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + EXPECT_TRUE(regex.RegComp(".*FATAL : severe log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + EXPECT_TRUE(regex.RegComp(".*FATAL : fatal log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + EXPECT_TRUE(regex.RegComp(".*OFF : none type log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + + EXPECT_TRUE(XFILE::CFile::Delete(logfile)); +} + +TEST_F(Testlog, SetLogLevel) +{ + std::string logfile; + + std::string appName = CCompileInfo::GetAppName(); + StringUtils::ToLower(appName); + logfile = CSpecialProtocol::TranslatePath("special://temp/") + appName + ".log"; + CServiceBroker::GetLogging().Initialize( + CSpecialProtocol::TranslatePath("special://temp/").c_str()); + EXPECT_TRUE(XFILE::CFile::Exists(logfile)); + + EXPECT_EQ(LOG_LEVEL_DEBUG, CServiceBroker::GetLogging().GetLogLevel()); + CServiceBroker::GetLogging().SetLogLevel(LOG_LEVEL_MAX); + EXPECT_EQ(LOG_LEVEL_MAX, CServiceBroker::GetLogging().GetLogLevel()); + + CServiceBroker::GetLogging().Uninitialize(); + EXPECT_TRUE(XFILE::CFile::Delete(logfile)); +} diff --git a/xbmc/utils/test/Testrfft.cpp b/xbmc/utils/test/Testrfft.cpp new file mode 100644 index 0000000..a6c859d --- /dev/null +++ b/xbmc/utils/test/Testrfft.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/rfft.h" + +#include + +#if defined(TARGET_WINDOWS) && !defined(_USE_MATH_DEFINES) +#define _USE_MATH_DEFINES +#endif + +#include + + +TEST(TestRFFT, SimpleSignal) +{ + const int size = 32; + const int freq1 = 5; + const int freq2[] = {1,7}; + std::vector input(2*size); + std::vector output(size); + for (size_t i=0;i