[WASAPI] fix stream types and frequencies enumeration
[xbmc.git] / xbmc / playlists / PlayListPLS.cpp
blob00eb67bfe46404e72fb0a6a31b2d3f6722c1a232
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "PlayListPLS.h"
11 #include "FileItem.h"
12 #include "PlayListFactory.h"
13 #include "Util.h"
14 #include "filesystem/File.h"
15 #include "music/MusicFileItemClassify.h"
16 #include "music/tags/MusicInfoTag.h"
17 #include "utils/CharsetConverter.h"
18 #include "utils/StringUtils.h"
19 #include "utils/URIUtils.h"
20 #include "utils/log.h"
22 #include <iostream>
23 #include <string>
24 #include <vector>
26 using namespace XFILE;
28 #define START_PLAYLIST_MARKER "[playlist]" // may be case-insensitive (equivalent to .ini file on win32)
29 #define PLAYLIST_NAME "PlaylistName"
31 namespace KODI::PLAYLIST
34 /*----------------------------------------------------------------------
35 [playlist]
36 PlaylistName=Playlist 001
37 File1=E:\Program Files\Winamp3\demo.mp3
38 Title1=demo
39 Length1=5
40 File2=E:\Program Files\Winamp3\demo.mp3
41 Title2=demo
42 Length2=5
43 NumberOfEntries=2
44 Version=2
45 ----------------------------------------------------------------------*/
46 CPlayListPLS::CPlayListPLS(void) = default;
48 CPlayListPLS::~CPlayListPLS(void) = default;
50 bool CPlayListPLS::Load(const std::string &strFile)
52 //read it from the file
53 std::string strFileName(strFile);
54 m_strPlayListName = URIUtils::GetFileName(strFileName);
56 Clear();
58 bool bShoutCast = false;
59 if( StringUtils::StartsWithNoCase(strFileName, "shout://") )
61 strFileName.replace(0, 8, "http://");
62 m_strBasePath = "";
63 bShoutCast = true;
65 else
66 URIUtils::GetParentPath(strFileName, m_strBasePath);
68 CFile file;
69 if (!file.Open(strFileName) )
71 file.Close();
72 return false;
75 if (file.GetLength() > 1024*1024)
77 CLog::Log(LOGWARNING, "{} - File is larger than 1 MB, most likely not a playlist",
78 __FUNCTION__);
79 return false;
82 char szLine[4096];
83 std::string strLine;
85 // run through looking for the [playlist] marker.
86 // if we find another http stream, then load it.
87 while (true)
89 if ( !file.ReadString(szLine, sizeof(szLine) ) )
91 file.Close();
92 return size() > 0;
94 strLine = szLine;
95 StringUtils::Trim(strLine);
96 if(StringUtils::EqualsNoCase(strLine, START_PLAYLIST_MARKER))
97 break;
99 // if there is something else before playlist marker, this isn't a pls file
100 if(!strLine.empty())
101 return false;
104 bool bFailed = false;
105 while (file.ReadString(szLine, sizeof(szLine) ) )
107 strLine = szLine;
108 StringUtils::RemoveCRLF(strLine);
109 size_t iPosEqual = strLine.find('=');
110 if (iPosEqual != std::string::npos)
112 std::string strLeft = strLine.substr(0, iPosEqual);
113 iPosEqual++;
114 std::string strValue = strLine.substr(iPosEqual);
115 StringUtils::ToLower(strLeft);
116 StringUtils::TrimLeft(strLeft);
118 if (strLeft == "numberofentries")
120 m_vecItems.reserve(atoi(strValue.c_str()));
122 else if (StringUtils::StartsWith(strLeft, "file"))
124 std::vector <int>::size_type idx = atoi(strLeft.c_str() + 4);
125 if (!Resize(idx))
127 bFailed = true;
128 break;
131 // Skip self - do not load playlist recursively
132 if (StringUtils::EqualsNoCase(URIUtils::GetFileName(strValue),
133 URIUtils::GetFileName(strFileName)))
134 continue;
136 if (m_vecItems[idx - 1]->GetLabel().empty())
137 m_vecItems[idx - 1]->SetLabel(URIUtils::GetFileName(strValue));
138 CFileItem item(strValue, false);
139 if (bShoutCast && !MUSIC::IsAudio(item))
140 strValue.replace(0, 7, "shout://");
142 strValue = URIUtils::SubstitutePath(strValue);
143 CUtil::GetQualifiedFilename(m_strBasePath, strValue);
144 g_charsetConverter.unknownToUTF8(strValue);
145 m_vecItems[idx - 1]->SetPath(strValue);
147 else if (StringUtils::StartsWith(strLeft, "title"))
149 std::vector <int>::size_type idx = atoi(strLeft.c_str() + 5);
150 if (!Resize(idx))
152 bFailed = true;
153 break;
155 g_charsetConverter.unknownToUTF8(strValue);
156 m_vecItems[idx - 1]->SetLabel(strValue);
158 else if (StringUtils::StartsWith(strLeft, "length"))
160 std::vector <int>::size_type idx = atoi(strLeft.c_str() + 6);
161 if (!Resize(idx))
163 bFailed = true;
164 break;
166 m_vecItems[idx - 1]->GetMusicInfoTag()->SetDuration(atol(strValue.c_str()));
168 else if (strLeft == "playlistname")
170 m_strPlayListName = strValue;
171 g_charsetConverter.unknownToUTF8(m_strPlayListName);
175 file.Close();
177 if (bFailed)
179 CLog::Log(LOGERROR,
180 "File {} is not a valid PLS playlist. Location of first file,title or length is not "
181 "permitted (eg. File0 should be File1)",
182 URIUtils::GetFileName(strFileName));
183 return false;
186 // check for missing entries
187 ivecItems p = m_vecItems.begin();
188 while ( p != m_vecItems.end())
190 if ((*p)->GetPath().empty())
192 p = m_vecItems.erase(p);
194 else
196 ++p;
200 return true;
203 void CPlayListPLS::Save(const std::string& strFileName) const
205 if (!m_vecItems.size()) return ;
206 std::string strPlaylist = CUtil::MakeLegalPath(strFileName);
207 CFile file;
208 if (!file.OpenForWrite(strPlaylist, true))
210 CLog::Log(LOGERROR, "Could not save PLS playlist: [{}]", strPlaylist);
211 return;
213 std::string write;
214 write += StringUtils::Format("{}\n", START_PLAYLIST_MARKER);
215 std::string strPlayListName=m_strPlayListName;
216 g_charsetConverter.utf8ToStringCharset(strPlayListName);
217 write += StringUtils::Format("PlaylistName={}\n", strPlayListName);
219 for (int i = 0; i < (int)m_vecItems.size(); ++i)
221 CFileItemPtr item = m_vecItems[i];
222 std::string strFileName=item->GetPath();
223 g_charsetConverter.utf8ToStringCharset(strFileName);
224 std::string strDescription=item->GetLabel();
225 g_charsetConverter.utf8ToStringCharset(strDescription);
226 write += StringUtils::Format("File{}={}\n", i + 1, strFileName);
227 write += StringUtils::Format("Title{}={}\n", i + 1, strDescription.c_str());
228 write +=
229 StringUtils::Format("Length{}={}\n", i + 1, item->GetMusicInfoTag()->GetDuration() / 1000);
232 write += StringUtils::Format("NumberOfEntries={0}\n", m_vecItems.size());
233 write += StringUtils::Format("Version=2\n");
234 file.Write(write.c_str(), write.size());
235 file.Close();
238 bool CPlayListPLS::Resize(std::vector <int>::size_type newSize)
240 if (newSize == 0)
241 return false;
243 while (m_vecItems.size() < newSize)
245 CFileItemPtr fileItem(new CFileItem());
246 m_vecItems.push_back(fileItem);
248 return true;
251 } // namespace KODI::PLAYLIST