[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / filesystem / StackDirectory.cpp
1 /*
2  *      Copyright (C) 2005-2013 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, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "StackDirectory.h"
22 #include "utils/log.h"
23 #include "utils/URIUtils.h"
24 #include "FileItem.h"
25 #include "utils/StringUtils.h"
26 #include "settings/AdvancedSettings.h"
27 #include "URL.h"
28
29 using namespace std;
30 namespace XFILE
31 {
32   CStackDirectory::CStackDirectory()
33   {
34   }
35
36   CStackDirectory::~CStackDirectory()
37   {
38   }
39
40   bool CStackDirectory::GetDirectory(const CStdString& strPath, CFileItemList& items)
41   {
42     items.Clear();
43     CStdStringArray files;
44     if (!GetPaths(strPath, files))
45       return false;   // error in path
46
47     for (unsigned int i = 0; i < files.size(); i++)
48     {
49       CStdString file = files[i];
50       CFileItemPtr item(new CFileItem(file));
51       //URIUtils::AddFileToFolder(folder, file, item->GetPath());
52       item->SetPath(file);
53       item->m_bIsFolder = false;
54       items.Add(item);
55     }
56     return true;
57   }
58
59   CStdString CStackDirectory::GetStackedTitlePath(const CStdString &strPath)
60   {
61     // Load up our REs
62     VECCREGEXP  RegExps;
63     CRegExp     tempRE(true);
64     const CStdStringArray& strRegExps = g_advancedSettings.m_videoStackRegExps;
65     CStdStringArray::const_iterator itRegExp = strRegExps.begin();
66     vector<pair<int, CStdString> > badStacks;
67     while (itRegExp != strRegExps.end())
68     {
69       tempRE.RegComp(*itRegExp);
70       if (tempRE.GetCaptureTotal() == 4)
71         RegExps.push_back(tempRE);
72       else
73         CLog::Log(LOGERROR, "Invalid video stack RE (%s). Must have exactly 4 captures.", itRegExp->c_str());
74       itRegExp++;
75     }
76     return GetStackedTitlePath(strPath, RegExps);
77   }
78
79   CStdString CStackDirectory::GetStackedTitlePath(const CStdString &strPath, VECCREGEXP& RegExps)
80   {
81     CStackDirectory stack;
82     CFileItemList   files;
83     CStdString      strStackTitlePath,
84                     strCommonDir        = URIUtils::GetParentPath(strPath);
85
86     stack.GetDirectory(strPath, files);
87
88     if (files.Size() > 1)
89     {
90       CStdString strStackTitle;
91
92       CStdString File1 = URIUtils::GetFileName(files[0]->GetPath());
93       CStdString File2 = URIUtils::GetFileName(files[1]->GetPath());
94       // Check if source path uses URL encoding
95       if (URIUtils::ProtocolHasEncodedFilename(CURL(strCommonDir).GetProtocol()))
96       {
97         CURL::Decode(File1);
98         CURL::Decode(File2);
99       }
100
101       std::vector<CRegExp>::iterator itRegExp = RegExps.begin();
102       int offset = 0;
103
104       while (itRegExp != RegExps.end())
105       {
106         if (itRegExp->RegFind(File1, offset) != -1)
107         {
108           CStdString Title1     = itRegExp->GetMatch(1),
109                      Volume1    = itRegExp->GetMatch(2),
110                      Ignore1    = itRegExp->GetMatch(3),
111                      Extension1 = itRegExp->GetMatch(4);
112           if (offset)
113             Title1 = File1.substr(0, itRegExp->GetSubStart(2));
114           if (itRegExp->RegFind(File2, offset) != -1)
115           {
116             CStdString Title2     = itRegExp->GetMatch(1),
117                        Volume2    = itRegExp->GetMatch(2),
118                        Ignore2    = itRegExp->GetMatch(3),
119                        Extension2 = itRegExp->GetMatch(4);
120             if (offset)
121               Title2 = File2.substr(0, itRegExp->GetSubStart(2));
122             if (Title1.Equals(Title2))
123             {
124               if (!Volume1.Equals(Volume2))
125               {
126                 if (Ignore1.Equals(Ignore2) && Extension1.Equals(Extension2))
127                 {
128                   // got it
129                   strStackTitle = Title1 + Ignore1 + Extension1;
130                   // Check if source path uses URL encoding
131                   if (URIUtils::ProtocolHasEncodedFilename(CURL(strCommonDir).GetProtocol()))
132                     CURL::Encode(strStackTitle);
133
134                   itRegExp = RegExps.end();
135                   break;
136                 }
137                 else // Invalid stack
138                   break;
139               }
140               else // Early match, retry with offset
141               {
142                 offset = itRegExp->GetSubStart(3);
143                 continue;
144               }
145             }
146           }
147         }
148         offset = 0;
149         itRegExp++;
150       }
151       if (!strCommonDir.empty() && !strStackTitle.empty())
152         strStackTitlePath = strCommonDir + strStackTitle;
153     }
154
155     return strStackTitlePath;
156   }
157
158   CStdString CStackDirectory::GetFirstStackedFile(const CStdString &strPath)
159   {
160     // the stacked files are always in volume order, so just get up to the first filename
161     // occurence of " , "
162     CStdString path, file, folder;
163     int pos = strPath.Find(" , ");
164     if (pos > 0)
165       URIUtils::Split(strPath.Left(pos), folder, file);
166     else
167       URIUtils::Split(strPath, folder, file); // single filed stacks - should really not happen
168
169     // remove "stack://" from the folder
170     folder = folder.Mid(8);
171     file.Replace(",,", ",");
172     URIUtils::AddFileToFolder(folder, file, path);
173
174     return path;
175   }
176
177   bool CStackDirectory::GetPaths(const CStdString& strPath, vector<CStdString>& vecPaths)
178   {
179     // format is:
180     // stack://file1 , file2 , file3 , file4
181     // filenames with commas are double escaped (ie replaced with ,,), thus the " , " separator used.
182     CStdString path = strPath;
183     // remove stack:// from the beginning
184     path = path.Mid(8);
185     
186     vecPaths.clear();
187     StringUtils::SplitString(path, " , ", vecPaths);
188     if (vecPaths.empty())
189       return false;
190
191     // because " , " is used as a seperator any "," in the real paths are double escaped
192     for (vector<CStdString>::iterator itPath = vecPaths.begin(); itPath != vecPaths.end(); itPath++)
193       itPath->Replace(",,", ",");
194
195     return true;
196   }
197
198   CStdString CStackDirectory::ConstructStackPath(const CFileItemList &items, const vector<int> &stack)
199   {
200     // no checks on the range of stack here.
201     // we replace all instances of comma's with double comma's, then separate
202     // the files using " , ".
203     CStdString stackedPath = "stack://";
204     CStdString folder, file;
205     URIUtils::Split(items[stack[0]]->GetPath(), folder, file);
206     stackedPath += folder;
207     // double escape any occurence of commas
208     file.Replace(",", ",,");
209     stackedPath += file;
210     for (unsigned int i = 1; i < stack.size(); ++i)
211     {
212       stackedPath += " , ";
213       file = items[stack[i]]->GetPath();
214
215       // double escape any occurence of commas
216       file.Replace(",", ",,");
217       stackedPath += file;
218     }
219     return stackedPath;
220   }
221
222   bool CStackDirectory::ConstructStackPath(const vector<CStdString> &paths, CStdString& stackedPath)
223   {
224     if (paths.size() < 2)
225       return false;
226     stackedPath = "stack://";
227     CStdString folder, file;
228     URIUtils::Split(paths[0], folder, file);
229     stackedPath += folder;
230     // double escape any occurence of commas
231     file.Replace(",", ",,");
232     stackedPath += file;
233     for (unsigned int i = 1; i < paths.size(); ++i)
234     {
235       stackedPath += " , ";
236       file = paths[i];
237
238       // double escape any occurence of commas
239       file.Replace(",", ",,");
240       stackedPath += file;
241     }
242     return true;
243   }
244 }
245