summaryrefslogtreecommitdiffstats
path: root/xbmc/filesystem/FileDirectoryFactory.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--xbmc/filesystem/FileDirectoryFactory.cpp250
1 files changed, 250 insertions, 0 deletions
diff --git a/xbmc/filesystem/FileDirectoryFactory.cpp b/xbmc/filesystem/FileDirectoryFactory.cpp
new file mode 100644
index 0000000..a4e0f3f
--- /dev/null
+++ b/xbmc/filesystem/FileDirectoryFactory.cpp
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * 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 "FileDirectoryFactory.h"
+
+#if defined(HAS_ISO9660PP)
+#include "ISO9660Directory.h"
+#endif
+#if defined(HAS_UDFREAD)
+#include "UDFDirectory.h"
+#endif
+#include "RSSDirectory.h"
+#include "UDFDirectory.h"
+#include "utils/URIUtils.h"
+#if defined(TARGET_ANDROID)
+#include "platform/android/filesystem/APKDirectory.h"
+#endif
+#include "AudioBookFileDirectory.h"
+#include "Directory.h"
+#include "FileItem.h"
+#include "PlaylistFileDirectory.h"
+#include "ServiceBroker.h"
+#include "SmartPlaylistDirectory.h"
+#include "URL.h"
+#include "XbtDirectory.h"
+#include "ZipDirectory.h"
+#include "addons/AudioDecoder.h"
+#include "addons/ExtsMimeSupportList.h"
+#include "addons/VFSEntry.h"
+#include "addons/addoninfo/AddonInfo.h"
+#include "playlists/PlayListFactory.h"
+#include "playlists/SmartPlayList.h"
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+using namespace ADDON;
+using namespace KODI::ADDONS;
+using namespace XFILE;
+using namespace PLAYLIST;
+
+CFileDirectoryFactory::CFileDirectoryFactory(void) = default;
+
+CFileDirectoryFactory::~CFileDirectoryFactory(void) = default;
+
+// return NULL + set pItem->m_bIsFolder to remove it completely from list.
+IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem, const std::string& strMask)
+{
+ if (url.IsProtocol("stack")) // disqualify stack as we need to work with each of the parts instead
+ return NULL;
+
+ /**
+ * Check available binary addons which can contain files with underlaid
+ * folders / files.
+ * Currently in vfs and audiodecoder addons.
+ *
+ * @note The file extensions are absolutely necessary for these in order to
+ * identify the associated add-on.
+ */
+ /**@{*/
+
+ // Get file extensions to find addon related to it.
+ std::string strExtension = URIUtils::GetExtension(url);
+ StringUtils::ToLower(strExtension);
+
+ if (!strExtension.empty() && CServiceBroker::IsAddonInterfaceUp())
+ {
+ /*!
+ * Scan here about audiodecoder addons.
+ *
+ * @note: Do not check audio decoder files that are already open, they cannot
+ * contain any further sub-folders.
+ */
+ if (!StringUtils::EndsWith(strExtension, KODI_ADDON_AUDIODECODER_TRACK_EXT))
+ {
+ auto addonInfos = CServiceBroker::GetExtsMimeSupportList().GetExtensionSupportedAddonInfos(
+ strExtension, CExtsMimeSupportList::FilterSelect::hasTracks);
+ for (const auto& addonInfo : addonInfos)
+ {
+ std::unique_ptr<CAudioDecoder> result = std::make_unique<CAudioDecoder>(addonInfo.second);
+ if (!result->CreateDecoder() || !result->ContainsFiles(url))
+ {
+ CLog::Log(LOGINFO,
+ "CFileDirectoryFactory::{}: Addon '{}' support extension '{}' but creation "
+ "failed (seems not supported), trying other addons and Kodi",
+ __func__, addonInfo.second->ID(), strExtension);
+ continue;
+ }
+ return result.release();
+ }
+ }
+
+ /*!
+ * Scan here about VFS addons.
+ */
+ for (const auto& vfsAddon : CServiceBroker::GetVFSAddonCache().GetAddonInstances())
+ {
+ if (vfsAddon->HasFileDirectories())
+ {
+ auto exts = StringUtils::Split(vfsAddon->GetExtensions(), "|");
+ if (std::find(exts.begin(), exts.end(), strExtension) != exts.end())
+ {
+ CVFSEntryIFileDirectoryWrapper* wrap = new CVFSEntryIFileDirectoryWrapper(vfsAddon);
+ if (wrap->ContainsFiles(url))
+ {
+ if (wrap->m_items.Size() == 1)
+ {
+ // one STORED file - collapse it down
+ *pItem = *wrap->m_items[0];
+ }
+ else
+ {
+ // compressed or more than one file -> create a dir
+ pItem->SetPath(wrap->m_items.GetPath());
+ }
+
+ // Check for folder, if yes return also wrap.
+ // Needed to fix for e.g. RAR files with only one file inside
+ pItem->m_bIsFolder = URIUtils::HasSlashAtEnd(pItem->GetPath());
+ if (pItem->m_bIsFolder)
+ return wrap;
+ }
+ else
+ {
+ pItem->m_bIsFolder = true;
+ }
+
+ delete wrap;
+ return nullptr;
+ }
+ }
+ }
+ }
+ /**@}*/
+
+ if (pItem->IsRSS())
+ return new CRSSDirectory();
+
+
+ if (pItem->IsDiscImage())
+ {
+#if defined(HAS_ISO9660PP)
+ CISO9660Directory* iso = new CISO9660Directory();
+ if (iso->Exists(pItem->GetURL()))
+ return iso;
+
+ delete iso;
+#endif
+
+#if defined(HAS_UDFREAD)
+ return new CUDFDirectory();
+#endif
+
+ return nullptr;
+ }
+
+#if defined(TARGET_ANDROID)
+ if (url.IsFileType("apk"))
+ {
+ CURL zipURL = URIUtils::CreateArchivePath("apk", url);
+
+ CFileItemList items;
+ CDirectory::GetDirectory(zipURL, items, strMask, DIR_FLAG_DEFAULTS);
+ if (items.Size() == 0) // no files
+ pItem->m_bIsFolder = true;
+ else if (items.Size() == 1 && items[0]->m_idepth == 0 && !items[0]->m_bIsFolder)
+ {
+ // one STORED file - collapse it down
+ *pItem = *items[0];
+ }
+ else
+ { // compressed or more than one file -> create a apk dir
+ pItem->SetURL(zipURL);
+ return new CAPKDirectory;
+ }
+ return NULL;
+ }
+#endif
+ if (url.IsFileType("zip"))
+ {
+ CURL zipURL = URIUtils::CreateArchivePath("zip", url);
+
+ CFileItemList items;
+ CDirectory::GetDirectory(zipURL, items, strMask, DIR_FLAG_DEFAULTS);
+ if (items.Size() == 0) // no files
+ pItem->m_bIsFolder = true;
+ else if (items.Size() == 1 && items[0]->m_idepth == 0 && !items[0]->m_bIsFolder)
+ {
+ // one STORED file - collapse it down
+ *pItem = *items[0];
+ }
+ else
+ { // compressed or more than one file -> create a zip dir
+ pItem->SetURL(zipURL);
+ return new CZipDirectory;
+ }
+ return NULL;
+ }
+ if (url.IsFileType("xbt"))
+ {
+ CURL xbtUrl = URIUtils::CreateArchivePath("xbt", url);
+ pItem->SetURL(xbtUrl);
+
+ return new CXbtDirectory();
+ }
+ if (url.IsFileType("xsp"))
+ { // XBMC Smart playlist - just XML renamed to XSP
+ // read the name of the playlist in
+ CSmartPlaylist playlist;
+ if (playlist.OpenAndReadName(url))
+ {
+ pItem->SetLabel(playlist.GetName());
+ pItem->SetLabelPreformatted(true);
+ }
+ IFileDirectory* pDir=new CSmartPlaylistDirectory;
+ return pDir; // treat as directory
+ }
+ if (CPlayListFactory::IsPlaylist(url))
+ { // Playlist file
+ // currently we only return the directory if it contains
+ // more than one file. Reason is that .pls and .m3u may be used
+ // for links to http streams etc.
+ IFileDirectory *pDir = new CPlaylistFileDirectory();
+ CFileItemList items;
+ if (pDir->GetDirectory(url, items))
+ {
+ if (items.Size() > 1)
+ return pDir;
+ }
+ delete pDir;
+ return NULL;
+ }
+
+ if (pItem->IsAudioBook())
+ {
+ if (!pItem->HasMusicInfoTag() || pItem->GetEndOffset() <= 0)
+ {
+ std::unique_ptr<CAudioBookFileDirectory> pDir(new CAudioBookFileDirectory);
+ if (pDir->ContainsFiles(url))
+ return pDir.release();
+ }
+ return NULL;
+ }
+ return NULL;
+}
+