[videodb] Remove nested transaction when saving state after stopping PVR playback
[xbmc.git] / xbmc / filesystem / FileDirectoryFactory.cpp
blob45852d2707fb76f6a3f79eabe560eaea935253c4
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "FileDirectoryFactory.h"
11 #include "music/MusicFileItemClassify.h"
13 #if defined(HAS_ISO9660PP)
14 #include "ISO9660Directory.h"
15 #endif
16 #if defined(HAS_UDFREAD)
17 #include "UDFDirectory.h"
18 #endif
19 #include "RSSDirectory.h"
20 #include "UDFDirectory.h"
21 #include "utils/URIUtils.h"
22 #if defined(TARGET_ANDROID)
23 #include "platform/android/filesystem/APKDirectory.h"
24 #endif
25 #include "AudioBookFileDirectory.h"
26 #include "Directory.h"
27 #include "FileItem.h"
28 #include "PlaylistFileDirectory.h"
29 #include "ServiceBroker.h"
30 #include "SmartPlaylistDirectory.h"
31 #include "URL.h"
32 #include "XbtDirectory.h"
33 #include "ZipDirectory.h"
34 #include "addons/AudioDecoder.h"
35 #include "addons/ExtsMimeSupportList.h"
36 #include "addons/VFSEntry.h"
37 #include "addons/addoninfo/AddonInfo.h"
38 #include "playlists/PlayListFactory.h"
39 #include "playlists/SmartPlayList.h"
40 #include "utils/StringUtils.h"
41 #include "utils/log.h"
43 using namespace ADDON;
44 using namespace KODI;
45 using namespace KODI::ADDONS;
46 using namespace XFILE;
47 using namespace PLAYLIST;
49 CFileDirectoryFactory::CFileDirectoryFactory(void) = default;
51 CFileDirectoryFactory::~CFileDirectoryFactory(void) = default;
53 // return NULL + set pItem->m_bIsFolder to remove it completely from list.
54 IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem, const std::string& strMask)
56 if (url.IsProtocol("stack")) // disqualify stack as we need to work with each of the parts instead
57 return NULL;
59 /**
60 * Check available binary addons which can contain files with underlaid
61 * folders / files.
62 * Currently in vfs and audiodecoder addons.
64 * @note The file extensions are absolutely necessary for these in order to
65 * identify the associated add-on.
67 /**@{*/
69 // Get file extensions to find addon related to it.
70 std::string strExtension = URIUtils::GetExtension(url);
71 StringUtils::ToLower(strExtension);
73 if (!strExtension.empty() && CServiceBroker::IsAddonInterfaceUp())
75 /*!
76 * Scan here about audiodecoder addons.
78 * @note: Do not check audio decoder files that are already open, they cannot
79 * contain any further sub-folders.
81 if (!StringUtils::EndsWith(strExtension, KODI_ADDON_AUDIODECODER_TRACK_EXT))
83 auto addonInfos = CServiceBroker::GetExtsMimeSupportList().GetExtensionSupportedAddonInfos(
84 strExtension, CExtsMimeSupportList::FilterSelect::hasTracks);
85 for (const auto& addonInfo : addonInfos)
87 std::unique_ptr<CAudioDecoder> result = std::make_unique<CAudioDecoder>(addonInfo.second);
88 if (!result->CreateDecoder() || !result->ContainsFiles(url))
90 CLog::Log(LOGINFO,
91 "CFileDirectoryFactory::{}: Addon '{}' support extension '{}' but creation "
92 "failed (seems not supported), trying other addons and Kodi",
93 __func__, addonInfo.second->ID(), strExtension);
94 continue;
96 return result.release();
101 * Scan here about VFS addons.
103 for (const auto& vfsAddon : CServiceBroker::GetVFSAddonCache().GetAddonInstances())
105 if (vfsAddon->HasFileDirectories())
107 auto exts = StringUtils::Split(vfsAddon->GetExtensions(), "|");
108 if (std::find(exts.begin(), exts.end(), strExtension) != exts.end())
110 CVFSEntryIFileDirectoryWrapper* wrap = new CVFSEntryIFileDirectoryWrapper(vfsAddon);
111 if (wrap->ContainsFiles(url))
113 if (wrap->m_items.Size() == 1)
115 // one STORED file - collapse it down
116 *pItem = *wrap->m_items[0];
118 else
120 // compressed or more than one file -> create a dir
121 pItem->SetPath(wrap->m_items.GetPath());
124 // Check for folder, if yes return also wrap.
125 // Needed to fix for e.g. RAR files with only one file inside
126 pItem->m_bIsFolder = URIUtils::HasSlashAtEnd(pItem->GetPath());
127 if (pItem->m_bIsFolder)
128 return wrap;
130 else
132 pItem->m_bIsFolder = true;
135 delete wrap;
136 return nullptr;
141 /**@}*/
143 if (pItem->IsRSS())
144 return new CRSSDirectory();
147 if (pItem->IsDiscImage())
149 #if defined(HAS_ISO9660PP)
150 CISO9660Directory* iso = new CISO9660Directory();
151 if (iso->Exists(pItem->GetURL()))
152 return iso;
154 delete iso;
155 #endif
157 #if defined(HAS_UDFREAD)
158 return new CUDFDirectory();
159 #endif
161 return nullptr;
164 #if defined(TARGET_ANDROID)
165 if (url.IsFileType("apk"))
167 CURL zipURL = URIUtils::CreateArchivePath("apk", url);
169 CFileItemList items;
170 CDirectory::GetDirectory(zipURL, items, strMask, DIR_FLAG_DEFAULTS);
171 if (items.Size() == 0) // no files
172 pItem->m_bIsFolder = true;
173 else if (items.Size() == 1 && items[0]->m_idepth == 0 && !items[0]->m_bIsFolder)
175 // one STORED file - collapse it down
176 *pItem = *items[0];
178 else
179 { // compressed or more than one file -> create a apk dir
180 pItem->SetURL(zipURL);
181 return new CAPKDirectory;
183 return NULL;
185 #endif
186 if (url.IsFileType("zip"))
188 CURL zipURL = URIUtils::CreateArchivePath("zip", url);
190 CFileItemList items;
191 CDirectory::GetDirectory(zipURL, items, strMask, DIR_FLAG_DEFAULTS);
192 if (items.Size() == 0) // no files
193 pItem->m_bIsFolder = true;
194 else if (items.Size() == 1 && items[0]->m_idepth == 0 && !items[0]->m_bIsFolder)
196 // one STORED file - collapse it down
197 *pItem = *items[0];
199 else
200 { // compressed or more than one file -> create a zip dir
201 pItem->SetURL(zipURL);
202 return new CZipDirectory;
204 return NULL;
206 if (url.IsFileType("xbt"))
208 CURL xbtUrl = URIUtils::CreateArchivePath("xbt", url);
209 pItem->SetURL(xbtUrl);
211 return new CXbtDirectory();
213 if (url.IsFileType("xsp"))
214 { // XBMC Smart playlist - just XML renamed to XSP
215 // read the name of the playlist in
216 CSmartPlaylist playlist;
217 if (playlist.OpenAndReadName(url))
219 pItem->SetLabel(playlist.GetName());
220 pItem->SetLabelPreformatted(true);
222 IFileDirectory* pDir=new CSmartPlaylistDirectory;
223 return pDir; // treat as directory
225 if (CPlayListFactory::IsPlaylist(url))
226 { // Playlist file
227 // currently we only return the directory if it contains
228 // more than one file. Reason is that .pls and .m3u may be used
229 // for links to http streams etc.
230 IFileDirectory *pDir = new CPlaylistFileDirectory();
231 CFileItemList items;
232 if (pDir->GetDirectory(url, items))
234 if (items.Size() > 1)
235 return pDir;
237 delete pDir;
238 return NULL;
241 if (MUSIC::IsAudioBook(*pItem))
243 if (!pItem->HasMusicInfoTag() || pItem->GetEndOffset() <= 0)
245 auto pDir = std::make_unique<CAudioBookFileDirectory>();
246 if (pDir->ContainsFiles(url))
247 return pDir.release();
249 return NULL;
251 return NULL;