aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Rector <rmrector@gmail.com>2024-04-07 15:45:38 -0600
committerRyan Rector <rmrector@gmail.com>2024-05-28 20:29:56 -0600
commitdf84be09bef1c0e3c2c096c5e76957ec97d78b8e (patch)
treeaef0e0c4d66a2022da8e041c78d3b35b42a5446d
parente8906a9cf6c173e00ac8486cf455289bdfbd4a00 (diff)
add ImageFileURL for explicit image URL handling
-rw-r--r--cmake/treedata/common/tests.txt1
-rw-r--r--xbmc/imagefiles/CMakeLists.txt6
-rw-r--r--xbmc/imagefiles/ImageFileURL.cpp107
-rw-r--r--xbmc/imagefiles/ImageFileURL.h90
-rw-r--r--xbmc/imagefiles/test/CMakeLists.txt3
-rw-r--r--xbmc/imagefiles/test/TestImageFileURL.cpp45
6 files changed, 250 insertions, 2 deletions
diff --git a/cmake/treedata/common/tests.txt b/cmake/treedata/common/tests.txt
index 8d8d1107f2..3141b916cd 100644
--- a/cmake/treedata/common/tests.txt
+++ b/cmake/treedata/common/tests.txt
@@ -6,6 +6,7 @@ xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/test test/videoshaders
xbmc/filesystem/test test/filesystem
xbmc/games/addons/input/test test/games/addons/input
xbmc/games/controllers/input/test test/games/controllers/input
+xbmc/imagefiles/test test/imagefiles
xbmc/input/keyboard/test test/input/keyboard
xbmc/interfaces/python/test test/python
xbmc/music/test test/music
diff --git a/xbmc/imagefiles/CMakeLists.txt b/xbmc/imagefiles/CMakeLists.txt
index 48f00441a5..66d1b45aa8 100644
--- a/xbmc/imagefiles/CMakeLists.txt
+++ b/xbmc/imagefiles/CMakeLists.txt
@@ -1,6 +1,8 @@
-set(SOURCES SpecialImageLoaderFactory.cpp)
+set(SOURCES ImageFileURL.cpp
+ SpecialImageLoaderFactory.cpp)
-set(HEADERS SpecialImageFileLoader.h
+set(HEADERS ImageFileURL.h
+ SpecialImageFileLoader.h
SpecialImageLoaderFactory.h)
core_add_library(imagefiles)
diff --git a/xbmc/imagefiles/ImageFileURL.cpp b/xbmc/imagefiles/ImageFileURL.cpp
new file mode 100644
index 0000000000..d2d1cddfce
--- /dev/null
+++ b/xbmc/imagefiles/ImageFileURL.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2024 Team Kodi
+ * 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 "ImageFileURL.h"
+
+#include "URL.h"
+#include "utils/URIUtils.h"
+
+#include <charconv>
+
+namespace IMAGE_FILES
+{
+
+CImageFileURL::CImageFileURL(const std::string& imageFileURL)
+{
+ if (!URIUtils::IsProtocol(imageFileURL, "image"))
+ {
+ m_filePath = imageFileURL;
+ return;
+ }
+
+ CURL url{imageFileURL};
+ m_filePath = url.GetHostName();
+ m_specialType = url.GetUserName();
+
+ url.GetOptions(m_options);
+
+ auto option = m_options.find("flipped");
+ if (option != m_options.end())
+ {
+ flipped = true;
+ m_options.erase(option);
+ }
+}
+
+CImageFileURL::CImageFileURL()
+{
+}
+
+CImageFileURL CImageFileURL::FromFile(const std::string& filePath, std::string specialType)
+{
+ if (URIUtils::IsProtocol(filePath, "image"))
+ {
+ // this function should not be called with an image file URL
+ return CImageFileURL(filePath);
+ }
+
+ CImageFileURL item;
+ item.m_filePath = filePath;
+ item.m_specialType = std::move(specialType);
+
+ return item;
+}
+
+void CImageFileURL::AddOption(std::string key, std::string value)
+{
+ m_options[std::move(key)] = std::move(value);
+}
+
+std::string CImageFileURL::GetOption(const std::string& key) const
+{
+ auto value = m_options.find(key);
+ if (value == m_options.end())
+ {
+ return {};
+ }
+ return value->second;
+}
+
+std::string CImageFileURL::ToString() const
+{
+ CURL url;
+ url.SetProtocol("image");
+ url.SetUserName(m_specialType);
+ url.SetHostName(m_filePath);
+ if (flipped)
+ url.SetOption("flipped", "");
+ for (const auto& option : m_options)
+ url.SetOption(option.first, option.second);
+
+ return url.Get();
+}
+
+std::string CImageFileURL::ToCacheKey() const
+{
+ if (!flipped && m_specialType.empty() && m_options.empty())
+ return m_filePath;
+
+ return ToString();
+}
+
+std::string URLFromFile(const std::string& filePath, std::string specialType)
+{
+ return CImageFileURL::FromFile(filePath, std::move(specialType)).ToString();
+}
+
+std::string ToCacheKey(const std::string& imageFileURL)
+{
+ return CImageFileURL(imageFileURL).ToCacheKey();
+}
+
+} // namespace IMAGE_FILES
diff --git a/xbmc/imagefiles/ImageFileURL.h b/xbmc/imagefiles/ImageFileURL.h
new file mode 100644
index 0000000000..e55d5b1d42
--- /dev/null
+++ b/xbmc/imagefiles/ImageFileURL.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 Team Kodi
+ * This file 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 <map>
+#include <string>
+
+class CURL;
+
+namespace IMAGE_FILES
+{
+/*!
+ * \brief A mostly-typed representation of a URL to any image, whether a simple path to an image
+ * file, embedded in another file, or generated in some way.
+ *
+ * A URL string is good to pass between most classes, store, and transmit, but use this if you need
+ * to _create_ or _modify_ a special image path, or are working on the details of such image files.
+ *
+ * URL string format is `image://[type@]<url_encoded_path>?options`
+*/
+class CImageFileURL
+{
+public:
+ /*!
+ * \brief Create an ImageFileURL from a string representation.
+ */
+ CImageFileURL(const std::string& imageFileURL);
+
+ /*!
+ * \brief Create an ImageFileURL pointing to a specific file.
+ *
+ * Provide a 'specialType' parameter to specify a special image loader.
+ *
+ * \param specialType set a special image type - an implementation of \ref ISpecialImageFileLoader
+ */
+ static CImageFileURL FromFile(const std::string& filePath, std::string specialType = "");
+
+ void AddOption(std::string key, std::string value);
+
+ std::string GetOption(const std::string& key) const;
+
+ /*!
+ * \brief Build a complete string representation of this ImageFileURL.
+ */
+ std::string ToString() const;
+
+ /*!
+ * \brief Build a cache key for this ImageFileURL.
+ *
+ * Return base filePath if not special and multiple options are in a stable order,
+ * otherwise return a complete string representation.
+ */
+ std::string ToCacheKey() const;
+
+ std::string GetTargetFile() const { return m_filePath; }
+
+ bool IsSpecialImage() const { return !m_specialType.empty(); }
+ std::string GetSpecialType() const { return m_specialType; }
+
+ bool flipped{false};
+
+private:
+ CImageFileURL();
+ std::string m_filePath;
+ std::string m_specialType;
+
+ std::map<std::string, std::string> m_options{};
+};
+
+/*!
+ * \brief Build an ImageFileURL string from a file path.
+ *
+ * Provide a 'specialType' parameter to specify a special image loader.
+ *
+ * \param specialType set a special image type - an implementation of \ref ISpecialImageFileLoader
+*/
+std::string URLFromFile(const std::string& filePath, std::string specialType = "");
+
+/*!
+ * \brief Build a cache key for an ImageFileURL string.
+*/
+std::string ToCacheKey(const std::string& imageFileURL);
+
+} // namespace IMAGE_FILES
diff --git a/xbmc/imagefiles/test/CMakeLists.txt b/xbmc/imagefiles/test/CMakeLists.txt
new file mode 100644
index 0000000000..5bd4bbbfb2
--- /dev/null
+++ b/xbmc/imagefiles/test/CMakeLists.txt
@@ -0,0 +1,3 @@
+set(SOURCES TestImageFileURL.cpp)
+
+core_add_test_library(imagefiles_test)
diff --git a/xbmc/imagefiles/test/TestImageFileURL.cpp b/xbmc/imagefiles/test/TestImageFileURL.cpp
new file mode 100644
index 0000000000..65ca769784
--- /dev/null
+++ b/xbmc/imagefiles/test/TestImageFileURL.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 Team Kodi
+ * 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 "URL.h"
+#include "imagefiles/ImageFileURL.h"
+
+#include <gtest/gtest.h>
+
+using ::testing::ValuesIn;
+
+namespace
+{
+typedef struct
+{
+ const char* in;
+ const char* type;
+ const char* out;
+} TestFiles;
+
+const TestFiles test_files[] = {
+ {"/path/to/image/file.jpg", "", "image://%2fpath%2fto%2fimage%2ffile.jpg/"},
+ {"/path/to/video/file.mkv", "video", "image://video@%2fpath%2fto%2fvideo%2ffile.mkv/"},
+ {"/path/to/music/file.mp3", "music", "image://music@%2fpath%2fto%2fmusic%2ffile.mp3/"},
+ {"image://%2fpath%2fto%2fimage%2ffile.jpg/", "", "image://%2fpath%2fto%2fimage%2ffile.jpg/"}};
+
+class TestImageFileURL : public ::testing::TestWithParam<TestFiles>
+{
+};
+
+TEST_P(TestImageFileURL, URLFromFile)
+{
+ const TestFiles& testFiles(GetParam());
+
+ std::string expected = testFiles.out;
+ std::string out = IMAGE_FILES::URLFromFile(testFiles.in, testFiles.type);
+ EXPECT_EQ(expected, out);
+}
+
+INSTANTIATE_TEST_SUITE_P(SampleFiles, TestImageFileURL, ValuesIn(test_files));
+} // namespace