fixed: use CDirectory::GetDirectory for thumbnail searches to avoid useless stat...
[xbmc:xbmc-antiquated.git] / xbmc / FileItem.cpp
1 /*
2  *      Copyright (C) 2005-2008 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, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "stdafx.h"
23 #include "FileItem.h"
24 #include "Util.h"
25 #include "Picture.h"
26 #include "PlayListFactory.h"
27 #include "Shortcut.h"
28 #include "Crc32.h"
29 #include "FileSystem/DirectoryCache.h"
30 #include "FileSystem/StackDirectory.h"
31 #include "FileSystem/FileCurl.h"
32 #include "FileSystem/MultiPathDirectory.h"
33 #include "FileSystem/MusicDatabaseDirectory.h"
34 #include "FileSystem/VideoDatabaseDirectory.h"
35 #include "FileSystem/IDirectory.h"
36 #include "FileSystem/FactoryDirectory.h"
37 #include "MusicInfoTagLoaderFactory.h"
38 #include "CueDocument.h"
39 #include "utils/fstrcmp.h"
40 #include "VideoDatabase.h"
41 #include "MusicDatabase.h"
42 #include "SortFileItem.h"
43 #include "utils/TuxBoxUtil.h"
44 #include "VideoInfoTag.h"
45 #include "utils/SingleLock.h"
46 #include "MusicInfoTag.h"
47 #include "PictureInfoTag.h"
48 #include "Artist.h"
49 #include "Album.h"
50 #include "Song.h"
51 #include "URL.h"
52 #include "Settings.h"
53
54 using namespace std;
55 using namespace XFILE;
56 using namespace DIRECTORY;
57 using namespace PLAYLIST;
58 using namespace MUSIC_INFO;
59
60 CFileItem::CFileItem(const CSong& song)
61 {
62   m_musicInfoTag = NULL;
63   m_videoInfoTag = NULL;
64   m_pictureInfoTag = NULL;
65   Reset();
66   SetLabel(song.strTitle);
67   m_strPath = _P(song.strFileName);
68   GetMusicInfoTag()->SetSong(song);
69   m_lStartOffset = song.iStartOffset;
70   m_lEndOffset = song.iEndOffset;
71   m_strThumbnailImage = _P(song.strThumb);
72 }
73
74 CFileItem::CFileItem(const CStdString &path, const CAlbum& album)
75 {
76   m_musicInfoTag = NULL;
77   m_videoInfoTag = NULL;
78   m_pictureInfoTag = NULL;
79   Reset();
80   SetLabel(album.strAlbum);
81   m_strPath = _P(path);
82   m_bIsFolder = true;
83   m_strLabel2 = album.strArtist;
84   CUtil::AddSlashAtEnd(m_strPath);
85   GetMusicInfoTag()->SetAlbum(album);
86   if (album.thumbURL.m_url.size() > 0)
87     m_strThumbnailImage = album.thumbURL.m_url[0].m_url;
88   else
89     m_strThumbnailImage.clear();
90
91   SetProperty("description", album.strReview);
92   SetProperty("theme", album.strThemes);
93   SetProperty("mood", album.strMoods);
94   SetProperty("style", album.strStyles);
95   SetProperty("type", album.strType);
96   SetProperty("label", album.strLabel);
97   if (album.iRating > 0)
98     SetProperty("rating", album.iRating);
99 }
100
101 CFileItem::CFileItem(const CVideoInfoTag& movie)
102 {
103   m_musicInfoTag = NULL;
104   m_videoInfoTag = NULL;
105   m_pictureInfoTag = NULL;
106   Reset();
107   SetLabel(movie.m_strTitle);
108   if (movie.m_strFileNameAndPath.IsEmpty())
109   {
110     m_strPath = _P(movie.m_strPath);
111     CUtil::AddSlashAtEnd(m_strPath);
112     m_bIsFolder = true;
113   }
114   else
115   {
116     m_strPath = _P(movie.m_strFileNameAndPath);
117     m_bIsFolder = false;
118   }
119   *GetVideoInfoTag() = movie;
120   FillInDefaultIcon();
121   SetVideoThumb();
122   SetInvalid();
123 }
124
125 CFileItem::CFileItem(const CArtist& artist)
126 {
127   m_musicInfoTag = NULL;
128   m_videoInfoTag = NULL;
129   m_pictureInfoTag = NULL;
130   Reset();
131   SetLabel(artist.strArtist);
132   m_strPath = _P(artist.strArtist);
133   m_bIsFolder = true;
134   CUtil::AddSlashAtEnd(m_strPath);
135   GetMusicInfoTag()->SetArtist(artist.strArtist);
136 }
137
138 CFileItem::CFileItem(const CGenre& genre)
139 {
140   m_musicInfoTag = NULL;
141   m_videoInfoTag = NULL;
142   m_pictureInfoTag = NULL;
143   Reset();
144   SetLabel(genre.strGenre);
145   m_strPath = _P(genre.strGenre);
146   m_bIsFolder = true;
147   CUtil::AddSlashAtEnd(m_strPath);
148   GetMusicInfoTag()->SetGenre(genre.strGenre);
149 }
150
151 CFileItem::CFileItem(const CFileItem& item): CGUIListItem()
152 {
153   m_musicInfoTag = NULL;
154   m_videoInfoTag = NULL;
155   m_pictureInfoTag = NULL;
156   *this = item;
157 }
158
159 CFileItem::CFileItem(const CGUIListItem& item)
160 {
161   m_musicInfoTag = NULL;
162   m_videoInfoTag = NULL;
163   m_pictureInfoTag = NULL;
164   Reset();
165   // not particularly pretty, but it gets around the issue of Reset() defaulting
166   // parameters in the CGUIListItem base class.
167   *((CGUIListItem *)this) = item;
168 }
169
170 CFileItem::CFileItem(void)
171 {
172   m_musicInfoTag = NULL;
173   m_videoInfoTag = NULL;
174   m_pictureInfoTag = NULL;
175   Reset();
176 }
177
178 CFileItem::CFileItem(const CStdString& strLabel)
179     : CGUIListItem()
180 {
181   m_musicInfoTag = NULL;
182   m_videoInfoTag = NULL;
183   m_pictureInfoTag = NULL;
184   Reset();
185   SetLabel(strLabel);
186 }
187
188 CFileItem::CFileItem(const CStdString& strPath, bool bIsFolder)
189 {
190   m_musicInfoTag = NULL;
191   m_videoInfoTag = NULL;
192   m_pictureInfoTag = NULL;
193   Reset();
194   m_strPath = _P(strPath);
195   m_bIsFolder = bIsFolder;
196   // tuxbox urls cannot have a / at end
197   if (m_bIsFolder && !m_strPath.IsEmpty() && !IsFileFolder() && !CUtil::IsTuxBox(m_strPath))
198   {
199 #ifdef DEBUG
200     ASSERT(CUtil::HasSlashAtEnd(m_strPath));
201 #endif
202     CUtil::AddSlashAtEnd(m_strPath);
203   }
204 }
205
206 CFileItem::CFileItem(const CMediaSource& share)
207 {
208   m_musicInfoTag = NULL;
209   m_videoInfoTag = NULL;
210   m_pictureInfoTag = NULL;
211   Reset();
212   m_bIsFolder = true;
213   m_bIsShareOrDrive = true;
214   m_strPath = _P(share.strPath);
215   CUtil::AddSlashAtEnd(m_strPath);
216   CStdString label = share.strName;
217   if (share.strStatus.size())
218     label.Format("%s (%s)", share.strName.c_str(), share.strStatus.c_str());
219   SetLabel(label);
220   m_iLockMode = share.m_iLockMode;
221   m_strLockCode = share.m_strLockCode;
222   m_iHasLock = share.m_iHasLock;
223   m_iBadPwdCount = share.m_iBadPwdCount;
224   m_iDriveType = share.m_iDriveType;
225   m_strThumbnailImage = _P(share.m_strThumbnailImage);
226   SetLabelPreformated(true);
227 }
228
229 CFileItem::~CFileItem(void)
230 {
231   if (m_musicInfoTag)
232     delete m_musicInfoTag;
233   if (m_videoInfoTag)
234     delete m_videoInfoTag;
235   if (m_pictureInfoTag)
236     delete m_pictureInfoTag;
237
238   m_musicInfoTag = NULL;
239   m_videoInfoTag = NULL;
240   m_pictureInfoTag = NULL;
241 }
242
243 const CFileItem& CFileItem::operator=(const CFileItem& item)
244 {
245   if (this == &item) return * this;
246   CGUIListItem::operator=(item);
247   m_bLabelPreformated=item.m_bLabelPreformated;
248   FreeMemory();
249   m_strPath = item.m_strPath;
250 #ifdef DEBUG
251   if (m_bIsFolder && !m_strPath.IsEmpty() && !IsFileFolder() && !CUtil::IsTuxBox(m_strPath))  // should root paths be "/" ?
252   {
253 #ifndef __APPLE__
254     ASSERT(CUtil::HasSlashAtEnd(m_strPath));
255 #endif
256   }
257 #endif
258   m_bIsParentFolder = item.m_bIsParentFolder;
259   m_iDriveType = item.m_iDriveType;
260   m_bIsShareOrDrive = item.m_bIsShareOrDrive;
261   m_dateTime = item.m_dateTime;
262   m_dwSize = item.m_dwSize;
263   if (item.HasMusicInfoTag())
264   {
265     m_musicInfoTag = GetMusicInfoTag();
266     if (m_musicInfoTag)
267       *m_musicInfoTag = *item.m_musicInfoTag;
268   }
269   else
270   {
271     if (m_musicInfoTag)
272       delete m_musicInfoTag;
273
274     m_musicInfoTag = NULL;
275   }
276
277   if (item.HasVideoInfoTag())
278   {
279     m_videoInfoTag = GetVideoInfoTag();
280     if (m_videoInfoTag)
281       *m_videoInfoTag = *item.m_videoInfoTag;
282   }
283   else
284   {
285     if (m_videoInfoTag)
286       delete m_videoInfoTag;
287
288     m_videoInfoTag = NULL;
289   }
290
291   if (item.HasPictureInfoTag())
292   {
293     m_pictureInfoTag = GetPictureInfoTag();
294     if (m_pictureInfoTag)
295       *m_pictureInfoTag = *item.m_pictureInfoTag;
296   }
297   else
298   {
299     if (m_pictureInfoTag)
300       delete m_pictureInfoTag;
301
302     m_pictureInfoTag = NULL;
303   }
304
305   m_lStartOffset = item.m_lStartOffset;
306   m_lEndOffset = item.m_lEndOffset;
307   m_strDVDLabel = item.m_strDVDLabel;
308   m_strTitle = item.m_strTitle;
309   m_iprogramCount = item.m_iprogramCount;
310   m_idepth = item.m_idepth;
311   m_iLockMode = item.m_iLockMode;
312   m_strLockCode = item.m_strLockCode;
313   m_iHasLock = item.m_iHasLock;
314   m_iBadPwdCount = item.m_iBadPwdCount;
315   m_bCanQueue=item.m_bCanQueue;
316   m_contenttype = item.m_contenttype;
317   m_extrainfo = item.m_extrainfo;
318   return *this;
319 }
320
321 void CFileItem::Reset()
322 {
323   m_strLabel2.Empty();
324   SetLabel("");
325   m_bLabelPreformated=false;
326   FreeIcons();
327   m_overlayIcon = ICON_OVERLAY_NONE;
328   m_bSelected = false;
329   m_strDVDLabel.Empty();
330   m_strTitle.Empty();
331   m_strPath.Empty();
332   m_dwSize = 0;
333   m_bIsFolder = false;
334   m_bIsParentFolder=false;
335   m_bIsShareOrDrive = false;
336   m_dateTime.Reset();
337   m_iDriveType = CMediaSource::SOURCE_TYPE_UNKNOWN;
338   m_lStartOffset = 0;
339   m_lEndOffset = 0;
340   m_iprogramCount = 0;
341   m_idepth = 1;
342   m_iLockMode = LOCK_MODE_EVERYONE;
343   m_strLockCode = "";
344   m_iBadPwdCount = 0;
345   m_iHasLock = 0;
346   m_bCanQueue=true;
347   m_contenttype = "";
348   if (m_musicInfoTag)
349     delete m_musicInfoTag;
350   m_musicInfoTag=NULL;
351   if (m_videoInfoTag)
352     delete m_videoInfoTag;
353   m_videoInfoTag=NULL;
354   if (m_pictureInfoTag)
355     delete m_pictureInfoTag;
356   m_pictureInfoTag=NULL;
357   m_extrainfo.Empty();
358   SetInvalid();
359 }
360
361 void CFileItem::Serialize(CArchive& ar)
362 {
363   CGUIListItem::Serialize(ar);
364
365   if (ar.IsStoring())
366   {
367     ar << m_bIsParentFolder;
368     ar << m_bLabelPreformated;
369     ar << m_strPath;
370     ar << m_bIsShareOrDrive;
371     ar << m_iDriveType;
372     ar << m_dateTime;
373     ar << m_dwSize;
374     ar << m_strDVDLabel;
375     ar << m_strTitle;
376     ar << m_iprogramCount;
377     ar << m_idepth;
378     ar << m_lStartOffset;
379     ar << m_lEndOffset;
380     ar << m_iLockMode;
381     ar << m_strLockCode;
382     ar << m_iBadPwdCount;
383
384     ar << m_bCanQueue;
385     ar << m_contenttype;
386     ar << m_extrainfo;
387
388     if (m_musicInfoTag)
389     {
390       ar << 1;
391       ar << *m_musicInfoTag;
392     }
393     else
394       ar << 0;
395     if (m_videoInfoTag)
396     {
397       ar << 1;
398       ar << *m_videoInfoTag;
399     }
400     else 
401       ar << 0;
402     if (m_pictureInfoTag)
403     {
404       ar << 1;
405       ar << *m_pictureInfoTag;
406     }
407     else 
408       ar << 0;
409   }
410   else
411   {
412     ar >> m_bIsParentFolder;
413     ar >> m_bLabelPreformated;
414     ar >> m_strPath;
415     ar >> m_bIsShareOrDrive;
416     ar >> m_iDriveType;
417     ar >> m_dateTime;
418     ar >> m_dwSize;
419     ar >> m_strDVDLabel;
420     ar >> m_strTitle;
421     ar >> m_iprogramCount;
422     ar >> m_idepth;
423     ar >> m_lStartOffset;
424     ar >> m_lEndOffset;
425     ar >> (int&)m_iLockMode;
426     ar >> m_strLockCode;
427     ar >> m_iBadPwdCount;
428
429     ar >> m_bCanQueue;
430     ar >> m_contenttype;
431     ar >> m_extrainfo;
432
433     int iType;
434     ar >> iType;
435     if (iType == 1)
436       ar >> *GetMusicInfoTag();
437     ar >> iType;
438     if (iType == 1)
439       ar >> *GetVideoInfoTag();
440     ar >> iType;
441     if (iType == 1)
442       ar >> *GetPictureInfoTag();
443
444     SetInvalid();
445   }
446 }
447
448 bool CFileItem::IsVideo() const
449 {
450   /* check preset content type */
451   if( m_contenttype.Left(6).Equals("video/") )
452     return true;
453   
454   if (m_strPath.Left(7).Equals("tuxbox:")) 
455     return true;
456
457   if (m_strPath.Left(10).Equals("hdhomerun:"))
458     return true;
459
460   CStdString extension;
461   if( m_contenttype.Left(12).Equals("application/") )
462   { /* check for some standard types */
463     extension = m_contenttype.Mid(12);
464     if( extension.Equals("ogg")
465      || extension.Equals("mp4")
466      || extension.Equals("mxf") )
467      return true;
468   }
469
470   CUtil::GetExtension(m_strPath, extension);
471
472   if (extension.IsEmpty())
473     return false;
474
475   extension.ToLower();
476
477   if (g_stSettings.m_videoExtensions.Find(extension) != -1)
478     return true;
479
480   return false;
481 }
482
483 bool CFileItem::IsAudio() const
484 {
485   if (IsCDDA()) return true;
486   if (IsShoutCast() && !m_bIsFolder) return true;
487   if (IsLastFM() && !m_bIsFolder) return true;
488
489   /* check preset content type */
490   if( m_contenttype.Left(6).Equals("audio/") )
491     return true;
492
493   CStdString extension;
494   if( m_contenttype.Left(12).Equals("application/") )
495   { /* check for some standard types */
496     extension = m_contenttype.Mid(12);
497     if( extension.Equals("ogg")
498      || extension.Equals("mp4")
499      || extension.Equals("mxf") )
500      return true;
501   }
502
503   CUtil::GetExtension(m_strPath, extension);
504
505   if (extension.IsEmpty())
506     return false;
507
508   extension.ToLower();
509   if (g_stSettings.m_musicExtensions.Find(extension) != -1)
510     return true;
511
512   return false;
513 }
514
515 bool CFileItem::IsPicture() const
516 {
517   if( m_contenttype.Left(6).Equals("image/") )
518     return true;
519
520   CStdString extension;
521   CUtil::GetExtension(m_strPath, extension);
522
523   if (extension.IsEmpty())
524     return false;
525
526   extension.ToLower();
527   if (g_stSettings.m_pictureExtensions.Find(extension) != -1)
528     return true;
529
530   if (extension == ".tbn")
531     return true;
532
533   return false;
534 }
535
536 bool CFileItem::IsCUESheet() const
537 {
538   CStdString strExtension;
539   CUtil::GetExtension(m_strPath, strExtension);
540   return (strExtension.CompareNoCase(".cue") == 0);
541 }
542
543 bool CFileItem::IsShoutCast() const
544 {
545   if (strstr(m_strPath.c_str(), "shout:") ) return true;
546   return false;
547 }
548 bool CFileItem::IsLastFM() const
549 {
550   if (strstr(m_strPath.c_str(), "lastfm:") ) return true;
551   return false;
552 }
553
554 bool CFileItem::IsInternetStream() const
555 {
556   CURL url(m_strPath);
557   CStdString strProtocol = url.GetProtocol();
558   strProtocol.ToLower();
559
560   if (strProtocol.size() == 0)
561     return false;
562
563   if ((strProtocol == "http" || strProtocol == "https" ) && g_advancedSettings.m_bHTTPDirectoryLocalMode)
564     return false;
565   
566   // there's nothing to stop internet streams from being stacked
567   if (strProtocol == "stack")
568   {
569     CFileItem fileItem(CStackDirectory::GetFirstStackedFile(m_strPath), false);
570     return fileItem.IsInternetStream();
571   }
572
573   if (strProtocol == "shout" || strProtocol == "mms" ||
574       strProtocol == "http" || /*strProtocol == "ftp" ||*/
575       strProtocol == "rtsp" || strProtocol == "rtp" ||
576       strProtocol == "udp"  || strProtocol == "lastfm" ||
577       strProtocol == "https" || strProtocol == "rtmp")
578     return true;
579
580   return false;
581 }
582
583 bool CFileItem::IsFileFolder() const
584 {
585   return (
586     m_bIsFolder && (
587     IsPluginFolder() ||
588     IsSmartPlayList() ||
589     IsPlayList() ||
590     IsZIP() ||
591     IsRAR() ||
592     IsType(".ogg") ||
593     IsType(".nsf") ||
594     IsType(".sid") ||
595     IsType(".sap") ||
596     IsShoutCast()
597     )
598     );
599 }
600
601
602 bool CFileItem::IsSmartPlayList() const
603 {
604   CStdString strExtension;
605   CUtil::GetExtension(m_strPath, strExtension);
606   strExtension.ToLower();
607   return (strExtension == ".xsp");
608 }
609
610 bool CFileItem::IsPlayList() const
611 {
612   return CPlayListFactory::IsPlaylist(m_strPath);
613 }
614
615 bool CFileItem::IsPythonScript() const
616 {
617   return CUtil::GetExtension(m_strPath).Equals(".py", false);
618 }
619
620 bool CFileItem::IsXBE() const
621 {
622   return CUtil::GetExtension(m_strPath).Equals(".xbe", false);
623 }
624
625 bool CFileItem::IsType(const char *ext) const
626 {
627   return CUtil::GetExtension(m_strPath).Equals(ext, false);
628 }
629
630 bool CFileItem::IsDefaultXBE() const
631 {
632   CStdString filename = CUtil::GetFileName(m_strPath);
633   if (filename.Equals("default.xbe")) return true;
634   return false;
635 }
636
637 bool CFileItem::IsShortCut() const
638 {
639   return CUtil::GetExtension(m_strPath).Equals(".cut", false);
640 }
641
642 bool CFileItem::IsNFO() const
643 {
644   return CUtil::GetExtension(m_strPath).Equals(".nfo", false);
645 }
646
647 bool CFileItem::IsDVDImage() const
648 {
649   CStdString strExtension;
650   CUtil::GetExtension(m_strPath, strExtension);
651   if (strExtension.Equals(".img") || strExtension.Equals(".iso") || strExtension.Equals(".nrg")) return true;
652   return false;
653 }
654
655 bool CFileItem::IsDVDFile(bool bVobs /*= true*/, bool bIfos /*= true*/) const
656 {
657   CStdString strFileName = CUtil::GetFileName(m_strPath);
658   if (bIfos)
659   {
660     if (strFileName.Equals("video_ts.ifo")) return true;
661     if (strFileName.Left(4).Equals("vts_") && strFileName.Right(6).Equals("_0.ifo") && strFileName.length() == 12) return true;
662   }
663   if (bVobs)
664   {
665     if (strFileName.Equals("video_ts.vob")) return true;
666     if (strFileName.Left(4).Equals("vts_") && strFileName.Right(4).Equals(".vob")) return true;
667   }
668
669   return false;
670 }
671
672 bool CFileItem::IsRAR() const
673 {
674   CStdString strExtension;
675   CUtil::GetExtension(m_strPath, strExtension);
676   if ( (strExtension.CompareNoCase(".rar") == 0) || ((strExtension.Equals(".001") && m_strPath.Mid(m_strPath.length()-7,7).CompareNoCase(".ts.001"))) ) return true; // sometimes the first rar is named .001
677   return false;
678 }
679
680 bool CFileItem::IsZIP() const
681 {
682   return CUtil::GetExtension(m_strPath).Equals(".zip", false);
683 }
684
685 bool CFileItem::IsCBZ() const
686 {
687   return CUtil::GetExtension(m_strPath).Equals(".cbz", false);
688 }
689
690 bool CFileItem::IsCBR() const
691 {
692   return CUtil::GetExtension(m_strPath).Equals(".cbr", false);
693 }
694
695 bool CFileItem::IsStack() const
696 {
697   return CUtil::IsStack(m_strPath);
698 }
699
700 bool CFileItem::IsPluginFolder() const
701 {
702   CURL url(m_strPath);
703   return url.GetProtocol().Equals("plugin") && !url.GetFileName().IsEmpty();
704 }
705
706 bool CFileItem::IsMultiPath() const
707 {
708   return CUtil::IsMultiPath(m_strPath);
709 }
710
711 bool CFileItem::IsCDDA() const
712 {
713   return CUtil::IsCDDA(m_strPath);
714 }
715
716 bool CFileItem::IsDVD() const
717 {
718   return CUtil::IsDVD(m_strPath);
719 }
720
721 bool CFileItem::IsOnDVD() const
722 {
723   return CUtil::IsOnDVD(m_strPath);
724 }
725
726 bool CFileItem::IsOnLAN() const
727 {
728   return CUtil::IsOnLAN(m_strPath);
729 }
730
731 bool CFileItem::IsISO9660() const
732 {
733   return CUtil::IsISO9660(m_strPath);
734 }
735
736 bool CFileItem::IsRemote() const
737 {
738   return CUtil::IsRemote(m_strPath);
739 }
740
741 bool CFileItem::IsSmb() const
742 {
743   return CUtil::IsSmb(m_strPath);
744 }
745
746 bool CFileItem::IsDAAP() const
747 {
748   return CUtil::IsDAAP(m_strPath);
749 }
750
751 bool CFileItem::IsTuxBox() const
752 {
753   return CUtil::IsTuxBox(m_strPath);
754 }
755
756 bool CFileItem::IsMythTV() const
757 {
758   return CUtil::IsMythTV(m_strPath);
759 }
760
761 bool CFileItem::IsVTP() const
762 {
763   return CUtil::IsVTP(m_strPath);
764 }
765
766 bool CFileItem::IsTV() const
767 {
768   return CUtil::IsTV(m_strPath);
769 }
770
771 bool CFileItem::IsHD() const
772 {
773   return CUtil::IsHD(m_strPath);
774 }
775
776 bool CFileItem::IsMusicDb() const
777 {
778   if (strstr(m_strPath.c_str(), "musicdb:") ) return true;
779   return false;
780 }
781
782 bool CFileItem::IsVideoDb() const
783 {
784   if (strstr(m_strPath.c_str(), "videodb:") ) return true;
785   return false;
786 }
787
788 bool CFileItem::IsVirtualDirectoryRoot() const
789 {
790   return (m_bIsFolder && m_strPath.IsEmpty());
791 }
792
793 bool CFileItem::IsMemoryUnit() const
794 {
795   CURL url(m_strPath);
796   return url.GetProtocol().Left(3).Equals("mem");
797 }
798
799 bool CFileItem::IsRemovable() const
800 {
801   return IsOnDVD() || IsCDDA() || IsMemoryUnit();
802 }
803
804 bool CFileItem::IsReadOnly() const
805 {
806   if (IsParentFolder()) return true;
807   if (m_bIsShareOrDrive) return true;
808   return !CUtil::SupportsFileOperations(m_strPath);
809 }
810
811 void CFileItem::FillInDefaultIcon()
812 {
813   //CLog::Log(LOGINFO, "FillInDefaultIcon(%s)", pItem->GetLabel().c_str());
814   // find the default icon for a file or folder item
815   // for files this can be the (depending on the file type)
816   //   default picture for photo's
817   //   default picture for songs
818   //   default picture for videos
819   //   default picture for shortcuts
820   //   default picture for playlists
821   //   or the icon embedded in an .xbe
822   //
823   // for folders
824   //   for .. folders the default picture for parent folder
825   //   for other folders the defaultFolder.png
826
827   CStdString strThumb;
828   CStdString strExtension;
829   if (GetIconImage() == "")
830   {
831     if (!m_bIsFolder)
832     {
833       if ( IsPlayList() )
834       {
835         SetIconImage("defaultPlaylist.png");
836       }
837       else if ( IsPicture() )
838       {
839         // picture
840         SetIconImage("defaultPicture.png");
841       }
842       else if ( IsXBE() )
843       {
844         // xbe
845         SetIconImage("defaultProgram.png");
846       }
847       else if ( IsAudio() )
848       {
849         // audio
850         SetIconImage("defaultAudio.png");
851       }
852       else if ( IsVideo() )
853       {
854         // video
855         SetIconImage("defaultVideo.png");
856       }
857       else if ( IsShortCut() && !IsLabelPreformated() )
858       {
859         // shortcut
860         CStdString strDescription;
861         CStdString strFName;
862         strFName = CUtil::GetFileName(m_strPath);
863
864         int iPos = strFName.ReverseFind(".");
865         strDescription = strFName.Left(iPos);
866         SetLabel(strDescription);
867         SetIconImage("defaultShortcut.png");
868       }
869       else if ( IsPythonScript() )
870       {
871         SetIconImage("DefaultScript.png");
872       }
873       else
874       {
875         // default icon for unknown file type
876         SetIconImage("defaultFile.png");
877       }
878     }
879     else
880     {
881       if ( IsPlayList() )
882       {
883         SetIconImage("defaultPlaylist.png");
884       }
885       else if (IsParentFolder())
886       {
887         SetIconImage("defaultFolderBack.png");
888       }
889       else
890       {
891         SetIconImage("defaultFolder.png");
892       }
893     }
894   }
895   // Set the icon overlays (if applicable)
896   if (!HasOverlay())
897   {
898     if (CUtil::IsInRAR(m_strPath))
899       SetOverlayImage(CGUIListItem::ICON_OVERLAY_RAR);
900     else if (CUtil::IsInZIP(m_strPath))
901       SetOverlayImage(CGUIListItem::ICON_OVERLAY_ZIP);
902   }
903 }
904
905 CStdString CFileItem::GetCachedArtistThumb() const
906 {
907   return GetCachedThumb("artist"+GetLabel(),g_settings.GetMusicArtistThumbFolder());
908 }
909
910 CStdString CFileItem::GetCachedProfileThumb() const
911 {
912   return GetCachedThumb("profile"+m_strPath,g_settings.GetUserDataFolder()+"\\Thumbnails\\Profiles");
913 }
914
915 CStdString CFileItem::GetCachedSeasonThumb() const
916 {
917   CStdString seasonPath;
918   if (HasVideoInfoTag())
919     seasonPath = GetVideoInfoTag()->m_strPath;
920    
921   return GetCachedThumb("season"+seasonPath+GetLabel(),g_settings.GetVideoThumbFolder(),true);
922 }
923
924 CStdString CFileItem::GetCachedActorThumb() const
925 {
926   return GetCachedThumb("actor"+GetLabel(),g_settings.GetVideoThumbFolder(),true);
927 }
928
929 void CFileItem::SetCachedArtistThumb()
930 {
931   CStdString thumb(GetCachedArtistThumb());
932   if (CFile::Exists(thumb))
933   {
934     // found it, we are finished.
935     SetThumbnailImage(thumb);
936 //    SetIconImage(strThumb);
937   }
938 }
939
940 // set the album thumb for a file or folder
941 void CFileItem::SetMusicThumb(bool alwaysCheckRemote /* = true */)
942 {
943   if (HasThumbnail()) return;
944   SetCachedMusicThumb();
945   if (!HasThumbnail())
946     SetUserMusicThumb(alwaysCheckRemote);
947 }
948
949 void CFileItem::SetCachedSeasonThumb()
950 {
951   CStdString thumb(GetCachedSeasonThumb());
952   if (CFile::Exists(thumb))
953   {
954     // found it, we are finished.
955     SetThumbnailImage(thumb);
956   }
957 }
958
959 void CFileItem::RemoveExtension()
960 {
961   if (m_bIsFolder)
962     return ;
963   CStdString strLabel = GetLabel();
964   CUtil::RemoveExtension(strLabel);
965   SetLabel(strLabel);
966 }
967
968 void CFileItem::CleanString()
969 {
970   if (IsTV())
971     return;
972   CStdString strLabel = GetLabel();
973   CUtil::CleanString(strLabel, m_bIsFolder);
974   SetLabel(strLabel);
975 }
976
977 void CFileItem::SetLabel(const CStdString &strLabel)
978 {
979   if (strLabel=="..")
980   {
981     m_bIsParentFolder=true;
982     m_bIsFolder=true;
983     SetLabelPreformated(true);
984   }
985   CGUIListItem::SetLabel(strLabel);
986 }
987
988 void CFileItem::SetFileSizeLabel()
989 {
990   if( m_bIsFolder && m_dwSize == 0 )
991     SetLabel2("");
992   else
993     SetLabel2(StringUtils::SizeToString(m_dwSize));
994 }
995
996 CURL CFileItem::GetAsUrl() const
997 {
998   return CURL(m_strPath);
999 }
1000
1001 bool CFileItem::CanQueue() const
1002 {
1003   return m_bCanQueue;
1004 }
1005
1006 void CFileItem::SetCanQueue(bool bYesNo)
1007 {
1008   m_bCanQueue=bYesNo;
1009 }
1010
1011 bool CFileItem::IsParentFolder() const
1012 {
1013   return m_bIsParentFolder;
1014 }
1015
1016 const CStdString& CFileItem::GetContentType() const
1017 {
1018   if( m_contenttype.IsEmpty() )
1019   {
1020     // discard const qualifyier
1021     CStdString& m_ref = (CStdString&)m_contenttype;
1022
1023     if( m_bIsFolder )
1024       m_ref = "x-directory/normal";
1025     else if( m_strPath.Left(8).Equals("shout://")
1026           || m_strPath.Left(7).Equals("http://")
1027           || m_strPath.Left(8).Equals("https://")
1028           || m_strPath.Left(7).Equals("upnp://"))
1029     {
1030       CFileCurl::GetContent(GetAsUrl(), m_ref);
1031
1032       // make sure there are no options set in content type
1033       // content type can look like "video/x-ms-asf ; charset=utf8"
1034       int i = m_ref.Find(';');
1035       if(i>=0)
1036         m_ref.Delete(i,m_ref.length()-i);
1037       m_ref.Trim();
1038     }
1039
1040     // if it's still empty set to an unknown type
1041     if( m_ref.IsEmpty() )
1042       m_ref = "application/octet-stream";
1043   }
1044
1045   return m_contenttype;
1046 }
1047
1048 bool CFileItem::IsSamePath(const CFileItem *item) const
1049 {
1050   if (!item)
1051     return false;
1052
1053   if (item->m_strPath == m_strPath && item->m_lStartOffset == m_lStartOffset) return true;
1054   if (IsMusicDb() && HasMusicInfoTag())
1055   {
1056     CFileItem dbItem(m_musicInfoTag->GetURL(), false);
1057     dbItem.m_lStartOffset = m_lStartOffset;
1058     return dbItem.IsSamePath(item);
1059   }
1060   if (IsVideoDb() && HasVideoInfoTag())
1061   {
1062     CFileItem dbItem(m_videoInfoTag->m_strFileNameAndPath, false);
1063     dbItem.m_lStartOffset = m_lStartOffset;
1064     return dbItem.IsSamePath(item);
1065   }
1066   if (item->IsMusicDb() && item->HasMusicInfoTag())
1067   {
1068     CFileItem dbItem(item->m_musicInfoTag->GetURL(), false);
1069     dbItem.m_lStartOffset = item->m_lStartOffset;
1070     return IsSamePath(&dbItem);
1071   }
1072   if (item->IsVideoDb() && item->HasVideoInfoTag())
1073   {
1074     CFileItem dbItem(item->m_videoInfoTag->m_strFileNameAndPath, false);
1075     dbItem.m_lStartOffset = item->m_lStartOffset;
1076     return IsSamePath(&dbItem);
1077   }
1078   return false;
1079 }
1080
1081 /////////////////////////////////////////////////////////////////////////////////
1082 /////
1083 ///// CFileItemList
1084 /////
1085 //////////////////////////////////////////////////////////////////////////////////
1086
1087 CFileItemList::CFileItemList()
1088 {
1089   m_fastLookup = false;
1090   m_bIsFolder=true;
1091   m_cacheToDisc=CACHE_IF_SLOW;
1092   m_sortMethod=SORT_METHOD_NONE;
1093   m_sortOrder=SORT_ORDER_NONE;
1094   m_replaceListing = false;
1095 }
1096
1097 CFileItemList::CFileItemList(const CStdString& strPath)
1098 {
1099   m_strPath=strPath;
1100   m_fastLookup = false;
1101   m_bIsFolder=true;
1102   m_cacheToDisc=CACHE_IF_SLOW;
1103   m_sortMethod=SORT_METHOD_NONE;
1104   m_sortOrder=SORT_ORDER_NONE;
1105   m_replaceListing = false;
1106 }
1107
1108 CFileItemList::~CFileItemList()
1109 {
1110   Clear();
1111 }
1112
1113 CFileItemPtr CFileItemList::operator[] (int iItem)
1114 {
1115   return Get(iItem);
1116 }
1117
1118 const CFileItemPtr CFileItemList::operator[] (int iItem) const
1119 {
1120   return Get(iItem);
1121 }
1122
1123 CFileItemPtr CFileItemList::operator[] (const CStdString& strPath)
1124 {
1125   return Get(strPath);
1126 }
1127
1128 const CFileItemPtr CFileItemList::operator[] (const CStdString& strPath) const
1129 {
1130   return Get(strPath);
1131 }
1132
1133 void CFileItemList::SetFastLookup(bool fastLookup)
1134 {
1135   CSingleLock lock(m_lock);
1136
1137   if (fastLookup && !m_fastLookup)
1138   { // generate the map
1139     m_map.clear();
1140     for (unsigned int i=0; i < m_items.size(); i++)
1141     {
1142       CFileItemPtr pItem = m_items[i];
1143       CStdString path(pItem->m_strPath); path.ToLower();
1144       m_map.insert(MAPFILEITEMSPAIR(path, pItem));
1145     }
1146   }
1147   if (!fastLookup && m_fastLookup)
1148     m_map.clear();
1149   m_fastLookup = fastLookup;
1150 }
1151
1152 bool CFileItemList::Contains(const CStdString& fileName) const
1153 {
1154   CSingleLock lock(m_lock);
1155
1156   // checks case insensitive
1157   CStdString checkPath(fileName); checkPath.ToLower();
1158   if (m_fastLookup)
1159     return m_map.find(checkPath) != m_map.end();
1160   // slow method...
1161   for (unsigned int i = 0; i < m_items.size(); i++)
1162   {
1163     const CFileItemPtr pItem = m_items[i];
1164     if (pItem->m_strPath.Equals(checkPath))
1165       return true;
1166   }
1167   return false;
1168 }
1169
1170 void CFileItemList::Clear()
1171 {
1172   CSingleLock lock(m_lock);
1173
1174   ClearItems();
1175   m_sortMethod=SORT_METHOD_NONE;
1176   m_sortOrder=SORT_ORDER_NONE;
1177   m_cacheToDisc=CACHE_IF_SLOW;
1178   m_sortDetails.clear();
1179   m_replaceListing = false;
1180   m_content.Empty();
1181 }
1182
1183 void CFileItemList::ClearItems()
1184 {
1185   CSingleLock lock(m_lock);
1186   // make sure we free the memory of the items (these are GUIControls which may have allocated resources)
1187   FreeMemory();
1188   for (unsigned int i = 0; i < m_items.size(); i++)
1189   {
1190     CFileItemPtr item = m_items[i];
1191     item->FreeMemory();
1192   }
1193   m_items.clear();
1194   m_map.clear();
1195 }
1196
1197 void CFileItemList::Add(const CFileItemPtr &pItem)
1198 {
1199   CSingleLock lock(m_lock);
1200
1201   m_items.push_back(pItem);
1202   if (m_fastLookup)
1203   {
1204     CStdString path(pItem->m_strPath); path.ToLower();
1205     m_map.insert(MAPFILEITEMSPAIR(path, pItem));
1206   }
1207 }
1208
1209 void CFileItemList::AddFront(const CFileItemPtr &pItem, int itemPosition)
1210 {
1211   CSingleLock lock(m_lock);
1212
1213   if (itemPosition >= 0)
1214   {
1215     m_items.insert(m_items.begin()+itemPosition, pItem);
1216   }
1217   else
1218   {
1219     m_items.insert(m_items.begin()+(m_items.size()+itemPosition), pItem);
1220   }
1221   if (m_fastLookup)
1222   {
1223     CStdString path(pItem->m_strPath); path.ToLower();
1224     m_map.insert(MAPFILEITEMSPAIR(path, pItem));
1225   }
1226 }
1227
1228 void CFileItemList::Remove(CFileItem* pItem)
1229 {
1230   CSingleLock lock(m_lock);
1231
1232   for (IVECFILEITEMS it = m_items.begin(); it != m_items.end(); ++it)
1233   {
1234     if (pItem == it->get())
1235     {
1236       m_items.erase(it);
1237       if (m_fastLookup)
1238       {
1239         CStdString path(pItem->m_strPath); path.ToLower();
1240         m_map.erase(path);
1241       }
1242       break;
1243     }
1244   }
1245 }
1246
1247 void CFileItemList::Remove(int iItem)
1248 {
1249   CSingleLock lock(m_lock);
1250
1251   if (iItem >= 0 && iItem < (int)Size())
1252   {
1253     CFileItemPtr pItem = *(m_items.begin() + iItem);
1254     if (m_fastLookup)
1255     {
1256       CStdString path(pItem->m_strPath); path.ToLower();
1257       m_map.erase(path);
1258     }
1259     m_items.erase(m_items.begin() + iItem);
1260   }
1261 }
1262
1263 void CFileItemList::Append(const CFileItemList& itemlist)
1264 {
1265   CSingleLock lock(m_lock);
1266
1267   for (int i = 0; i < itemlist.Size(); ++i)
1268     Add(itemlist[i]);
1269 }
1270
1271 void CFileItemList::Assign(const CFileItemList& itemlist, bool append)
1272 {
1273   CSingleLock lock(m_lock);
1274   if (!append)
1275     Clear();
1276   Append(itemlist);
1277   m_strPath = itemlist.m_strPath;
1278   m_sortDetails = itemlist.m_sortDetails;
1279   m_replaceListing = itemlist.m_replaceListing;
1280   m_content = itemlist.m_content;
1281   m_mapProperties = itemlist.m_mapProperties;
1282   m_cacheToDisc = itemlist.m_cacheToDisc;
1283 }
1284
1285 CFileItemPtr CFileItemList::Get(int iItem)
1286 {
1287   CSingleLock lock(m_lock);
1288
1289   if (iItem > -1)
1290     return m_items[iItem];
1291
1292   return CFileItemPtr();
1293 }
1294
1295 const CFileItemPtr CFileItemList::Get(int iItem) const
1296 {
1297   CSingleLock lock(m_lock);
1298
1299   if (iItem > -1)
1300     return m_items[iItem];
1301
1302   return CFileItemPtr();
1303 }
1304
1305 CFileItemPtr CFileItemList::Get(const CStdString& strPath)
1306 {
1307   CSingleLock lock(m_lock);
1308
1309   CStdString pathToCheck(strPath); pathToCheck.ToLower();
1310   if (m_fastLookup)
1311   {
1312     IMAPFILEITEMS it=m_map.find(pathToCheck);
1313     if (it != m_map.end())
1314       return it->second;
1315
1316     return CFileItemPtr();
1317   }
1318   // slow method...
1319   for (unsigned int i = 0; i < m_items.size(); i++)
1320   {
1321     CFileItemPtr pItem = m_items[i];
1322     if (pItem->m_strPath.Equals(pathToCheck))
1323       return pItem;
1324   }
1325
1326   return CFileItemPtr();
1327 }
1328
1329 const CFileItemPtr CFileItemList::Get(const CStdString& strPath) const
1330 {
1331   CSingleLock lock(m_lock);
1332
1333   CStdString pathToCheck(strPath); pathToCheck.ToLower();
1334   if (m_fastLookup)
1335   {
1336     map<CStdString, CFileItemPtr>::const_iterator it=m_map.find(pathToCheck);
1337     if (it != m_map.end())
1338       return it->second;
1339
1340     return CFileItemPtr();
1341   }
1342   // slow method...
1343   for (unsigned int i = 0; i < m_items.size(); i++)
1344   {
1345     CFileItemPtr pItem = m_items[i];
1346     if (pItem->m_strPath.Equals(pathToCheck))
1347       return pItem;
1348   }
1349
1350   return CFileItemPtr();
1351 }
1352
1353 int CFileItemList::Size() const
1354 {
1355   CSingleLock lock(m_lock);
1356   return (int)m_items.size();
1357 }
1358
1359 bool CFileItemList::IsEmpty() const
1360 {
1361   CSingleLock lock(m_lock);
1362   return (m_items.size() <= 0);
1363 }
1364
1365 void CFileItemList::Reserve(int iCount)
1366 {
1367   CSingleLock lock(m_lock);
1368   m_items.reserve(iCount);
1369 }
1370
1371 void CFileItemList::Sort(FILEITEMLISTCOMPARISONFUNC func)
1372 {
1373   CSingleLock lock(m_lock);
1374   DWORD dwStart = GetTickCount();
1375   std::sort(m_items.begin(), m_items.end(), func);
1376   DWORD dwElapsed = GetTickCount() - dwStart;
1377   CLog::Log(LOGDEBUG,"%s, sorting took %u millis", __FUNCTION__, dwElapsed);
1378 }
1379
1380 void CFileItemList::FillSortFields(FILEITEMFILLFUNC func)
1381 {
1382   CSingleLock lock(m_lock);
1383   std::for_each(m_items.begin(), m_items.end(), func);
1384 }
1385
1386 void CFileItemList::Sort(SORT_METHOD sortMethod, SORT_ORDER sortOrder)
1387 {
1388   //  Already sorted?
1389   if (sortMethod==m_sortMethod && m_sortOrder==sortOrder)
1390     return;
1391
1392   switch (sortMethod)
1393   {
1394   case SORT_METHOD_LABEL:
1395     FillSortFields(SSortFileItem::ByLabel);
1396     break;
1397   case SORT_METHOD_LABEL_IGNORE_THE:
1398     FillSortFields(SSortFileItem::ByLabelNoThe);
1399     break;
1400   case SORT_METHOD_DATE:
1401     FillSortFields(SSortFileItem::ByDate);
1402     break;
1403   case SORT_METHOD_SIZE:
1404     FillSortFields(SSortFileItem::BySize);
1405     break;
1406   case SORT_METHOD_DRIVE_TYPE:
1407     FillSortFields(SSortFileItem::ByDriveType);
1408     break;
1409   case SORT_METHOD_TRACKNUM:
1410     FillSortFields(SSortFileItem::BySongTrackNum);
1411     break;
1412   case SORT_METHOD_EPISODE:
1413     FillSortFields(SSortFileItem::ByEpisodeNum);
1414     break;
1415   case SORT_METHOD_DURATION:
1416     FillSortFields(SSortFileItem::BySongDuration);
1417     break;
1418   case SORT_METHOD_TITLE_IGNORE_THE:
1419     FillSortFields(SSortFileItem::BySongTitleNoThe);
1420     break;
1421   case SORT_METHOD_TITLE:
1422     FillSortFields(SSortFileItem::BySongTitle);
1423     break;
1424   case SORT_METHOD_ARTIST:
1425     FillSortFields(SSortFileItem::BySongArtist);
1426     break;
1427   case SORT_METHOD_ARTIST_IGNORE_THE:
1428     FillSortFields(SSortFileItem::BySongArtistNoThe);
1429     break;
1430   case SORT_METHOD_ALBUM:
1431     FillSortFields(SSortFileItem::BySongAlbum);
1432     break;
1433   case SORT_METHOD_ALBUM_IGNORE_THE:
1434     FillSortFields(SSortFileItem::BySongAlbumNoThe);
1435     break;
1436   case SORT_METHOD_GENRE:
1437     FillSortFields(SSortFileItem::ByGenre);
1438     break;
1439   case SORT_METHOD_FILE:
1440     FillSortFields(SSortFileItem::ByFile);
1441     break;
1442   case SORT_METHOD_VIDEO_RATING:
1443     FillSortFields(SSortFileItem::ByMovieRating);
1444     break;
1445   case SORT_METHOD_VIDEO_TITLE:
1446     FillSortFields(SSortFileItem::ByMovieTitle);
1447     break;
1448   case SORT_METHOD_YEAR:
1449     FillSortFields(SSortFileItem::ByYear);
1450     break;
1451   case SORT_METHOD_PRODUCTIONCODE:
1452     FillSortFields(SSortFileItem::ByProductionCode);
1453     break;
1454   case SORT_METHOD_PROGRAM_COUNT:
1455   case SORT_METHOD_PLAYLIST_ORDER:
1456     // TODO: Playlist order is hacked into program count variable (not nice, but ok until 2.0)
1457     FillSortFields(SSortFileItem::ByProgramCount);
1458     break;
1459   case SORT_METHOD_SONG_RATING:
1460     FillSortFields(SSortFileItem::BySongRating);
1461     break;
1462   case SORT_METHOD_MPAA_RATING:
1463     FillSortFields(SSortFileItem::ByMPAARating);
1464     break;
1465   case SORT_METHOD_VIDEO_RUNTIME:
1466     FillSortFields(SSortFileItem::ByMovieRuntime);
1467     break;
1468   case SORT_METHOD_STUDIO:
1469     FillSortFields(SSortFileItem::ByStudio);
1470     break;
1471   case SORT_METHOD_STUDIO_IGNORE_THE:
1472     FillSortFields(SSortFileItem::ByStudioNoThe);
1473     break;
1474   case SORT_METHOD_FULLPATH:
1475     FillSortFields(SSortFileItem::ByFullPath);
1476     break;
1477   default:
1478     break;
1479   }
1480   if (sortMethod == SORT_METHOD_FILE)
1481     Sort(sortOrder==SORT_ORDER_ASC ? SSortFileItem::IgnoreFoldersAscending : SSortFileItem::IgnoreFoldersDescending);
1482   else if (sortMethod != SORT_METHOD_NONE)
1483     Sort(sortOrder==SORT_ORDER_ASC ? SSortFileItem::Ascending : SSortFileItem::Descending);
1484
1485   m_sortMethod=sortMethod;
1486   m_sortOrder=sortOrder;
1487 }
1488
1489 void CFileItemList::Randomize()
1490 {
1491   CSingleLock lock(m_lock);
1492   random_shuffle(m_items.begin(), m_items.end());
1493 }
1494
1495 void CFileItemList::Serialize(CArchive& ar)
1496 {
1497   CSingleLock lock(m_lock);
1498   if (ar.IsStoring())
1499   {
1500     CFileItem::Serialize(ar);
1501
1502     int i = 0;
1503     if (m_items.size() > 0 && m_items[0]->IsParentFolder())
1504       i = 1;
1505
1506     ar << (int)(m_items.size() - i);
1507
1508     ar << m_fastLookup;
1509
1510     ar << (int)m_sortMethod;
1511     ar << (int)m_sortOrder;
1512     ar << (int)m_cacheToDisc;
1513
1514     ar << (int)m_sortDetails.size();
1515     for (unsigned int j = 0; j < m_sortDetails.size(); ++j)
1516     {
1517       const SORT_METHOD_DETAILS &details = m_sortDetails[j];
1518       ar << (int)details.m_sortMethod;
1519       ar << details.m_buttonLabel;
1520       ar << details.m_labelMasks.m_strLabelFile;
1521       ar << details.m_labelMasks.m_strLabelFolder;
1522       ar << details.m_labelMasks.m_strLabel2File;
1523       ar << details.m_labelMasks.m_strLabel2Folder;
1524     }
1525
1526     ar << m_content;
1527
1528     for (; i < (int)m_items.size(); ++i)
1529     {
1530       CFileItemPtr pItem = m_items[i];
1531       ar << *pItem;
1532     }
1533   }
1534   else
1535   {
1536     CFileItemPtr pParent;
1537     if (!IsEmpty())
1538     {
1539       CFileItemPtr pItem=m_items[0];
1540       if (pItem->IsParentFolder())
1541         pParent.reset(new CFileItem(*pItem));
1542     }
1543
1544     SetFastLookup(false);
1545     Clear();
1546
1547
1548     CFileItem::Serialize(ar);
1549
1550     int iSize = 0;
1551     ar >> iSize;
1552     if (iSize <= 0)
1553       return ;
1554
1555     if (pParent)
1556     {
1557       m_items.reserve(iSize + 1);
1558       m_items.push_back(pParent);
1559     }
1560     else
1561       m_items.reserve(iSize);
1562
1563     bool fastLookup=false;
1564     ar >> fastLookup;
1565
1566     ar >> (int&)m_sortMethod;
1567     ar >> (int&)m_sortOrder;
1568     ar >> (int&)m_cacheToDisc;
1569
1570     unsigned int detailSize = 0;
1571     ar >> detailSize;
1572     for (unsigned int j = 0; j < detailSize; ++j)
1573     {
1574       SORT_METHOD_DETAILS details;
1575       ar >> (int&)details.m_sortMethod;
1576       ar >> details.m_buttonLabel;
1577       ar >> details.m_labelMasks.m_strLabelFile;
1578       ar >> details.m_labelMasks.m_strLabelFolder;
1579       ar >> details.m_labelMasks.m_strLabel2File;
1580       ar >> details.m_labelMasks.m_strLabel2Folder;
1581       m_sortDetails.push_back(details);
1582     }
1583
1584     ar >> m_content;
1585
1586     for (int i = 0; i < iSize; ++i)
1587     {
1588       CFileItemPtr pItem(new CFileItem);
1589       ar >> *pItem;
1590       Add(pItem);
1591     }
1592
1593     SetFastLookup(fastLookup);
1594   }
1595 }
1596
1597 void CFileItemList::FillInDefaultIcons()
1598 {
1599   CSingleLock lock(m_lock);
1600   for (int i = 0; i < (int)m_items.size(); ++i)
1601   {
1602     CFileItemPtr pItem = m_items[i];
1603     pItem->FillInDefaultIcon();
1604   }
1605 }
1606
1607 void CFileItemList::SetMusicThumbs()
1608 {
1609   CSingleLock lock(m_lock);
1610   //cache thumbnails directory
1611   g_directoryCache.InitMusicThumbCache();
1612
1613   for (int i = 0; i < (int)m_items.size(); ++i)
1614   {
1615     CFileItemPtr pItem = m_items[i];
1616     pItem->SetMusicThumb();
1617   }
1618
1619   g_directoryCache.ClearMusicThumbCache();
1620 }
1621
1622 int CFileItemList::GetFolderCount() const
1623 {
1624   CSingleLock lock(m_lock);
1625   int nFolderCount = 0;
1626   for (int i = 0; i < (int)m_items.size(); i++)
1627   {
1628     CFileItemPtr pItem = m_items[i];
1629     if (pItem->m_bIsFolder)
1630       nFolderCount++;
1631   }
1632
1633   return nFolderCount;
1634 }
1635
1636 int CFileItemList::GetObjectCount() const
1637 {
1638   CSingleLock lock(m_lock);
1639
1640   int numObjects = (int)m_items.size();
1641   if (numObjects && m_items[0]->IsParentFolder())
1642     numObjects--;
1643
1644   return numObjects;
1645 }
1646
1647 int CFileItemList::GetFileCount() const
1648 {
1649   CSingleLock lock(m_lock);
1650   int nFileCount = 0;
1651   for (int i = 0; i < (int)m_items.size(); i++)
1652   {
1653     CFileItemPtr pItem = m_items[i];
1654     if (!pItem->m_bIsFolder)
1655       nFileCount++;
1656   }
1657
1658   return nFileCount;
1659 }
1660
1661 int CFileItemList::GetSelectedCount() const
1662 {
1663   CSingleLock lock(m_lock);
1664   int count = 0;
1665   for (int i = 0; i < (int)m_items.size(); i++)
1666   {
1667     CFileItemPtr pItem = m_items[i];
1668     if (pItem->IsSelected())
1669       count++;
1670   }
1671
1672   return count;
1673 }
1674
1675 void CFileItemList::FilterCueItems()
1676 {
1677   CSingleLock lock(m_lock);
1678   // Handle .CUE sheet files...
1679   VECSONGS itemstoadd;
1680   CStdStringArray itemstodelete;
1681   for (int i = 0; i < (int)m_items.size(); i++)
1682   {
1683     CFileItemPtr pItem = m_items[i];
1684     if (!pItem->m_bIsFolder)
1685     { // see if it's a .CUE sheet
1686       if (pItem->IsCUESheet())
1687       {
1688         CCueDocument cuesheet;
1689         if (cuesheet.Parse(pItem->m_strPath))
1690         {
1691           VECSONGS newitems;
1692           cuesheet.GetSongs(newitems);
1693
1694           std::vector<CStdString> MediaFileVec;
1695           cuesheet.GetMediaFiles(MediaFileVec);
1696
1697           // queue the cue sheet and the underlying media file for deletion
1698           for(std::vector<CStdString>::iterator itMedia = MediaFileVec.begin(); itMedia != MediaFileVec.end(); itMedia++)
1699           {
1700             CStdString strMediaFile = *itMedia;
1701             CStdString fileFromCue = strMediaFile; // save the file from the cue we're matching against,
1702                                                    // as we're going to search for others here...
1703             bool bFoundMediaFile = CFile::Exists(strMediaFile);
1704             // queue the cue sheet and the underlying media file for deletion
1705             if (!bFoundMediaFile)
1706             {
1707               // try file in same dir, not matching case...
1708               if (Contains(strMediaFile))
1709               {
1710                 bFoundMediaFile = true;
1711               }
1712               else
1713               {
1714                 // try removing the .cue extension...
1715                 strMediaFile = pItem->m_strPath;
1716                 CUtil::RemoveExtension(strMediaFile);
1717                 CFileItem item(strMediaFile, false);
1718                 if (item.IsAudio() && Contains(strMediaFile))
1719                 {
1720                   bFoundMediaFile = true;
1721                 }
1722                 else
1723                 { // try replacing the extension with one of our allowed ones.
1724                   CStdStringArray extensions;
1725                   StringUtils::SplitString(g_stSettings.m_musicExtensions, "|", extensions);
1726                   for (unsigned int i = 0; i < extensions.size(); i++)
1727                   {
1728                     CUtil::ReplaceExtension(pItem->m_strPath, extensions[i], strMediaFile);
1729                     CFileItem item(strMediaFile, false);
1730                     if (!item.IsCUESheet() && !item.IsPlayList() && Contains(strMediaFile))
1731                     {
1732                       bFoundMediaFile = true;
1733                       break;
1734                     }
1735                   }
1736                 }
1737               }
1738             }
1739             if (bFoundMediaFile)
1740             {
1741               itemstodelete.push_back(pItem->m_strPath);
1742               itemstodelete.push_back(strMediaFile);
1743               // get the additional stuff (year, genre etc.) from the underlying media files tag.
1744               CMusicInfoTag tag;
1745               auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(strMediaFile));
1746               if (NULL != pLoader.get())
1747               {
1748                 // get id3tag
1749                 pLoader->Load(strMediaFile, tag);
1750               }
1751               // fill in any missing entries from underlying media file
1752               for (int j = 0; j < (int)newitems.size(); j++)
1753               {
1754                 CSong song = newitems[j];
1755                 // only for songs that actually match the current media file
1756                 if (song.strFileName == fileFromCue)
1757                 {
1758                   // we might have a new media file from the above matching code
1759                   song.strFileName = strMediaFile;
1760                   if (tag.Loaded())
1761                   {
1762                     if (song.strAlbum.empty() && !tag.GetAlbum().empty()) song.strAlbum = tag.GetAlbum();
1763                     if (song.strGenre.empty() && !tag.GetGenre().empty()) song.strGenre = tag.GetGenre();
1764                     if (song.strArtist.empty() && !tag.GetArtist().empty()) song.strArtist = tag.GetArtist();
1765                     SYSTEMTIME dateTime;
1766                     tag.GetReleaseDate(dateTime);
1767                     if (dateTime.wYear) song.iYear = dateTime.wYear;
1768                   }
1769                   if (!song.iDuration && tag.GetDuration() > 0)
1770                   { // must be the last song
1771                     song.iDuration = (tag.GetDuration() * 75 - song.iStartOffset + 37) / 75;
1772                   }
1773                   // add this item to the list
1774                   itemstoadd.push_back(song);
1775                 }
1776               }
1777             }
1778             else
1779             { // remove the .cue sheet from the directory
1780               itemstodelete.push_back(pItem->m_strPath);
1781             }
1782           }
1783         }
1784         else
1785         { // remove the .cue sheet from the directory (can't parse it - no point listing it)
1786           itemstodelete.push_back(pItem->m_strPath);
1787         }
1788       }
1789     }
1790   }
1791   // now delete the .CUE files and underlying media files.
1792   for (int i = 0; i < (int)itemstodelete.size(); i++)
1793   {
1794     for (int j = 0; j < (int)m_items.size(); j++)
1795     {
1796       CFileItemPtr pItem = m_items[j];
1797       if (stricmp(pItem->m_strPath.c_str(), itemstodelete[i].c_str()) == 0)
1798       { // delete this item
1799         m_items.erase(m_items.begin() + j);
1800         break;
1801       }
1802     }
1803   }
1804   // and add the files from the .CUE sheet
1805   for (int i = 0; i < (int)itemstoadd.size(); i++)
1806   {
1807     // now create the file item, and add to the item list.
1808     CFileItemPtr pItem(new CFileItem(itemstoadd[i]));
1809     m_items.push_back(pItem);
1810   }
1811 }
1812
1813 // Remove the extensions from the filenames
1814 void CFileItemList::RemoveExtensions()
1815 {
1816   CSingleLock lock(m_lock);
1817   for (int i = 0; i < Size(); ++i)
1818     m_items[i]->RemoveExtension();
1819 }
1820
1821 void CFileItemList::Stack()
1822 {
1823   CSingleLock lock(m_lock);
1824
1825   // not allowed here
1826   if (IsVirtualDirectoryRoot() || IsTV())
1827     return;
1828
1829   // items needs to be sorted for stuff below to work properly
1830   Sort(SORT_METHOD_LABEL, SORT_ORDER_ASC);
1831
1832   // stack folders
1833   bool isDVDFolder(false);
1834   int i = 0;
1835   for (i = 0; i < Size(); ++i)
1836   {
1837     CFileItemPtr item = Get(i);
1838     if (item->GetLabel().Equals("VIDEO_TS.IFO"))
1839     {
1840       isDVDFolder = true;
1841       break;
1842     }
1843     // combined the folder checks
1844     if (item->m_bIsFolder)
1845     { 
1846       // only check known fast sources?
1847       // xbms included because it supports file existance
1848       // NOTES:
1849       // 1. xbms would not have worked previously: item->m_strPath.Left(5).Equals("xbms", false)
1850       // 2. rars and zips may be on slow sources? is this supposed to be allowed?
1851       if( !item->IsRemote()
1852         || item->IsSmb()
1853         || item->m_strPath.Left(7).Equals("xbms://")
1854         || CUtil::IsInRAR(item->m_strPath)
1855         || CUtil::IsInZIP(item->m_strPath)
1856         )
1857       {
1858         // stack cd# folders if contains only a single video file
1859         // NOTE: if we're doing this anyway, why not collapse *all* folders with just a single video file?
1860         CStdString folderName = item->GetLabel();
1861         if (folderName.Left(2).Equals("CD") && StringUtils::IsNaturalNumber(folderName.Mid(2)))
1862         {
1863           CFileItemList items;
1864           CDirectory::GetDirectory(item->m_strPath,items,g_stSettings.m_videoExtensions,true);
1865           // optimized to only traverse listing once by checking for filecount
1866           // and recording last file item for later use
1867           int nFiles = 0;
1868           int index = -1;
1869           for (int j = 0; j < items.Size(); j++)
1870           {
1871             if (!items[j]->m_bIsFolder)
1872             {
1873               nFiles++;
1874               index = j;
1875             }
1876             if (nFiles > 1)
1877               break;
1878           }
1879           if (nFiles == 1)
1880           {
1881             *item = *items[index];
1882           }
1883         }
1884
1885         // check for dvd folders
1886         else
1887         {
1888           CStdString path;
1889           CStdString dvdPath;
1890           CUtil::AddFileToFolder(item->m_strPath, "VIDEO_TS.IFO", path);
1891           if (CFile::Exists(path))
1892             dvdPath = path;
1893           else
1894           {
1895             CUtil::AddFileToFolder(item->m_strPath, "VIDEO_TS", dvdPath);
1896             CUtil::AddFileToFolder(dvdPath, "VIDEO_TS.IFO", path);
1897             dvdPath.Empty();
1898             if (CFile::Exists(path))
1899               dvdPath = path;
1900           }
1901           if (!dvdPath.IsEmpty())
1902           {
1903             // NOTE: should this be done for the CD# folders too?
1904             /* set the thumbnail based on folder */
1905             item->SetCachedVideoThumb();
1906             if (!item->HasThumbnail())
1907               item->SetUserVideoThumb();
1908
1909             item->m_bIsFolder = false;
1910             item->m_strPath = dvdPath;
1911             item->SetLabel2("");
1912             item->SetLabelPreformated(true);
1913             m_sortMethod = SORT_METHOD_NONE; /* sorting is now broken */
1914
1915             /* override the previously set thumb if video_ts.ifo has any */
1916             /* otherwise user can't set icon on the stacked file as that */
1917             /* will allways be set on the video_ts.ifo file */
1918             CStdString thumb(item->GetCachedVideoThumb());
1919             if(CFile::Exists(thumb))
1920               item->SetThumbnailImage(thumb);
1921             else
1922               item->SetUserVideoThumb();
1923           }
1924         }
1925       }
1926     }
1927   }
1928
1929
1930   // now stack the files, some of which may be from the previous stack iteration
1931   i = 0;
1932   while (i < Size())
1933   {
1934     CFileItemPtr item = Get(i);
1935
1936     // skip folders, nfo files, playlists, dvd images
1937     if (item->m_bIsFolder
1938       || item->IsParentFolder()
1939       || item->IsNFO()
1940       || item->IsPlayList() 
1941       || item->IsDVDImage()
1942       )
1943     {
1944       // increment index
1945       i++;
1946       continue;
1947     }
1948
1949     if (isDVDFolder)
1950     {
1951       // remove any other ifo files in this folder
1952       if (item->IsDVDFile(false, true) && !item->GetLabel().Equals("VIDEO_TS.IFO"))
1953       {
1954         Remove(i);
1955         continue;
1956       }
1957     }
1958
1959     CStdString fileName, filePath;
1960     CUtil::Split(item->m_strPath, filePath, fileName);
1961     CStdString fileTitle, volumeNumber;
1962     // hmmm... should this use GetLabel() or fileName?
1963     if (CUtil::GetVolumeFromFileName(item->GetLabel(), fileTitle, volumeNumber))
1964     {
1965       vector<int> stack;
1966       stack.push_back(i);
1967       __int64 size = item->m_dwSize;
1968
1969       int j = i + 1;
1970       while (j < Size())
1971       {
1972         CFileItemPtr item2 = Get(j);
1973         CStdString fileName2, filePath2;
1974         CUtil::Split(item2->m_strPath, filePath2, fileName2);
1975         // only do a stacking comparison if the first letter of the filename is the same
1976         if (fileName2.size() && fileName2.at(0) != fileName.at(0))
1977           break;
1978
1979         CStdString fileTitle2, volumeNumber2;
1980         // hmmm... should this use GetLabel() or fileName2?
1981         if (CUtil::GetVolumeFromFileName(item2->GetLabel(), fileTitle2, volumeNumber2))
1982         {
1983           if (fileTitle2.Equals(fileTitle))
1984           {
1985             stack.push_back(j);
1986             size += item2->m_dwSize;
1987           }
1988         }
1989
1990         // increment index
1991         j++;
1992       }
1993
1994       if (stack.size() > 1)
1995       {
1996         // have a stack, remove the items and add the stacked item
1997         CStackDirectory dir;
1998         // dont actually stack a multipart rar set, just remove all items but the first
1999         CStdString stackPath;
2000         if (Get(stack[0])->IsRAR())
2001           stackPath = Get(stack[0])->m_strPath;
2002         else
2003           stackPath = dir.ConstructStackPath(*this, stack);
2004         item->m_strPath = stackPath;
2005         // clean up list
2006         for (unsigned int k = stack.size() - 1; k > 0; --k)
2007         {
2008           Remove(stack[k]);
2009         }
2010         // item->m_bIsFolder = true;  // don't treat stacked files as folders
2011         // the label may be in a different char set from the filename (eg over smb
2012         // the label is converted from utf8, but the filename is not)
2013         CUtil::GetVolumeFromFileName(item->GetLabel(), fileTitle, volumeNumber);
2014         if (g_guiSettings.GetBool("filelists.hideextensions"))
2015           CUtil::RemoveExtension(fileTitle);
2016         item->SetLabel(fileTitle);
2017         item->m_dwSize = size;
2018       }
2019     }
2020
2021     // increment index
2022     i++;
2023   }
2024 }
2025
2026 bool CFileItemList::Load()
2027 {
2028   CFile file;
2029   if (file.Open(GetDiscCacheFile()))
2030   {
2031     CLog::Log(LOGDEBUG,"Loading fileitems [%s]",m_strPath.c_str());
2032     CArchive ar(&file, CArchive::load);
2033     ar >> *this;
2034     CLog::Log(LOGDEBUG,"  -- items: %i, directory: %s sort method: %i, ascending: %s",Size(),m_strPath.c_str(), m_sortMethod, m_sortOrder ? "true" : "false");
2035     ar.Close();
2036     file.Close();
2037     return true;
2038   }
2039
2040   return false;
2041 }
2042
2043 bool CFileItemList::Save()
2044 {
2045   int iSize = Size();
2046   if (iSize <= 0)
2047     return false;
2048
2049   CLog::Log(LOGDEBUG,"Saving fileitems [%s]",m_strPath.c_str());
2050
2051   CFile file;
2052   if (file.OpenForWrite(GetDiscCacheFile(), true, true)) // overwrite always
2053   {
2054     CArchive ar(&file, CArchive::store);
2055     ar << *this;
2056     CLog::Log(LOGDEBUG,"  -- items: %i, sort method: %i, ascending: %s",iSize,m_sortMethod, m_sortOrder ? "true" : "false");
2057     ar.Close();
2058     file.Close();
2059     return true;
2060   }
2061
2062   return false;
2063 }
2064
2065 void CFileItemList::RemoveDiscCache() const
2066 {
2067   CLog::Log(LOGDEBUG,"Clearing cached fileitems [%s]",m_strPath.c_str());
2068   if (CFile::Exists(GetDiscCacheFile()))
2069     CFile::Delete(GetDiscCacheFile());
2070 }
2071
2072 CStdString CFileItemList::GetDiscCacheFile() const
2073 {
2074   CStdString strPath=m_strPath;
2075   CUtil::RemoveSlashAtEnd(strPath);
2076
2077   Crc32 crc;
2078   crc.ComputeFromLowerCase(strPath);
2079
2080   CStdString cacheFile;
2081   if (IsCDDA() || IsOnDVD())
2082     cacheFile.Format("Z:\\r-%08x.fi", (unsigned __int32)crc);
2083   else if (IsMusicDb())
2084     cacheFile.Format("Z:\\mdb-%08x.fi", (unsigned __int32)crc);
2085   else if (IsVideoDb())
2086     cacheFile.Format("Z:\\vdb-%08x.fi", (unsigned __int32)crc);
2087   else
2088     cacheFile.Format("Z:\\%08x.fi", (unsigned __int32)crc);
2089   return _P(cacheFile);
2090 }
2091
2092 bool CFileItemList::AlwaysCache() const
2093 {
2094   // some database folders are always cached
2095   if (IsMusicDb())
2096     return CMusicDatabaseDirectory::CanCache(m_strPath);
2097   if (IsVideoDb())
2098     return CVideoDatabaseDirectory::CanCache(m_strPath);
2099   return false;
2100 }
2101
2102 void CFileItemList::SetCachedVideoThumbs()
2103 {
2104   CSingleLock lock(m_lock);
2105   // TODO: Investigate caching time to see if it speeds things up
2106   for (unsigned int i = 0; i < m_items.size(); ++i)
2107   {
2108     CFileItemPtr pItem = m_items[i];
2109     pItem->SetCachedVideoThumb();
2110   }
2111 }
2112
2113 void CFileItemList::SetCachedProgramThumbs()
2114 {
2115   CSingleLock lock(m_lock);
2116   // TODO: Investigate caching time to see if it speeds things up
2117   for (unsigned int i = 0; i < m_items.size(); ++i)
2118   {
2119     CFileItemPtr pItem = m_items[i];
2120     pItem->SetCachedProgramThumb();
2121   }
2122 }
2123
2124 void CFileItemList::SetCachedMusicThumbs()
2125 {
2126   CSingleLock lock(m_lock);
2127   // TODO: Investigate caching time to see if it speeds things up
2128   for (unsigned int i = 0; i < m_items.size(); ++i)
2129   {
2130     CFileItemPtr pItem = m_items[i];
2131     pItem->SetCachedMusicThumb();
2132   }
2133 }
2134
2135 CStdString CFileItem::GetCachedPictureThumb() const
2136 {
2137   return GetCachedThumb(m_strPath,g_settings.GetPicturesThumbFolder(),true);
2138 }
2139
2140 void CFileItem::SetCachedMusicThumb()
2141 {
2142   // if it already has a thumbnail, then return
2143   if (HasThumbnail() || m_bIsShareOrDrive) return ;
2144
2145   // streams do not have thumbnails
2146   if (IsInternetStream()) return ;
2147
2148   //  music db items already have thumbs or there is no thumb available
2149   if (IsMusicDb()) return;
2150
2151   // ignore the parent dir items
2152   if (IsParentFolder()) return;
2153
2154   CStdString cachedThumb(GetPreviouslyCachedMusicThumb());
2155   if (!cachedThumb.IsEmpty())
2156     SetThumbnailImage(cachedThumb);
2157     // SetIconImage(cachedThumb);
2158 }
2159
2160 CStdString CFileItem::GetPreviouslyCachedMusicThumb() const
2161 {
2162   // look if an album thumb is available,
2163   // could be any file with tags loaded or
2164   // a directory in album window
2165   CStdString strAlbum, strArtist;
2166   if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
2167   {
2168     strAlbum = m_musicInfoTag->GetAlbum();
2169     if (!m_musicInfoTag->GetAlbumArtist().IsEmpty())
2170       strArtist = m_musicInfoTag->GetAlbumArtist();
2171     else
2172       strArtist = m_musicInfoTag->GetArtist();
2173   }
2174   if (!strAlbum.IsEmpty() && !strArtist.IsEmpty())
2175   {
2176     // try permanent album thumb (Q:\userdata\thumbnails\music)
2177     // using "album name + artist name"
2178     CStdString thumb(CUtil::GetCachedAlbumThumb(strAlbum, strArtist));
2179     if (CFile::Exists(thumb))
2180       return thumb;
2181   }
2182
2183   // if a file, try to find a cached filename.tbn
2184   if (!m_bIsFolder)
2185   {
2186     // look for locally cached tbn
2187     CStdString thumb(CUtil::GetCachedMusicThumb(m_strPath));
2188     if (CFile::Exists(thumb))
2189       return thumb;
2190   }
2191
2192   // try and find a cached folder thumb (folder.jpg or folder.tbn)
2193   CStdString strPath;
2194   if (!m_bIsFolder)
2195     CUtil::GetDirectory(m_strPath, strPath);
2196   else
2197     strPath = m_strPath;
2198   // music thumbs are cached without slash at end
2199   CUtil::RemoveSlashAtEnd(strPath);
2200
2201   CStdString thumb(CUtil::GetCachedMusicThumb(strPath));
2202   if (CFile::Exists(thumb))
2203     return thumb;
2204
2205   return "";
2206 }
2207
2208 CStdString CFileItem::GetUserMusicThumb(bool alwaysCheckRemote /* = false */) const
2209 {
2210   if (m_strPath.IsEmpty() || m_bIsShareOrDrive || IsInternetStream() || CUtil::IsUPnP(m_strPath) || IsParentFolder() || IsMusicDb())
2211     return "";
2212
2213   // check <filename>.tbn or <foldername>.tbn
2214   CStdString fileThumb(GetTBNFile());
2215   if (CFile::Exists(fileThumb))
2216     return fileThumb;
2217
2218   // if folder, check for folder image (defined in m_musicThumbs)
2219   if (m_bIsFolder && (!IsRemote() || alwaysCheckRemote || g_guiSettings.GetBool("musicfiles.findremotethumbs")))
2220   {
2221     std::vector<CStdString> vecMusicThumbs;
2222     StringUtils::SplitString(g_advancedSettings.m_musicThumbs, "|", vecMusicThumbs);
2223     
2224     CStdString strDir;
2225     CUtil::GetDirectory(m_strPath, strDir);
2226
2227     CFileItemList items;
2228     CDirectory::GetDirectory(strDir, items, g_stSettings.m_pictureExtensions, false, false, false, false);
2229
2230     for (int i = 0; i < items.Size(); ++i)
2231     {
2232       CFileItemPtr pItem = items[i];
2233       if ((!pItem->IsPlayList()) && (!pItem->m_bIsFolder))
2234       {
2235         if (find(vecMusicThumbs.begin(),vecMusicThumbs.end(),pItem->m_strPath) == vecMusicThumbs.end())
2236         {
2237           return pItem->m_strPath.c_str();
2238         }
2239       }
2240     }
2241   }
2242
2243   // this adds support for files which inherit a folder.jpg icon which has not been cached yet.
2244   // this occurs when queueing a top-level folder which has not been traversed yet.
2245   else if (!IsRemote() || alwaysCheckRemote || g_guiSettings.GetBool("musicfiles.findremotethumbs"))
2246   {
2247     CStdString strFolder, strFile;
2248     CUtil::Split(m_strPath, strFolder, strFile);
2249     CFileItem folderItem(strFolder, true);
2250     folderItem.SetMusicThumb(alwaysCheckRemote);
2251     if (folderItem.HasThumbnail())
2252       return folderItem.GetThumbnailImage();
2253   }
2254
2255   // No thumb found
2256   return "";
2257 }
2258
2259 void CFileItem::SetUserMusicThumb(bool alwaysCheckRemote /* = false */)
2260 {
2261   // caches as the local thumb
2262   CStdString thumb(GetUserMusicThumb(alwaysCheckRemote));
2263   if (!thumb.IsEmpty())
2264   {
2265     CStdString cachedThumb(CUtil::GetCachedMusicThumb(m_strPath));
2266     CPicture pic;
2267     pic.DoCreateThumbnail(thumb, cachedThumb);
2268   }
2269
2270   SetCachedMusicThumb();
2271 }
2272
2273 void CFileItem::SetCachedPictureThumb()
2274 {
2275   if (IsParentFolder()) return;
2276   CStdString cachedThumb(GetCachedPictureThumb());
2277   if (CFile::Exists(cachedThumb))
2278     SetThumbnailImage(cachedThumb);
2279 }
2280
2281 CStdString CFileItem::GetCachedVideoThumb() const
2282 {
2283   if (IsStack())
2284     return GetCachedThumb(CStackDirectory::GetFirstStackedFile(m_strPath),g_settings.GetVideoThumbFolder(),true);
2285   else
2286     return GetCachedThumb(m_strPath,g_settings.GetVideoThumbFolder(),true);
2287 }
2288
2289 CStdString CFileItem::GetCachedEpisodeThumb() const
2290 {
2291   // get the locally cached thumb
2292   CStdString strCRC;
2293   strCRC.Format("%sepisode%i",GetVideoInfoTag()->m_strFileNameAndPath.c_str(),GetVideoInfoTag()->m_iEpisode);
2294   return GetCachedThumb(strCRC,g_settings.GetVideoThumbFolder(),true);
2295 }
2296
2297 void CFileItem::SetCachedVideoThumb()
2298 {
2299   if (IsParentFolder()) return;
2300   CStdString cachedThumb(GetCachedVideoThumb());
2301   if (CFile::Exists(cachedThumb))
2302     SetThumbnailImage(cachedThumb);
2303 }
2304
2305 // Gets the .tbn filename from a file or folder name.
2306 // <filename>.ext -> <filename>.tbn
2307 // <foldername>/ -> <foldername>.tbn
2308 CStdString CFileItem::GetTBNFile() const
2309 {
2310   CStdString thumbFile;
2311   CStdString strFile = m_strPath;
2312
2313   if (IsStack())
2314   {
2315     CStdString strPath;
2316     CUtil::GetParentPath(m_strPath,strPath);
2317     CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
2318     CStdString strReturn = item.GetTBNFile();
2319     if (CFile::Exists(strReturn))
2320       return strReturn;
2321
2322     CUtil::AddFileToFolder(strPath,CUtil::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)),strFile);
2323   }
2324
2325   if (CUtil::IsInRAR(strFile) || CUtil::IsInZIP(strFile))
2326   {
2327     CStdString strPath, strParent;
2328     CUtil::GetDirectory(strFile,strPath);
2329     CUtil::GetParentPath(strPath,strParent);
2330     CUtil::AddFileToFolder(strParent,CUtil::GetFileName(m_strPath),strFile);
2331   }
2332
2333   if (m_bIsFolder && !IsFileFolder())
2334     CUtil::RemoveSlashAtEnd(strFile);
2335
2336   CUtil::ReplaceExtension(strFile, ".tbn", thumbFile);
2337   return thumbFile;
2338 }
2339
2340 CStdString CFileItem::GetUserVideoThumb() const
2341 {
2342   if (m_strPath.IsEmpty() || m_bIsShareOrDrive || IsInternetStream() || CUtil::IsFTP(m_strPath) || CUtil::IsUPnP(m_strPath) || IsParentFolder() || IsVTP())
2343     return "";
2344
2345   if (IsTuxBox())
2346   {
2347     if (!m_bIsFolder)
2348       return g_tuxbox.GetPicon(GetLabel());
2349     else return "";
2350   }
2351
2352   // check <filename>.tbn or <foldername>.tbn
2353   CStdString fileThumb(GetTBNFile());
2354   if (CFile::Exists(fileThumb))
2355     return fileThumb;
2356
2357   // check movie.tbn, as long as it's not a folder
2358   if (!m_bIsFolder)
2359   {
2360     CStdString strPath, movietbnFile;
2361     CUtil::GetParentPath(m_strPath, strPath);
2362     CUtil::AddFileToFolder(strPath, "movie.tbn", movietbnFile);
2363     if (CFile::Exists(movietbnFile))
2364       return movietbnFile;
2365   }
2366
2367   // if folder, check for folder image (defined in m_dvdThumbs)
2368   if (m_bIsFolder)
2369   {
2370     std::vector<CStdString> vecVideoThumbs;
2371     StringUtils::SplitString(g_advancedSettings.m_dvdThumbs, "|", vecVideoThumbs);
2372     
2373     CStdString strDir;
2374     CUtil::GetDirectory(m_strPath, strDir);
2375
2376     CFileItemList items;
2377     CDirectory::GetDirectory(strDir, items, g_stSettings.m_pictureExtensions, false, false, false, false);
2378
2379     for (int i = 0; i < items.Size(); ++i)
2380     {
2381       CFileItemPtr pItem = items[i];
2382       if (!pItem->m_bIsFolder)
2383       {
2384         if (find(vecVideoThumbs.begin(),vecVideoThumbs.end(),pItem->m_strPath) == vecVideoThumbs.end())
2385         {
2386           return pItem->m_strPath.c_str();
2387         }
2388       }
2389     }
2390   }
2391
2392   // No thumb found
2393   return "";
2394 }
2395
2396 CStdString CFileItem::GetFolderThumb(const CStdString &folderJPG /* = "folder.jpg" */) const
2397 {
2398   CStdString folderThumb;
2399   CStdString strFolder = m_strPath;
2400
2401   if (IsStack())
2402   {
2403     CStdString strPath;
2404     CUtil::GetParentPath(m_strPath,strPath);
2405     CStdString strFolder = CStackDirectory::GetStackedTitlePath(m_strPath);
2406   }
2407
2408   if (CUtil::IsInRAR(strFolder) || CUtil::IsInZIP(strFolder))
2409   {
2410     CStdString strPath, strParent;
2411     CUtil::GetDirectory(strFolder,strPath);
2412     CUtil::GetParentPath(strPath,strParent);
2413   }
2414
2415   if (IsMultiPath())
2416     strFolder = CMultiPathDirectory::GetFirstPath(m_strPath);
2417   
2418   CUtil::AddFileToFolder(strFolder, folderJPG, folderThumb);
2419   return folderThumb;
2420 }
2421
2422 void CFileItem::SetVideoThumb()
2423 {
2424   if (HasThumbnail()) return;
2425   SetCachedVideoThumb();
2426   if (!HasThumbnail())
2427     SetUserVideoThumb();
2428 }
2429
2430 void CFileItem::SetUserVideoThumb()
2431 {
2432   if (m_bIsShareOrDrive) return;
2433   if (IsParentFolder()) return;
2434
2435   // caches as the local thumb
2436   CStdString thumb(GetUserVideoThumb());
2437   if (!thumb.IsEmpty())
2438   {
2439     CStdString cachedThumb(GetCachedVideoThumb());
2440     CPicture pic;
2441     pic.DoCreateThumbnail(thumb, cachedThumb);
2442   }
2443   SetCachedVideoThumb();
2444 }
2445
2446 ///
2447 /// If a cached fanart image already exists, then we're fine.  Otherwise, we look for a local fanart.jpg
2448 /// and cache that image as our fanart.
2449 CStdString CFileItem::CacheFanart(bool probe) const
2450 {
2451   if (IsVideoDb())
2452   {
2453     if (!HasVideoInfoTag())
2454       return ""; // nothing can be done
2455     CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
2456     return dbItem.CacheFanart();
2457   }
2458
2459   CStdString cachedFanart(GetCachedFanart());
2460   if (!probe)
2461   {
2462     // first check for an already cached fanart image
2463     if (CFile::Exists(cachedFanart))
2464       return "";
2465   }
2466
2467   CStdString strFile = m_strPath;
2468   if (IsStack())
2469   {
2470     CStdString strPath;
2471     CUtil::GetParentPath(m_strPath,strPath);
2472     CStackDirectory dir;
2473     CStdString strPath2;
2474     strPath2 = dir.GetStackedTitlePath(strFile);
2475     CUtil::AddFileToFolder(strPath,CUtil::GetFileName(strPath2),strFile);
2476   }
2477   if (CUtil::IsInRAR(strFile) || CUtil::IsInZIP(strFile))
2478   {
2479     CStdString strPath, strParent;
2480     CUtil::GetDirectory(strFile,strPath);
2481     CUtil::GetParentPath(strPath,strParent);
2482     CUtil::AddFileToFolder(strParent,CUtil::GetFileName(m_strPath),strFile);
2483   }
2484   
2485   // no local fanart available for these
2486   if (IsInternetStream() || CUtil::IsUPnP(strFile) || IsTV() || IsPluginFolder())
2487     return "";
2488
2489   // we don't have a cached image, so let's see if the user has a local image ..
2490   bool bFoundFanart = false;
2491   CStdString localFanart;
2492   CStdString strDir;
2493   CUtil::GetDirectory(strFile, strDir);
2494   CFileItemList items;
2495   CDirectory::GetDirectory(strDir, items, g_stSettings.m_pictureExtensions, true, false, false, false);
2496   CUtil::RemoveExtension(strFile);
2497   strFile += "-fanart";
2498   CStdString strFile2 = CUtil::AddFileToFolder(strDir, "fanart");
2499
2500   for (int i = 0; i < items.Size(); i++)
2501   {
2502     CStdString strCandidate = items[i]->m_strPath;
2503     CUtil::RemoveExtension(strCandidate);
2504     if (strCandidate == strFile || strCandidate == strFile2)
2505     {
2506       bFoundFanart = true;
2507       localFanart = items[i]->m_strPath;
2508       break;
2509     }
2510   }
2511   
2512   // no local fanart found
2513   if(!bFoundFanart)
2514     return "";
2515
2516   if (!probe)
2517   {
2518     CPicture pic;
2519     pic.CacheImage(localFanart, cachedFanart);
2520   }
2521
2522   return localFanart;
2523 }
2524
2525 CStdString CFileItem::GetCachedFanart() const
2526 {
2527   // get the locally cached thumb
2528   if (IsVideoDb())
2529   {
2530     if (!HasVideoInfoTag())
2531       return "";
2532     if (!GetVideoInfoTag()->m_strArtist.IsEmpty())
2533       return GetCachedThumb(GetVideoInfoTag()->m_strArtist,g_settings.GetMusicFanartFolder());
2534     return GetCachedThumb(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath,g_settings.GetVideoFanartFolder());
2535   }
2536   if (HasMusicInfoTag())
2537     return GetCachedThumb(GetMusicInfoTag()->GetArtist(),g_settings.GetMusicFanartFolder());
2538
2539   return GetCachedThumb(m_strPath,g_settings.GetVideoFanartFolder());
2540 }
2541
2542 CStdString CFileItem::GetCachedThumb(const CStdString &path, const CStdString &path2, bool split)
2543 {
2544   // get the locally cached thumb
2545   Crc32 crc;
2546   crc.ComputeFromLowerCase(path);
2547
2548   CStdString thumb;
2549   if (split)
2550   {
2551     CStdString hex;
2552     hex.Format("%08x", (__int32)crc);
2553     thumb.Format("%s\\%c\\%08x.tbn", path2.c_str(), hex[0], (unsigned __int32)crc);
2554   }
2555   else
2556     thumb.Format("%s\\%08x.tbn", path2.c_str(),(unsigned __int32)crc);
2557
2558   return _P(thumb);
2559 }
2560
2561 CStdString CFileItem::GetCachedProgramThumb() const
2562 {
2563   return GetCachedThumb(m_strPath,g_settings.GetProgramsThumbFolder());
2564 }
2565
2566 CStdString CFileItem::GetCachedGameSaveThumb() const
2567 {
2568   return "";
2569 }
2570
2571 void CFileItem::SetCachedProgramThumb()
2572 {
2573   // don't set any thumb for programs on DVD, as they're bound to be named the
2574   // same (D:\default.xbe).
2575   if (IsParentFolder()) return;
2576   CStdString thumb(GetCachedProgramThumb());
2577   if (CFile::Exists(thumb))
2578     SetThumbnailImage(thumb);
2579 }
2580
2581 void CFileItem::SetUserProgramThumb()
2582 {
2583   if (m_bIsShareOrDrive) return;
2584   if (IsParentFolder()) return;
2585
2586   if (IsShortCut())
2587   {
2588     CShortcut shortcut;
2589     if ( shortcut.Create( m_strPath ) )
2590     {
2591       // use the shortcut's thumb
2592       if (!shortcut.m_strThumb.IsEmpty())
2593         m_strThumbnailImage = shortcut.m_strThumb;
2594       else
2595       {
2596         CFileItem item(shortcut.m_strPath,false);
2597         item.SetUserProgramThumb();
2598         m_strThumbnailImage = item.m_strThumbnailImage;
2599       }
2600       return;
2601     }
2602   }
2603   // 1.  Try <filename>.tbn
2604   CStdString fileThumb(GetTBNFile());
2605   CStdString thumb(GetCachedProgramThumb());
2606   if (CFile::Exists(fileThumb))
2607   { // cache
2608     CPicture pic;
2609     if (pic.DoCreateThumbnail(fileThumb, thumb))
2610       SetThumbnailImage(thumb);
2611   }
2612   else if (m_bIsFolder)
2613   {
2614     // 3. cache the folder image
2615     CStdString folderThumb(GetFolderThumb());
2616     if (CFile::Exists(folderThumb))
2617     {
2618       CPicture pic;
2619       if (pic.DoCreateThumbnail(folderThumb, thumb))
2620         SetThumbnailImage(thumb);
2621     }
2622   }
2623 }
2624
2625 /*void CFileItem::SetThumb()
2626 {
2627   // we need to know the type of file at this point
2628   // as differing views have differing inheritance rules for thumbs:
2629
2630   // Videos:
2631   // Folders only use <foldername>/folder.jpg or <foldername>.tbn
2632   // Files use <filename>.tbn
2633   //  * Thumbs are cached from here using file or folder path
2634
2635   // Music:
2636   // Folders only use <foldername>/folder.jpg or <foldername>.tbn
2637   // Files use <filename>.tbn or the album/path cached thumb or inherit from the folder
2638   //  * Thumbs are cached from here using file or folder path
2639
2640   // Programs:
2641   // Folders only use <foldername>/folder.jpg or <foldername>.tbn
2642   // Files use <filename>.tbn or the embedded xbe.  Shortcuts have the additional step of the <thumbnail> tag to check
2643   //  * Thumbs are cached from here using file or folder path
2644
2645   // Pictures:
2646   // Folders use <foldername>/folder.jpg or <foldername>.tbn, or auto-generated from 4 images in the folder
2647   // Files use <filename>.tbn or a resized version of the picture
2648   //  * Thumbs are cached from here using file or folder path
2649
2650 }*/
2651
2652 void CFileItemList::SetProgramThumbs()
2653 {
2654   // TODO: Is there a speed up if we cache the program thumbs first?
2655   for (unsigned int i = 0; i < m_items.size(); i++)
2656   {
2657     CFileItemPtr pItem = m_items[i];
2658     if (pItem->IsParentFolder())
2659       continue;
2660     pItem->SetCachedProgramThumb();
2661     if (!pItem->HasThumbnail())
2662       pItem->SetUserProgramThumb();
2663   }
2664 }
2665
2666 bool CFileItem::LoadMusicTag()
2667 {
2668   // not audio
2669   if (!IsAudio())
2670     return false;
2671   // already loaded?
2672   if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
2673     return true;
2674   // check db
2675   CMusicDatabase musicDatabase;
2676   if (musicDatabase.Open())
2677   {
2678     CSong song;
2679     if (musicDatabase.GetSongByFileName(m_strPath, song))
2680     {
2681       GetMusicInfoTag()->SetSong(song);
2682       SetThumbnailImage(song.strThumb);
2683       return true;
2684     }
2685     musicDatabase.Close();
2686   }
2687   // load tag from file
2688   CLog::Log(LOGDEBUG, "%s: loading tag information for file: %s", __FUNCTION__, m_strPath.c_str());
2689   CMusicInfoTagLoaderFactory factory;
2690   auto_ptr<IMusicInfoTagLoader> pLoader (factory.CreateLoader(m_strPath));
2691   if (NULL != pLoader.get())
2692   {
2693     if (pLoader->Load(m_strPath, *GetMusicInfoTag()))
2694       return true;
2695   }
2696   // no tag - try some other things
2697   if (IsCDDA())
2698   {
2699     // we have the tracknumber...
2700     int iTrack = GetMusicInfoTag()->GetTrackNumber();
2701     if (iTrack >= 1)
2702     {
2703       CStdString strText = g_localizeStrings.Get(554); // "Track"
2704       if (strText.GetAt(strText.size() - 1) != ' ')
2705         strText += " ";
2706       CStdString strTrack;
2707       strTrack.Format(strText + "%i", iTrack);
2708       GetMusicInfoTag()->SetTitle(strTrack);
2709       GetMusicInfoTag()->SetLoaded(true);
2710       return true;
2711     }
2712   }
2713   else
2714   {
2715     CStdString fileName = CUtil::GetFileName(m_strPath);
2716     CUtil::RemoveExtension(fileName);
2717     for (unsigned int i = 0; i < g_advancedSettings.m_musicTagsFromFileFilters.size(); i++)
2718     {
2719       CLabelFormatter formatter(g_advancedSettings.m_musicTagsFromFileFilters[i], "");
2720       if (formatter.FillMusicTag(fileName, GetMusicInfoTag()))
2721       {
2722         GetMusicInfoTag()->SetLoaded(true);
2723         return true;
2724       }
2725     }
2726   }
2727   return false;
2728 }
2729
2730 void CFileItem::SetCachedGameSavesThumb()
2731 {
2732   if (IsParentFolder()) return;
2733   CStdString thumb(GetCachedGameSaveThumb());
2734   if (CFile::Exists(thumb))
2735     SetThumbnailImage(thumb);
2736 }
2737
2738 void CFileItemList::SetCachedGameSavesThumbs()
2739 {
2740   // TODO: Investigate caching time to see if it speeds things up
2741   for (unsigned int i = 0; i < m_items.size(); ++i)
2742   {
2743     CFileItemPtr pItem = m_items[i];
2744     pItem->SetCachedGameSavesThumb();
2745   }
2746 }
2747
2748 void CFileItemList::SetGameSavesThumbs()
2749 {
2750   // No User thumbs
2751   // TODO: Is there a speed up if we cache the program thumbs first?
2752   for (unsigned int i = 0; i < m_items.size(); i++)
2753   {
2754     CFileItemPtr pItem = m_items[i];
2755     if (pItem->IsParentFolder())
2756       continue;
2757     pItem->SetCachedGameSavesThumb();  // was  pItem->SetCachedProgramThumb(); oringally
2758   }
2759 }
2760
2761 void CFileItemList::Swap(unsigned int item1, unsigned int item2)
2762 {
2763   if (item1 != item2 && item1 < m_items.size() && item2 < m_items.size())
2764     std::swap(m_items[item1], m_items[item2]);
2765 }
2766
2767 void CFileItemList::UpdateItem(const CFileItem *item)
2768 {
2769   if (!item) return;
2770   CFileItemPtr oldItem = Get(item->m_strPath);
2771   if (oldItem)
2772     *oldItem = *item;
2773 }
2774
2775 void CFileItemList::AddSortMethod(SORT_METHOD sortMethod, int buttonLabel, const LABEL_MASKS &labelMasks)
2776 {
2777   SORT_METHOD_DETAILS sort;
2778   sort.m_sortMethod=sortMethod;
2779   sort.m_buttonLabel=buttonLabel;
2780   sort.m_labelMasks=labelMasks;
2781
2782   m_sortDetails.push_back(sort);
2783 }
2784
2785 void CFileItemList::SetReplaceListing(bool replace)
2786 {
2787   m_replaceListing = replace;
2788 }
2789
2790 void CFileItemList::ClearSortState()
2791 {
2792   m_sortMethod=SORT_METHOD_NONE;
2793   m_sortOrder=SORT_ORDER_NONE;
2794 }
2795
2796 CVideoInfoTag* CFileItem::GetVideoInfoTag()
2797 {
2798   if (!m_videoInfoTag)
2799     m_videoInfoTag = new CVideoInfoTag;
2800
2801   return m_videoInfoTag;
2802 }
2803
2804 CPictureInfoTag* CFileItem::GetPictureInfoTag()
2805 {
2806   if (!m_pictureInfoTag)
2807     m_pictureInfoTag = new CPictureInfoTag;
2808
2809   return m_pictureInfoTag;
2810 }
2811
2812 MUSIC_INFO::CMusicInfoTag* CFileItem::GetMusicInfoTag()
2813 {
2814   if (!m_musicInfoTag)
2815     m_musicInfoTag = new MUSIC_INFO::CMusicInfoTag;
2816
2817   return m_musicInfoTag;
2818 }
2819
2820 CStdString CFileItem::FindTrailer() const
2821 {
2822   CStdString strTrailer;
2823   CStdString strFile = m_strPath;
2824   if (IsStack())
2825   {
2826     CStdString strPath;
2827     CUtil::GetParentPath(m_strPath,strPath);
2828     CStackDirectory dir;
2829     CStdString strPath2;
2830     strPath2 = dir.GetStackedTitlePath(strFile);
2831     CUtil::AddFileToFolder(strPath,CUtil::GetFileName(strPath2),strFile);
2832   }
2833   if (CUtil::IsInRAR(strFile) || CUtil::IsInZIP(strFile))
2834   {
2835     CStdString strPath, strParent;
2836     CUtil::GetDirectory(strFile,strPath);
2837     CUtil::GetParentPath(strPath,strParent);
2838     CUtil::AddFileToFolder(strParent,CUtil::GetFileName(m_strPath),strFile);
2839   }
2840
2841   // no local trailer available for these
2842   if (IsInternetStream() || CUtil::IsUPnP(strFile) || IsTV() || IsPluginFolder())
2843     return strTrailer;
2844   
2845   CStdString strDir;
2846   CUtil::GetDirectory(strFile, strDir);
2847   CFileItemList items;
2848   CDirectory::GetDirectory(strDir, items, g_stSettings.m_videoExtensions, true, false, false, false);
2849   CUtil::RemoveExtension(strFile);
2850   strFile += "-trailer";
2851   CStdString strFile2 = CUtil::AddFileToFolder(strDir, "movie-trailer");
2852
2853   for (int i = 0; i < items.Size(); i++)
2854   {
2855     CStdString strCandidate = items[i]->m_strPath;
2856     CUtil::RemoveExtension(strCandidate);
2857     if (strCandidate == strFile || strCandidate == strFile2)
2858     {
2859       strTrailer = items[i]->m_strPath;
2860       break;
2861     }
2862   }
2863   
2864   return strTrailer;
2865 }
2866