linuxport: Merging in the fruits of my labors (Python VFS)
[xbmc:xbmc-antiquated.git] / xbmc / FileSystem / FactoryFileDirectory.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22
23 #include "stdafx.h"
24 #include "Util.h"
25 #include "FactoryFileDirectory.h"
26 #ifdef HAS_FILESYSTEM
27 #include "OGGFileDirectory.h"
28 #include "NSFFileDirectory.h"
29 #include "SIDFileDirectory.h"
30 #include "ASAPFileDirectory.h"
31 #include "cores/paplayer/ASAPCodec.h"
32 #endif
33 #include "RarDirectory.h"
34 #include "ZipDirectory.h"
35 #include "SmartPlaylistDirectory.h"
36 #include "SmartPlaylist.h"
37 #include "PlaylistFileDirectory.h"
38 #include "PlayListFactory.h"
39 #include "GUIViewState.h"
40 #include "FileSystem/Directory.h"
41 #include "FileSystem/File.h"
42 #include "FileSystem/RarManager.h"
43 #include "FileSystem/ZipManager.h"
44 #include "Settings.h"
45 #include "FileItem.h"
46
47 using namespace XFILE;
48 using namespace DIRECTORY;
49 using namespace PLAYLIST;
50
51 CFactoryFileDirectory::CFactoryFileDirectory(void)
52 {}
53
54 CFactoryFileDirectory::~CFactoryFileDirectory(void)
55 {}
56
57 // return NULL + set pItem->m_bIsFolder to remove it completely from list.
58 IFileDirectory* CFactoryFileDirectory::Create(const CStdString& strPath, CFileItem* pItem, const CStdString& strMask)
59 {
60   CStdString strExtension=CUtil::GetExtension(strPath);
61   if (strExtension.size() == 0) return NULL;
62   strExtension.MakeLower();
63
64 #ifdef HAS_FILESYSTEM
65   if (strExtension.Equals(".ogg") && CFile::Exists(strPath))
66   {
67     IFileDirectory* pDir=new COGGFileDirectory;
68     //  Has the ogg file more than one bitstream?
69     if (pDir->ContainsFiles(strPath))
70     {
71       return pDir; // treat as directory
72     }
73
74     delete pDir;
75     return NULL;
76   }
77   if (strExtension.Equals(".nsf") && CFile::Exists(strPath))
78   {
79     IFileDirectory* pDir=new CNSFFileDirectory;
80     //  Has the nsf file more than one track?
81     if (pDir->ContainsFiles(strPath))
82       return pDir; // treat as directory
83
84     delete pDir;
85     return NULL;
86   }
87   if (strExtension.Equals(".sid") && CFile::Exists(strPath))
88   {
89     IFileDirectory* pDir=new CSIDFileDirectory;
90     //  Has the sid file more than one track?
91     if (pDir->ContainsFiles(strPath))
92       return pDir; // treat as directory
93
94     delete pDir;
95     return NULL;
96   }
97   if (ASAPCodec::IsSupportedFormat(strExtension) && CFile::Exists(strPath))
98   {
99     IFileDirectory* pDir=new CASAPFileDirectory;
100     //  Has the asap file more than one track?
101     if (pDir->ContainsFiles(strPath))
102       return pDir; // treat as directory
103
104     delete pDir;
105     return NULL;
106   }
107 #endif
108   if (strExtension.Equals(".zip"))
109   {
110     CStdString strUrl; 
111     CUtil::CreateArchivePath(strUrl, "zip", strPath, "");
112
113     CFileItemList item;
114     CGUIViewState* guiState = CGUIViewState::GetViewState(0,item);
115     if (guiState)
116     {
117       bool bState = guiState->UnrollArchives();
118       delete guiState;
119       guiState = NULL;
120       if (!bState)
121       {
122         pItem->m_strPath = strUrl;
123         return new CZipDirectory;
124       }
125     }
126
127     if (g_ZipManager.HasMultipleEntries(strPath))
128     {
129       pItem->m_strPath = strUrl;
130       return new CZipDirectory;
131     }
132
133     item.Clear();
134     CDirectory dir; dir.GetDirectory(strUrl,item,strMask);
135     if (item.Size())
136       *pItem = *item[0];
137     else
138       pItem->m_bIsFolder = true;
139
140     return NULL;
141   }
142   if (strExtension.Equals(".rar") || strExtension.Equals(".001"))
143   {
144     CStdString strUrl; 
145     CUtil::CreateArchivePath(strUrl, "rar", strPath, "");
146
147     std::vector<CStdString> tokens;
148     CUtil::Tokenize(strPath,tokens,".");
149     if (tokens.size() > 2)
150     {
151       if (strExtension.Equals(".001"))
152       {
153         if (tokens[tokens.size()-2].Equals("ts")) // .ts.001 - treat as a movie file to scratch some users itch
154           return NULL;
155       }
156       CStdString token = tokens[tokens.size()-2];
157       if (token.Left(4).CompareNoCase("part") == 0) // only list '.part01.rar'
158       {
159         // need this crap to avoid making mistakes - yeyh for the new rar naming scheme :/
160         struct __stat64 stat;
161         int digits = token.size()-4;
162         CStdString strNumber, strFormat;
163         strFormat.Format("part%%0%ii",digits);
164         strNumber.Format(strFormat.c_str(),1);
165         CStdString strPath2=strPath;
166         strPath2.Replace(token,strNumber);
167         if (atoi(token.substr(4).c_str()) > 1 && CFile::Stat(strPath2,&stat) == 0)
168         {
169           pItem->m_bIsFolder = true;
170           return NULL;
171         }
172       }
173     }
174
175     CFileItemList item;
176     CGUIViewState* guiState = CGUIViewState::GetViewState(0,item);
177     if (guiState)
178     {
179       bool bState = guiState->UnrollArchives();
180       delete guiState;
181       guiState = NULL;
182       if (!bState)
183       {
184         pItem->m_strPath = strUrl;
185         return new CRarDirectory;
186       }
187     }
188
189     if (g_RarManager.HasMultipleEntries(strPath))
190     {
191       pItem->m_strPath = strUrl;
192       return new CRarDirectory;
193     }
194
195     CDirectory dir; dir.GetDirectory(strUrl,item,strMask);
196     if (item.Size())
197       *pItem = *item[0];
198     else
199       pItem->m_bIsFolder = true;
200
201     return NULL;
202   }
203   if (strExtension.Equals(".xsp"))
204   { // XBMC Smart playlist - just XML renamed to XSP
205     // read the name of the playlist in
206     CSmartPlaylist playlist;
207     if (playlist.OpenAndReadName(strPath))
208     {
209       pItem->SetLabel(playlist.GetName());
210       pItem->SetLabelPreformated(true);
211     }
212     IFileDirectory* pDir=new CSmartPlaylistDirectory;
213     return pDir; // treat as directory
214   }
215   if (g_advancedSettings.m_playlistAsFolders && CPlayListFactory::IsPlaylist(strPath))
216   { // Playlist file
217     // currently we only return the directory if it contains
218     // more than one file.  Reason is that .pls and .m3u may be used
219     // for links to http streams etc. 
220     IFileDirectory *pDir = new CPlaylistFileDirectory();
221     CFileItemList items;
222     if (pDir->GetDirectory(strPath, items))
223     {
224       if (items.Size() > 1)
225         return pDir;
226     }
227     delete pDir;
228     return NULL;
229   }
230   return NULL;
231 }
232