2 * Copyright (C) 2005-2013 Team XBMC
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)
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.
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/>.
21 #include "StackDirectory.h"
22 #include "utils/log.h"
23 #include "utils/URIUtils.h"
25 #include "utils/StringUtils.h"
26 #include "settings/AdvancedSettings.h"
32 CStackDirectory::CStackDirectory()
36 CStackDirectory::~CStackDirectory()
40 bool CStackDirectory::GetDirectory(const CStdString& strPath, CFileItemList& items)
43 CStdStringArray files;
44 if (!GetPaths(strPath, files))
45 return false; // error in path
47 for (unsigned int i = 0; i < files.size(); i++)
49 CStdString file = files[i];
50 CFileItemPtr item(new CFileItem(file));
51 //URIUtils::AddFileToFolder(folder, file, item->GetPath());
53 item->m_bIsFolder = false;
59 CStdString CStackDirectory::GetStackedTitlePath(const CStdString &strPath)
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())
69 tempRE.RegComp(*itRegExp);
70 if (tempRE.GetCaptureTotal() == 4)
71 RegExps.push_back(tempRE);
73 CLog::Log(LOGERROR, "Invalid video stack RE (%s). Must have exactly 4 captures.", itRegExp->c_str());
76 return GetStackedTitlePath(strPath, RegExps);
79 CStdString CStackDirectory::GetStackedTitlePath(const CStdString &strPath, VECCREGEXP& RegExps)
81 CStackDirectory stack;
83 CStdString strStackTitlePath,
84 strCommonDir = URIUtils::GetParentPath(strPath);
86 stack.GetDirectory(strPath, files);
90 CStdString strStackTitle;
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()))
101 std::vector<CRegExp>::iterator itRegExp = RegExps.begin();
104 while (itRegExp != RegExps.end())
106 if (itRegExp->RegFind(File1, offset) != -1)
108 CStdString Title1 = itRegExp->GetMatch(1),
109 Volume1 = itRegExp->GetMatch(2),
110 Ignore1 = itRegExp->GetMatch(3),
111 Extension1 = itRegExp->GetMatch(4);
113 Title1 = File1.substr(0, itRegExp->GetSubStart(2));
114 if (itRegExp->RegFind(File2, offset) != -1)
116 CStdString Title2 = itRegExp->GetMatch(1),
117 Volume2 = itRegExp->GetMatch(2),
118 Ignore2 = itRegExp->GetMatch(3),
119 Extension2 = itRegExp->GetMatch(4);
121 Title2 = File2.substr(0, itRegExp->GetSubStart(2));
122 if (Title1.Equals(Title2))
124 if (!Volume1.Equals(Volume2))
126 if (Ignore1.Equals(Ignore2) && Extension1.Equals(Extension2))
129 strStackTitle = Title1 + Ignore1 + Extension1;
130 // Check if source path uses URL encoding
131 if (URIUtils::ProtocolHasEncodedFilename(CURL(strCommonDir).GetProtocol()))
132 CURL::Encode(strStackTitle);
134 itRegExp = RegExps.end();
137 else // Invalid stack
140 else // Early match, retry with offset
142 offset = itRegExp->GetSubStart(3);
151 if (!strCommonDir.empty() && !strStackTitle.empty())
152 strStackTitlePath = strCommonDir + strStackTitle;
155 return strStackTitlePath;
158 CStdString CStackDirectory::GetFirstStackedFile(const CStdString &strPath)
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(" , ");
165 URIUtils::Split(strPath.Left(pos), folder, file);
167 URIUtils::Split(strPath, folder, file); // single filed stacks - should really not happen
169 // remove "stack://" from the folder
170 folder = folder.Mid(8);
171 file.Replace(",,", ",");
172 URIUtils::AddFileToFolder(folder, file, path);
177 bool CStackDirectory::GetPaths(const CStdString& strPath, vector<CStdString>& vecPaths)
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
187 StringUtils::SplitString(path, " , ", vecPaths);
188 if (vecPaths.empty())
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(",,", ",");
198 CStdString CStackDirectory::ConstructStackPath(const CFileItemList &items, const vector<int> &stack)
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(",", ",,");
210 for (unsigned int i = 1; i < stack.size(); ++i)
212 stackedPath += " , ";
213 file = items[stack[i]]->GetPath();
215 // double escape any occurence of commas
216 file.Replace(",", ",,");
222 bool CStackDirectory::ConstructStackPath(const vector<CStdString> &paths, CStdString& stackedPath)
224 if (paths.size() < 2)
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(",", ",,");
233 for (unsigned int i = 1; i < paths.size(); ++i)
235 stackedPath += " , ";
238 // double escape any occurence of commas
239 file.Replace(",", ",,");