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 "HTTPDirectory.h"
25 #include "utils/RegExp.h"
26 #include "settings/AdvancedSettings.h"
27 #include "utils/StringUtils.h"
28 #include "utils/CharsetConverter.h"
29 #include "utils/log.h"
30 #include "utils/URIUtils.h"
31 #include "utils/HTMLUtil.h"
34 using namespace XFILE;
36 CHTTPDirectory::CHTTPDirectory(void){}
37 CHTTPDirectory::~CHTTPDirectory(void){}
39 bool CHTTPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
44 CStdString strName, strLink;
45 CStdString strBasePath = url.GetFileName();
49 CLog::Log(LOGERROR, "%s - Unable to get http directory", __FUNCTION__);
53 CRegExp reItem(true); // HTML is case-insensitive
54 reItem.RegComp("<a href=\"(.*)\">(.*)</a>");
56 CRegExp reDateTime(true);
57 reDateTime.RegComp("<td align=\"right\">([0-9]{2})-([A-Z]{3})-([0-9]{4}) ([0-9]{2}):([0-9]{2}) +</td>");
59 CRegExp reDateTimeLighttp(true);
60 reDateTimeLighttp.RegComp("<td class=\"m\">([0-9]{4})-([A-Z]{3})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})</td>");
62 CRegExp reDateTimeNginx(true);
63 reDateTimeNginx.RegComp("</a> +([0-9]{2})-([A-Z]{3})-([0-9]{4}) ([0-9]{2}):([0-9]{2}) ");
66 reSize.RegComp("> *([0-9.]+)(B|K|M|G| )</td>");
68 CRegExp reSizeNginx(true);
69 reSizeNginx.RegComp("([0-9]+)(B|K|M|G)?$");
71 /* read response from server into string buffer */
72 char buffer[MAX_PATH + 1024];
73 while(http.ReadString(buffer, sizeof(buffer)-1))
75 CStdString strBuffer = buffer;
76 std::string fileCharset(http.GetServerReportedCharset());
77 if (!fileCharset.empty() && fileCharset != "UTF-8")
79 std::string converted;
80 if (g_charsetConverter.ToUtf8(fileCharset, strBuffer, converted) && !converted.empty())
81 strBuffer = converted;
84 StringUtils::RemoveCRLF(strBuffer);
86 if (reItem.RegFind(strBuffer.c_str()) >= 0)
88 strLink = reItem.GetMatch(1);
89 strName = reItem.GetMatch(2);
92 strLink = strLink.substr(1);
94 CStdString strNameTemp = StringUtils::Trim(strName);
96 CStdStringW wName, wLink, wConverted;
97 if (fileCharset.empty())
98 g_charsetConverter.unknownToUTF8(strNameTemp);
99 g_charsetConverter.utf8ToW(strNameTemp, wName, false);
100 HTML::CHTMLUtil::ConvertHTMLToW(wName, wConverted);
101 g_charsetConverter.wToUTF8(wConverted, strNameTemp);
102 URIUtils::RemoveSlashAtEnd(strNameTemp);
104 CStdString strLinkBase = strLink;
105 CStdString strLinkOptions;
107 // split link with url options
108 size_t pos = strLinkBase.find('?');
109 if (pos != std::string::npos) {
110 strLinkOptions = strLinkBase.substr(pos);
111 strLinkBase.erase(pos);
113 CStdString strLinkTemp = strLinkBase;
115 URIUtils::RemoveSlashAtEnd(strLinkTemp);
116 strLinkTemp = CURL::Decode(strLinkTemp);
117 if (fileCharset.empty())
118 g_charsetConverter.unknownToUTF8(strLinkTemp);
119 g_charsetConverter.utf8ToW(strLinkTemp, wLink, false);
120 HTML::CHTMLUtil::ConvertHTMLToW(wLink, wConverted);
121 g_charsetConverter.wToUTF8(wConverted, strLinkTemp);
123 if (StringUtils::EndsWith(strNameTemp, "..>") &&
124 StringUtils::StartsWith(strLinkTemp, strNameTemp.substr(0, strNameTemp.length() - 3)))
125 strName = strNameTemp = strLinkTemp;
127 // we detect http directory items by its display name and its stripped link
128 // if same, we consider it as a valid item.
129 if (strNameTemp == strLinkTemp && strLinkTemp != "..")
131 CFileItemPtr pItem(new CFileItem(strNameTemp));
132 pItem->SetProperty("IsHTTPDirectory", true);
133 url.SetFileName(strBasePath + strLinkBase);
134 url.SetOptions(strLinkOptions);
135 pItem->SetPath(url.Get());
137 if(URIUtils::HasSlashAtEnd(pItem->GetPath(), true))
138 pItem->m_bIsFolder = true;
140 CStdString day, month, year, hour, minute;
142 if (reDateTime.RegFind(strBuffer.c_str()) >= 0)
144 day = reDateTime.GetMatch(1);
145 month = reDateTime.GetMatch(2);
146 year = reDateTime.GetMatch(3);
147 hour = reDateTime.GetMatch(4);
148 minute = reDateTime.GetMatch(5);
150 else if (reDateTimeNginx.RegFind(strBuffer.c_str()) >= 0)
152 day = reDateTimeNginx.GetMatch(1);
153 month = reDateTimeNginx.GetMatch(2);
154 year = reDateTimeNginx.GetMatch(3);
155 hour = reDateTimeNginx.GetMatch(4);
156 minute = reDateTimeNginx.GetMatch(5);
158 else if (reDateTimeLighttp.RegFind(strBuffer.c_str()) >= 0)
160 day = reDateTimeLighttp.GetMatch(3);
161 month = reDateTimeLighttp.GetMatch(2);
162 year = reDateTimeLighttp.GetMatch(1);
163 hour = reDateTimeLighttp.GetMatch(4);
164 minute = reDateTimeLighttp.GetMatch(5);
167 if (day.length() > 0 && month.length() > 0 && year.length() > 0)
169 pItem->m_dateTime = CDateTime(atoi(year.c_str()), CDateTime::MonthStringToMonthNum(month), atoi(day.c_str()), atoi(hour.c_str()), atoi(minute.c_str()), 0);
172 if (!pItem->m_bIsFolder)
174 if (reSize.RegFind(strBuffer.c_str()) >= 0)
176 double Size = atof(reSize.GetMatch(1).c_str());
177 std::string strUnit(reSize.GetMatch(2));
181 else if (strUnit == "M")
182 Size = Size * 1024 * 1024;
183 else if (strUnit == "G")
184 Size = Size * 1024 * 1024 * 1024;
186 pItem->m_dwSize = (int64_t)Size;
188 else if (reSizeNginx.RegFind(strBuffer.c_str()) >= 0)
190 double Size = atof(reSizeNginx.GetMatch(1).c_str());
191 std::string strUnit(reSize.GetMatch(2));
195 else if (strUnit == "M")
196 Size = Size * 1024 * 1024;
197 else if (strUnit == "G")
198 Size = Size * 1024 * 1024 * 1024;
200 pItem->m_dwSize = (int64_t)Size;
203 if (g_advancedSettings.m_bHTTPDirectoryStatFilesize) // As a fallback get the size by stat-ing the file (slow)
207 pItem->m_dwSize=file.GetLength();
217 items.SetProperty("IsHTTPDirectory", true);
222 bool CHTTPDirectory::Exists(const char* strPath)
226 struct __stat64 buffer;
228 if( http.Stat(url, &buffer) != 0 )
233 if (buffer.st_mode == _S_IFDIR)