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));
52 item->m_bIsFolder = false;
58 CStdString CStackDirectory::GetStackedTitlePath(const CStdString &strPath)
62 CRegExp tempRE(true, true);
63 const CStdStringArray& strRegExps = g_advancedSettings.m_videoStackRegExps;
64 CStdStringArray::const_iterator itRegExp = strRegExps.begin();
65 vector<pair<int, CStdString> > badStacks;
66 while (itRegExp != strRegExps.end())
68 tempRE.RegComp(*itRegExp);
69 if (tempRE.GetCaptureTotal() == 4)
70 RegExps.push_back(tempRE);
72 CLog::Log(LOGERROR, "Invalid video stack RE (%s). Must have exactly 4 captures.", itRegExp->c_str());
75 return GetStackedTitlePath(strPath, RegExps);
78 CStdString CStackDirectory::GetStackedTitlePath(const CStdString &strPath, VECCREGEXP& RegExps)
80 CStackDirectory stack;
82 CStdString strStackTitlePath,
83 strCommonDir = URIUtils::GetParentPath(strPath);
85 stack.GetDirectory(strPath, files);
89 CStdString strStackTitle;
91 CStdString File1 = URIUtils::GetFileName(files[0]->GetPath());
92 CStdString File2 = URIUtils::GetFileName(files[1]->GetPath());
93 // Check if source path uses URL encoding
94 if (URIUtils::ProtocolHasEncodedFilename(CURL(strCommonDir).GetProtocol()))
100 std::vector<CRegExp>::iterator itRegExp = RegExps.begin();
103 while (itRegExp != RegExps.end())
105 if (itRegExp->RegFind(File1, offset) != -1)
107 CStdString Title1 = itRegExp->GetMatch(1),
108 Volume1 = itRegExp->GetMatch(2),
109 Ignore1 = itRegExp->GetMatch(3),
110 Extension1 = itRegExp->GetMatch(4);
112 Title1 = File1.substr(0, itRegExp->GetSubStart(2));
113 if (itRegExp->RegFind(File2, offset) != -1)
115 CStdString Title2 = itRegExp->GetMatch(1),
116 Volume2 = itRegExp->GetMatch(2),
117 Ignore2 = itRegExp->GetMatch(3),
118 Extension2 = itRegExp->GetMatch(4);
120 Title2 = File2.substr(0, itRegExp->GetSubStart(2));
121 if (Title1.Equals(Title2))
123 if (!Volume1.Equals(Volume2))
125 if (Ignore1.Equals(Ignore2) && Extension1.Equals(Extension2))
128 strStackTitle = Title1 + Ignore1 + Extension1;
129 // Check if source path uses URL encoding
130 if (URIUtils::ProtocolHasEncodedFilename(CURL(strCommonDir).GetProtocol()))
131 CURL::Encode(strStackTitle);
133 itRegExp = RegExps.end();
136 else // Invalid stack
139 else // Early match, retry with offset
141 offset = itRegExp->GetSubStart(3);
150 if (!strCommonDir.empty() && !strStackTitle.empty())
151 strStackTitlePath = strCommonDir + strStackTitle;
154 return strStackTitlePath;
157 CStdString CStackDirectory::GetFirstStackedFile(const CStdString &strPath)
159 // the stacked files are always in volume order, so just get up to the first filename
160 // occurence of " , "
161 CStdString file, folder;
162 size_t pos = strPath.find(" , ");
163 if (pos != std::string::npos)
164 URIUtils::Split((CStdString)strPath.substr(0, pos), folder, file);
166 URIUtils::Split(strPath, folder, file); // single filed stacks - should really not happen
168 // remove "stack://" from the folder
169 folder = folder.substr(8);
170 StringUtils::Replace(file, ",,", ",");
172 return URIUtils::AddFileToFolder(folder, file);
175 bool CStackDirectory::GetPaths(const CStdString& strPath, vector<CStdString>& vecPaths)
178 // stack://file1 , file2 , file3 , file4
179 // filenames with commas are double escaped (ie replaced with ,,), thus the " , " separator used.
180 CStdString path = strPath;
181 // remove stack:// from the beginning
182 path = path.substr(8);
185 StringUtils::SplitString(path, " , ", vecPaths);
186 if (vecPaths.empty())
189 // because " , " is used as a seperator any "," in the real paths are double escaped
190 for (vector<CStdString>::iterator itPath = vecPaths.begin(); itPath != vecPaths.end(); itPath++)
191 StringUtils::Replace(*itPath, ",,", ",");
196 CStdString CStackDirectory::ConstructStackPath(const CFileItemList &items, const vector<int> &stack)
198 // no checks on the range of stack here.
199 // we replace all instances of comma's with double comma's, then separate
200 // the files using " , ".
201 CStdString stackedPath = "stack://";
202 CStdString folder, file;
203 URIUtils::Split(items[stack[0]]->GetPath(), folder, file);
204 stackedPath += folder;
205 // double escape any occurence of commas
206 StringUtils::Replace(file, ",", ",,");
208 for (unsigned int i = 1; i < stack.size(); ++i)
210 stackedPath += " , ";
211 file = items[stack[i]]->GetPath();
213 // double escape any occurence of commas
214 StringUtils::Replace(file, ",", ",,");
220 bool CStackDirectory::ConstructStackPath(const vector<CStdString> &paths, CStdString& stackedPath)
222 vector<string> pathsT;
223 pathsT.reserve(paths.size());
224 for (vector<CStdString>::const_iterator path = paths.begin();
225 path != paths.end(); ++path)
227 pathsT.push_back(*path);
229 std::string stackedPathT = stackedPath;
230 bool retVal = ConstructStackPath(pathsT, stackedPathT);
231 stackedPath = stackedPathT;
235 bool CStackDirectory::ConstructStackPath(const vector<std::string> &paths, std::string& stackedPath)
237 if (paths.size() < 2)
239 stackedPath = "stack://";
240 std::string folder, file;
241 URIUtils::Split(paths[0], folder, file);
242 stackedPath += folder;
243 // double escape any occurence of commas
244 StringUtils::Replace(file, ",", ",,");
246 for (unsigned int i = 1; i < paths.size(); ++i)
248 stackedPath += " , ";
251 // double escape any occurence of commas
252 StringUtils::Replace(file, ",", ",,");