Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Refactoring and cleanup.

  • Loading branch information...
commit b0d50c77a2dfb4c6e4a1aba8f3c71196e324aaf6 1 parent 5101668
psyton authored
View
15,260 XBMC.xcodeproj/project.pbxproj
7,649 additions, 7,611 deletions not shown
View
4,583 project/VS2010Express/XBMC.vcxproj
2,298 additions, 2,285 deletions not shown
View
10,482 project/VS2010Express/XBMC.vcxproj.filters
5,264 additions, 5,218 deletions not shown
View
495 xbmc/CueDocument.cpp
@@ -1,495 +0,0 @@
-/*
- * Copyright (C) 2005-2008 Team XBMC
- * http://www.xbmc.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- */
-
-////////////////////////////////////////////////////////////////////////////////////
-// Class: CueDocument
-// This class handles the .cue file format. This is produced by programs such as
-// EAC and CDRwin when one extracts audio data from a CD as a continuous .WAV
-// containing all the audio tracks in one big file. The .cue file contains all the
-// track and timing information. An example file is:
-//
-// PERFORMER "Pink Floyd"
-// TITLE "The Dark Side Of The Moon"
-// FILE "The Dark Side Of The Moon.mp3" WAVE
-// TRACK 01 AUDIO
-// TITLE "Speak To Me / Breathe"
-// PERFORMER "Pink Floyd"
-// INDEX 00 00:00:00
-// INDEX 01 00:00:32
-// TRACK 02 AUDIO
-// TITLE "On The Run"
-// PERFORMER "Pink Floyd"
-// INDEX 00 03:58:72
-// INDEX 01 04:00:72
-// TRACK 03 AUDIO
-// TITLE "Time"
-// PERFORMER "Pink Floyd"
-// INDEX 00 07:31:70
-// INDEX 01 07:33:70
-//
-// etc.
-//
-// The CCueDocument class member functions extract this information, and construct
-// the playlist items needed to seek to a track directly. This works best on CBR
-// compressed files - VBR files do not seek accurately enough for it to work well.
-//
-////////////////////////////////////////////////////////////////////////////////////
-
-#include "CueDocument.h"
-#include "utils/log.h"
-#include "utils/URIUtils.h"
-#include "utils/StringUtils.h"
-#include "utils/CharsetConverter.h"
-#include "filesystem/File.h"
-#include "filesystem/Directory.h"
-#include "FileItem.h"
-#include "settings/AdvancedSettings.h"
-#include "filesystem/File.h"
-#include "music/tags/MusicInfoTag.h"
-
-#include <set>
-
-using namespace std;
-using namespace XFILE;
-
-class FileCueReader
- : public CueReader
-{
- CFile m_file;
- bool m_opened;
- char m_szBuffer[1024];
-public:
- FileCueReader(const CStdString &strFile)
- {
- m_opened = m_file.Open(strFile);
- }
- virtual bool ReadNextLine(CStdString &szLine)
- {
- char *pos;
- // Read the next line.
- while (m_file.ReadString(m_szBuffer, 1023)) // Bigger than MAX_PATH_SIZE, for usage with relax!
- {
- // Remove the white space at the beginning of the line.
- pos = m_szBuffer;
- while (pos && skipChar(*pos)) pos++;
- if (pos)
- {
- szLine = pos;
- return true;
- }
- // If we are here, we have an empty line so try the next line
- }
- return false;
- }
- ~FileCueReader()
- {
- if (m_opened)
- m_file.Close();
- }
-};
-
-class TagCueReader
- : public CueReader
-{
- CStdString m_data;
- unsigned int m_currentPos;
-public:
- TagCueReader(const CStdString &cueData)
- : m_data(cueData)
- , m_currentPos(0)
- {
- }
- virtual bool ReadNextLine(CStdString &line)
- {
- // Read the next line.
- line = "";
- bool stop = false;
- while (m_currentPos < m_data.length())
- {
- // Remove the white space at the beginning of the line.
- char ch = m_data.at(m_currentPos++);
- stop |= (!skipChar(ch));
- if (stop)
- {
- if (ch == '\r' || ch == '\n')
- {
- if (!line.IsEmpty())
- return true;
- }
- else
- line += ch;
- }
- }
- return false;
- }
- ~TagCueReader()
- {
- }
-};
-
-
-CCueDocument::CCueDocument(const CFileItem &fileItem)
- : m_external(true)
- , m_reader(0)
-{
- m_strArtist = "";
- m_strAlbum = "";
- m_strGenre = "";
- m_iYear = 0;
- m_replayGainAlbumPeak = 0.0f;
- m_replayGainAlbumGain = 0.0f;
- m_iTotalTracks = 0;
- m_iTrack = 0;
- m_sourcePath = fileItem.GetPath();
- m_valid = Load(fileItem);
-}
-
-CCueDocument::~CCueDocument()
-{
- delete m_reader;
-}
-
-bool CCueDocument::isValid() const
-{
- return m_valid;
-}
-
-bool CCueDocument::isExternal() const
-{
- return m_external;
-}
-
-
-////////////////////////////////////////////////////////////////////////////////////
-// Function: Load()
-// Try to load cuesheet information from file.
-////////////////////////////////////////////////////////////////////////////////////
-bool CCueDocument::Load(const CFileItem &fileItem)
-{
- if (fileItem.IsCUESheet()) // *.CUE - file
- {
- m_reader = new FileCueReader(fileItem.GetPath());
- m_external = true;
- }
- else
- {
- CStdString extension;
- URIUtils::GetExtension(fileItem.GetPath(), extension);
- if (extension.Equals((char*)".ape") ||
- extension.Equals((char*)".flac") ||
- extension.Equals((char*)".wv") ||
- extension.Equals((char*)".ogg"))
- {
- MUSIC_INFO::CMusicInfoTag tag(fileItem.GetPath());
- if (tag.hasEmbeddedCue())
- {
- m_reader = new TagCueReader(tag.GetEmbeddedCue());
- m_external = false;
- }
- }
- }
- return Parse();
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-// Function: Parse()
-// Opens the .cue file for reading, and constructs the track database information
-////////////////////////////////////////////////////////////////////////////////////
-bool CCueDocument::Parse()
-{
- if (!m_reader)
- return false;
- CStdString strLine;
- m_iTotalTracks = -1;
- CStdString strCurrentFile = "";
- bool bCurrentFileChanged = false;
- int time;
-
- // Run through the .CUE file and extract the tracks...
- while (true)
- {
- if (!m_reader->ReadNextLine(strLine))
- break;
- if (strLine.Left(7) == "INDEX 0")
- {
- if (bCurrentFileChanged)
- {
- OutputDebugString("Track split over multiple files, unsupported");
- return false;
- }
-
- // find the end of the number section
- time = ExtractTimeFromIndex(strLine);
- if (time == -1)
- { // Error!
- OutputDebugString("Mangled Time in INDEX 0x tag in CUE file!\n");
- return false;
- }
- if (m_iTotalTracks > 0) // Set the end time of the last track
- m_Track[m_iTotalTracks - 1].iEndTime = time;
-
- if (m_iTotalTracks >= 0)
- m_Track[m_iTotalTracks].iStartTime = time; // start time of the next track
- }
- else if (strLine.Left(5) == "TITLE")
- {
- if (m_iTotalTracks == -1) // No tracks yet
- ExtractQuoteInfo(strLine, m_strAlbum);
- else if (!ExtractQuoteInfo(strLine, m_Track[m_iTotalTracks].strTitle))
- {
- // lets manage tracks titles without quotes
- CStdString titleNoQuote = strLine.Mid(5);
- titleNoQuote.TrimLeft();
- if (!titleNoQuote.IsEmpty())
- {
- g_charsetConverter.unknownToUTF8(titleNoQuote);
- m_Track[m_iTotalTracks].strTitle = titleNoQuote;
- }
- }
- }
- else if (strLine.Left(9) == "PERFORMER")
- {
- if (m_iTotalTracks == -1) // No tracks yet
- ExtractQuoteInfo(strLine, m_strArtist);
- else // New Artist for this track
- ExtractQuoteInfo(strLine, m_Track[m_iTotalTracks].strArtist);
- }
- else if (strLine.Left(5) == "TRACK")
- {
- int iTrackNumber = ExtractNumericInfo(strLine.c_str() + 5);
-
- m_iTotalTracks++;
-
- CCueTrack track;
- m_Track.push_back(track);
- m_Track[m_iTotalTracks].strFile = isExternal() ? strCurrentFile : m_sourcePath;
-
- if (iTrackNumber > 0)
- m_Track[m_iTotalTracks].iTrackNumber = iTrackNumber;
- else
- m_Track[m_iTotalTracks].iTrackNumber = m_iTotalTracks + 1;
-
- bCurrentFileChanged = false;
- }
- else if (strLine.Left(4) == "FILE")
- {
- if (isExternal())
- {
- // already a file name? then the time computation will be changed
- if(strCurrentFile.size() > 0)
- bCurrentFileChanged = true;
-
- ExtractQuoteInfo(strLine, strCurrentFile);
-
- // Resolve absolute paths (if needed).
- if (strCurrentFile.length() > 0)
- ResolvePath(strCurrentFile);
- }
- }
- else if (strLine.Left(8) == "REM DATE")
- {
- int iYear = ExtractNumericInfo(strLine.c_str() + 8);
- if (iYear > 0)
- m_iYear = iYear;
- }
- else if (strLine.Left(9) == "REM GENRE")
- {
- if (!ExtractQuoteInfo(strLine, m_strGenre))
- {
- CStdString genreNoQuote = strLine.Mid(9);
- genreNoQuote.TrimLeft();
- if (!genreNoQuote.IsEmpty())
- {
- g_charsetConverter.unknownToUTF8(genreNoQuote);
- m_strGenre = genreNoQuote;
- }
- }
- }
- else if (strLine.Left(25) == "REM REPLAYGAIN_ALBUM_GAIN")
- m_replayGainAlbumGain = (float)atof(strLine.Mid(26));
- else if (strLine.Left(25) == "REM REPLAYGAIN_ALBUM_PEAK")
- m_replayGainAlbumPeak = (float)atof(strLine.Mid(26));
- else if (strLine.Left(25) == "REM REPLAYGAIN_TRACK_GAIN" && m_iTotalTracks >= 0)
- m_Track[m_iTotalTracks].replayGainTrackGain = (float)atof(strLine.Mid(26));
- else if (strLine.Left(25) == "REM REPLAYGAIN_TRACK_PEAK" && m_iTotalTracks >= 0)
- m_Track[m_iTotalTracks].replayGainTrackPeak = (float)atof(strLine.Mid(26));
- }
-
- // reset track counter to 0, and fill in the last tracks end time
- m_iTrack = 0;
- if (m_iTotalTracks >= 0)
- m_Track[m_iTotalTracks].iEndTime = 0;
- else
- OutputDebugString("No INDEX 01 tags in CUE file!\n");
-
- if (m_iTotalTracks >= 0)
- {
- m_iTotalTracks++;
- }
- return (m_iTotalTracks > 0);
-}
-
-//////////////////////////////////////////////////////////////////////////////////
-// Function:GetNextItem()
-// Returns the track information from the next item in the cuelist
-//////////////////////////////////////////////////////////////////////////////////
-void CCueDocument::GetSongs(VECSONGS &songs)
-{
- for (int i = 0; i < m_iTotalTracks; i++)
- {
- CSong song;
- if ((m_Track[i].strArtist.length() == 0) && (m_strArtist.length() > 0))
- song.artist = StringUtils::Split(m_strArtist, g_advancedSettings.m_musicItemSeparator);
- else
- song.artist = StringUtils::Split(m_Track[i].strArtist, g_advancedSettings.m_musicItemSeparator);
- song.albumArtist = StringUtils::Split(m_strArtist, g_advancedSettings.m_musicItemSeparator);
- song.strAlbum = m_strAlbum;
- song.genre = StringUtils::Split(m_strGenre, g_advancedSettings.m_musicItemSeparator);
- song.iYear = m_iYear;
- song.iTrack = m_Track[i].iTrackNumber;
- if (m_Track[i].strTitle.length() == 0) // No track information for this track!
- song.strTitle.Format("Track %2d", i + 1);
- else
- song.strTitle = m_Track[i].strTitle;
- song.strFileName = m_Track[i].strFile;
- song.iStartOffset = m_Track[i].iStartTime;
- song.iEndOffset = m_Track[i].iEndTime;
- if (song.iEndOffset)
- song.iDuration = (song.iEndOffset - song.iStartOffset + 37) / 75;
- else
- song.iDuration = 0;
- // TODO: replayGain goes here
- songs.push_back(song);
- }
-}
-
-void CCueDocument::GetMediaFiles(vector<CStdString>& mediaFiles)
-{
- set<CStdString> uniqueFiles;
- for (int i = 0; i < m_iTotalTracks; i++)
- uniqueFiles.insert(m_Track[i].strFile);
-
- for (set<CStdString>::iterator it = uniqueFiles.begin(); it != uniqueFiles.end(); it++)
- mediaFiles.push_back(*it);
-}
-
-CStdString CCueDocument::GetMediaTitle()
-{
- return m_strAlbum;
-}
-
-// Private Functions start here
-
-////////////////////////////////////////////////////////////////////////////////////
-// Function: ExtractQuoteInfo()
-// Extracts the information in quotes from the string line, returning it in quote
-////////////////////////////////////////////////////////////////////////////////////
-bool CCueDocument::ExtractQuoteInfo(const CStdString &line, CStdString &quote)
-{
- quote.Empty();
- int left = line.Find('\"');
- if (left < 0) return false;
- int right = line.Find('\"', left + 1);
- if (right < 0) return false;
- quote = line.Mid(left + 1, right - left - 1);
- g_charsetConverter.unknownToUTF8(quote);
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-// Function: ExtractTimeFromIndex()
-// Extracts the time information from the index string index, returning it as a value in
-// milliseconds.
-// Assumed format is:
-// MM:SS:FF where MM is minutes, SS seconds, and FF frames (75 frames in a second)
-////////////////////////////////////////////////////////////////////////////////////
-int CCueDocument::ExtractTimeFromIndex(const CStdString &index)
-{
- // Get rid of the index number and any whitespace
- CStdString numberTime = index.Mid(5);
- numberTime.TrimLeft();
- while (!numberTime.IsEmpty())
- {
- if (!isdigit(numberTime[0]))
- break;
- numberTime.erase(0, 1);
- }
- numberTime.TrimLeft();
- // split the resulting string
- CStdStringArray time;
- StringUtils::SplitString(numberTime, ":", time);
- if (time.size() != 3)
- return -1;
-
- int mins = atoi(time[0].c_str());
- int secs = atoi(time[1].c_str());
- int frames = atoi(time[2].c_str());
-
- return (mins*60 + secs)*75 + frames;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-// Function: ExtractNumericInfo()
-// Extracts the numeric info from the string info, returning it as an integer value
-////////////////////////////////////////////////////////////////////////////////////
-int CCueDocument::ExtractNumericInfo(const CStdString &info)
-{
- CStdString number(info);
- number.TrimLeft();
- if (number.IsEmpty() || !isdigit(number[0]))
- return -1;
- return atoi(number.c_str());
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-// Function: ResolvePath()
-// Determines whether strPath is a relative path or not, and if so, converts it to an
-// absolute path using the path information in strBase
-////////////////////////////////////////////////////////////////////////////////////
-bool CCueDocument::ResolvePath(CStdString &strPath)
-{
- CStdString strDirectory;
- URIUtils::GetDirectory(m_sourcePath, strDirectory);
-
- CStdString strFilename = strPath;
- URIUtils::GetFileName(strFilename);
-
- URIUtils::AddFileToFolder(strDirectory, strFilename, strPath);
-
- // i *hate* windows
- if (!CFile::Exists(strPath))
- {
- CFileItemList items;
- CDirectory::GetDirectory(strDirectory,items);
- for (int i=0;i<items.Size();++i)
- {
- if (items[i]->GetPath().Equals(strPath))
- {
- strPath = items[i]->GetPath();
- return true;
- }
- }
- CLog::Log(LOGERROR,"Could not find FILE referenced in cue, case sensitivity issue?");
- return false;
- }
-
- return true;
-}
View
109 xbmc/CueDocument.h
@@ -1,109 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2005-2008 Team XBMC
- * http://www.xbmc.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- */
-
-#include "music/Song.h"
-
-#define MAX_PATH_SIZE 1024
-
-namespace XFILE {
- class CFile;
-}
-
-class CFileItem;
-class CueReader
-{
- bool m_external;
-public:
- CueReader() {}
- inline bool skipChar(char ch) const
- {
- return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
- }
- virtual bool ReadNextLine(CStdString &line) = 0;
- virtual ~CueReader() {};
-};
-
-class CCueDocument
-{
- class CCueTrack
- {
- public:
- CCueTrack()
- {
- iTrackNumber = 0;
- iStartTime = 0;
- iEndTime = 0;
- replayGainTrackGain = 0.0f;
- replayGainTrackPeak = 0.0f;
- }
- CStdString strArtist;
- CStdString strTitle;
- CStdString strFile;
- int iTrackNumber;
- int iStartTime;
- int iEndTime;
- float replayGainTrackGain;
- float replayGainTrackPeak;
- };
-
-public:
- CCueDocument(const CFileItem &fileItem);
- ~CCueDocument();
- // USED
-
- bool isValid() const;
- bool isExternal() const;
- void GetSongs(VECSONGS &songs);
- CStdString GetMediaPath();
- CStdString GetMediaTitle();
- void GetMediaFiles(std::vector<CStdString>& mediaFiles);
-
-private:
- // Member variables
- CStdString m_strArtist; // album artist
- CStdString m_strAlbum; // album title
- CStdString m_strGenre; // album genre
- int m_iYear; //album year
- int m_iTrack; // current track
- int m_iTotalTracks; // total tracks
- float m_replayGainAlbumGain;
- float m_replayGainAlbumPeak;
- bool m_valid;
- bool m_external;
- CStdString m_sourcePath;
-
- CueReader* m_reader;
-
- // cuetrack array
- std::vector<CCueTrack> m_Track;
-
- bool Parse();
-
- //bool ReadNextLine(XFILE::CFile& file, CStdString &strLine);
- bool ExtractQuoteInfo(const CStdString &line, CStdString &quote);
- int ExtractTimeFromIndex(const CStdString &index);
- int ExtractNumericInfo(const CStdString &info);
- bool ResolvePath(CStdString &strPath);
-
- bool Load(const CFileItem &fileItem);
-};
View
6,113 xbmc/FileItem.cpp
3,003 additions, 3,110 deletions not shown
View
4 xbmc/cores/paplayer/PAPlayer.cpp
@@ -636,8 +636,6 @@ bool PAPlayer::QueueData(StreamInfo *si)
unsigned int added = si->m_stream->AddData(data, samples * si->m_bytesPerSample);
si->m_framesSent += added / si->m_bytesPerFrame;
- CLog::Log(LOGDEBUG, "PAPlayer::QueueData - m_frame_set %d - %d", si->m_framesSent, si->m_prepareNextAtFrame);
-
return true;
}
@@ -695,12 +693,10 @@ void PAPlayer::Pause()
void PAPlayer::SetVolume(float volume)
{
-
}
void PAPlayer::SetDynamicRangeCompression(long drc)
{
-
}
void PAPlayer::ToFFRW(int iSpeed)
View
16 xbmc/music/cue/CStdStringHash.hpp
@@ -0,0 +1,16 @@
+#pragma once
+#include "utils/StdString.h"
+#include <boost/functional/hash.hpp>
+
+
+struct CStdStringHash
+ : std::unary_function<CStdString, size_t>
+{
+ std::size_t operator()(const CStdString& str) const
+ {
+ size_t seed = 0;
+ for (int i = 0; i < str.GetLength(); ++i)
+ boost::hash_combine(seed, str.at(i));
+ return seed;
+ }
+};
View
46 xbmc/music/cue/CueMetaData.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "CueMetaData.h"
+
+const CStdString& CueMetaData::value(const CStdString& key)
+{
+ MetaFields::const_iterator it = m_data.find(key);
+ if (it != m_data.end())
+ return it->second;
+ static CStdString s_empty;
+ return s_empty;
+}
+
+void CueMetaData::insert(const CStdString& key, const CStdString& value)
+{
+ m_data.insert(MetaField(key, value));
+}
+
+const bool CueMetaData::contains(const CStdString& key) const
+{
+ return m_data.find(key) != m_data.end();
+}
+
+void CueMetaData::clear()
+{
+ m_data.clear();
+}
View
38 xbmc/music/cue/CueMetaData.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#pragma once
+#include "CStdStringHash.hpp"
+#include <boost/unordered/unordered_map.hpp>
+
+/*! Helper class for collecting meta information in parsing time.
+ */
+class CueMetaData
+{
+ typedef boost::unordered_map<CStdString, CStdString, CStdStringHash> MetaFields;
+ typedef std::pair<CStdString, CStdString> MetaField;
+ MetaFields m_data;
+public:
+ void insert(const CStdString& key, const CStdString& value);
+ const CStdString& value(const CStdString& key);
+ const bool contains(const CStdString& key) const;
+ void clear();
+};
View
423 xbmc/music/cue/CueParser.cpp
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "CueParser.h"
+#include "CueParserCallback.h"
+#include "utils/StringUtils.h"
+#include "utils/CharsetConverter.h"
+#include "settings/AdvancedSettings.h"
+#include "utils/log.h"
+
+CueParser::CueParser()
+{
+}
+
+void CueParser::reset()
+{
+ m_file.Empty();
+ m_currentTrack.reset();
+ m_currentTrack.m_trackNumber = 0;
+ m_globalData.reset();
+ m_is_va = false;
+ m_tracks.clear();
+}
+
+bool CueParser::parse(CueParserCallback& callback)
+{
+ reset();
+
+ CStdString strLine;
+ // Run through the .CUE file and extract the tracks...
+ while (true)
+ {
+ if (!callback.onDataNeeded(strLine))
+ break;
+ if (strLine.find('\n') != -1)
+ CLog::Log(LOGINFO, "Error!!!");
+
+ CStdString cmd = cutFirstWord(strLine);
+ if (cmd == "INDEX")
+ {
+ if (!onIndex(strLine))
+ {
+ OutputDebugString("CUE INDEX parsing error");
+ return false;
+ }
+ }
+ else if (cmd == "FLAGS")
+ {
+ if (!onFlags(strLine))
+ {
+ OutputDebugString("CUE FLAGS parsing error");
+ return false;
+ }
+ }
+ else if (cmd == "PREGAP")
+ {
+ if (!onPregap(strLine))
+ {
+ OutputDebugString("CUE PREGAP parsing error");
+ return false;
+ }
+ }
+ else if (cmd == "TRACK")
+ {
+ if (!onTrack(strLine))
+ {
+ OutputDebugString("CUE TRACK parsing error");
+ return false;
+ }
+ }
+ else if (cmd == "FILE")
+ {
+ if (!onFile(strLine))
+ {
+ OutputDebugString("CUE FILE parsing error");
+ return false;
+ }
+ if (!callback.onFile(m_file))
+ return false;
+ }
+ else if (cmd == "REM")
+ {
+ bool success = false;
+ CStdString name = cutFirstWord(strLine);
+ CStdString value;
+ success = extractString(strLine, value, false);
+ if (success)
+ {
+ if (name == "GENRE" || name == "DATE" || name == "DISCID" || name == "COMMENT" ||
+ name == "REPLAYGAIN_TRACK_GAIN" || name == "REPLAYGAIN_TRACK_PEAK" ||
+ name == "REPLAYGAIN_ALBUM_GAIN" || name == "REPLAYGAIN_ALBUM_PEAK")
+ {
+ success = onMeta(name, value);
+ }
+ }
+ if (!success)
+ {
+ OutputDebugString("CUE parsing error");
+ return false;
+ }
+ }
+ else
+ {
+ bool success = true;
+ CStdString value;
+ if (cmd == "SONGWRITER" || cmd == "TITLE" || cmd == "PERFORMER")
+ {
+ success = extractString(strLine ,value, true);
+ if (cmd == "PERFORMER")
+ cmd = "ARTIST";
+ if (success)
+ success = onMeta(cmd, value);
+ }
+ else if (cmd == "CATALOG" || cmd == "ISRC")
+ success = extractString(strLine ,value, false) && onMeta(cmd, value);
+ if (!success)
+ {
+ OutputDebugString("CUE parsing error");
+ return false;
+ }
+ }
+ }
+ if (m_currentTrack.m_trackNumber)
+ {
+ if (finalizeTrack())
+ {
+ m_globalData.m_meta.debug();
+ m_currentTrack.m_trackNumber = 0;
+ for (Tracks::iterator iter = m_tracks.begin(); iter != m_tracks.end(); ++iter)
+ {
+ iter->m_meta.debug();
+ CSong song;
+ // set base data
+ song.strFileName = iter->m_file;
+ song.iTrack = iter->m_trackNumber;
+ song.iStartOffset = iter->m_indexes.start();
+ song.iEndOffset = iter->m_endOffset;
+ if (song.iEndOffset)
+ song.iDuration = (song.iEndOffset - song.iStartOffset + 37) / 75; // what is 37???
+ else
+ song.iDuration = 0;
+ // set track title
+ song.strTitle = iter->m_meta.value("TITLE");
+ if (song.strTitle.length() == 0)
+ song.strTitle.Format("Track %2d", iter->m_trackNumber);
+ // set album
+ song.strAlbum = iter->m_meta.value("ALBUM");
+ if (song.strAlbum.IsEmpty())
+ song.strAlbum = m_globalData.m_meta.value("ALBUM");
+ // set artist
+ if (m_is_va)
+ {
+ CStdString globalArtist = m_globalData.m_meta.value("ARTIST");
+ CStdString localArtist = iter->m_meta.value("ARTIST");
+ if (globalArtist.GetLength())
+ {
+ song.albumArtist = StringUtils::Split(globalArtist, g_advancedSettings.m_musicItemSeparator);
+ if (localArtist.GetLength())
+ song.artist = StringUtils::Split(localArtist, g_advancedSettings.m_musicItemSeparator);
+ else
+ song.artist = song.albumArtist;
+ }
+ else
+ {
+ if (localArtist.GetLength())
+ song.artist = StringUtils::Split(localArtist, g_advancedSettings.m_musicItemSeparator);
+ }
+ }
+ song.strComment = iter->m_meta.value("COMMENT");
+ // set genre
+ CStdString tmp = m_globalData.m_meta.value("GENRE");
+ if (tmp.GetLength())
+ song.genre = StringUtils::Split(tmp, g_advancedSettings.m_musicItemSeparator);
+ // set year
+ tmp = iter->m_meta.value("DATE");
+ song.iYear = atoi(tmp.c_str());
+ if (song.iYear <= 0)
+ song.iYear = 0;
+
+ // \todo Other meta fields, replay gain???
+ if (!callback.onTrackReady(song))
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool CueParser::onMeta(const CStdString& name, const CStdString& value)
+{
+ if (!value.length() || !name.length())
+ return false;
+ if (!m_currentTrack.m_trackNumber)
+ {
+ if (name == "TITLE")
+ m_globalData.m_meta.insert("ALBUM", value);
+ else
+ {
+ if (name == "ARTIST")
+ m_albumArtist = value;
+ m_globalData.m_meta.insert(name, value);
+ m_globalData.m_meta.debug();
+ }
+ }
+ else
+ {
+ if (!m_is_va)
+ {
+ if (name == "ARTIST")
+ {
+ if (m_albumArtist.length())
+ m_is_va = !m_albumArtist.Equals(value);
+ }
+ }
+ m_currentTrack.m_meta.insert(name, value);
+ m_currentTrack.m_meta.debug();
+ }
+ return true;
+}
+
+bool CueParser::onIndex(const CStdString& strLine)
+{
+ CStdString indexStr;
+ unsigned i = 0;
+ for (; i < strLine.length() && isdigit(strLine[i]); ++i)
+ indexStr += strLine[i];
+ if (!indexStr.length())
+ return false;
+ unsigned index = atoi(indexStr.c_str());
+ if (index > 99)
+ return false;
+
+ unsigned time;
+ CStdString timeStr = strLine.Mid(i);
+ if (!extractTime(timeStr.Trim(), time))
+ return false;
+ m_currentTrack.m_indexes.setIndex(index, time);
+ return true;
+}
+
+bool CueParser::onTrack(const CStdString& strLine)
+{
+ int idx = strLine.Find("AUDIO");
+ if (idx < 0)
+ return false;
+ CStdString number = strLine.Left(idx-1).Trim();
+ unsigned i = 0;
+ for (; i < number.length() && isdigit(number[i]); ++i)
+ ;
+ if (i < number.length())
+ return false;
+ int track = atoi(number.c_str());
+ if (track < 1 || track > 99)
+ return false;
+ bool success = true;
+ if (m_currentTrack.m_trackNumber)
+ success = finalizeTrack();
+ if (success)
+ {
+ m_currentTrack.m_trackNumber = track;
+ m_currentTrack.m_file = m_file;
+ }
+ return (!m_currentTrack.m_file.IsEmpty());
+}
+
+bool CueParser::finalizeTrack()
+{
+ if (!m_currentTrack.m_indexes.isValid())
+ return false;
+ if (!m_currentTrack.m_indexes.updatePreGap(m_currentTrack.m_pregap))
+ return false;
+ if (m_currentTrack.m_file.IsEmpty())
+ return false;
+
+ Tracks::reverse_iterator last = m_tracks.rbegin();
+ if (last != m_tracks.rend())
+ last->m_endOffset = m_currentTrack.m_indexes.start() - m_currentTrack.m_indexes.pregap();
+
+ m_tracks.push_back(m_currentTrack);
+ m_currentTrack.reset();
+ return true;
+}
+
+bool CueParser::onFile(const CStdString& strLine)
+{
+ CStdString file;
+ if (extractString(strLine, file, true))
+ m_file = file;
+ return m_file.size() > 0;
+}
+
+bool CueParser::onFlags(const CStdString& strLine)
+{
+ m_globalData.m_flags = strLine;
+ return true;
+}
+
+bool CueParser::onPregap(const CStdString& strLine)
+{
+ return extractTime(strLine, m_currentTrack.m_pregap);
+}
+
+bool CueParser::extractString(const CStdString &line, CStdString &outStr, bool spaceIsError)
+{
+ outStr.Empty();
+ int left = line.Find('\"');
+ if (left >= 0)
+ {
+ int right = line.Find('\"', left + 1);
+ if (right < 0)
+ return false;
+ outStr = line.Mid(left + 1, right - left - 1);
+ }
+ else
+ {
+ if (spaceIsError && line.find(' ') >= 0)
+ return false;
+ outStr = line.Mid(0);
+ }
+ g_charsetConverter.unknownToUTF8(outStr);
+ return true;
+}
+
+bool CueParser::extractTime(const CStdString& timeStr, unsigned& time)
+{
+ CStdStringArray timePatrs;
+ StringUtils::SplitString(timeStr, ":", timePatrs);
+ unsigned i = 0;
+ for (; i < timePatrs.size(); ++i)
+ {
+ unsigned j = 0;
+ for (; j < timePatrs[i].length() && isdigit(timePatrs[i][j]); ++j)
+ ;
+ if (j < timePatrs[i].length())
+ return false;
+ }
+
+ if (i == 0)
+ return false;
+
+ CStdString frames;
+ CStdString seconds;
+ CStdString minutes;
+
+ switch (timePatrs.size())
+ {
+ case 1:
+ frames = timePatrs[0];
+ break;
+ case 2:
+ seconds = timePatrs[0];
+ frames = timePatrs[1];
+ break;
+ case 3:
+ minutes = timePatrs[0];
+ seconds = timePatrs[1];
+ frames = timePatrs[2];
+ break;
+ default:
+ return false;
+ }
+ time = 0;
+ if (frames.length())
+ time = atoi(frames.c_str());
+ if (seconds.length())
+ time += 75 * atoi(seconds.c_str());
+ if (minutes.length())
+ time += 75 * 60 * atoi(minutes.c_str());
+ return true;
+}
+
+CStdString CueParser::cutFirstWord(CStdString& inputStr)
+{
+ CStdString out;
+ int idx = inputStr.Find(' ');
+ if (idx > 0)
+ {
+ out = inputStr.Left(idx);
+ inputStr.Delete(0, idx);
+ inputStr.TrimLeft();
+ }
+ else
+ {
+ out = inputStr;
+ inputStr.Empty();
+ }
+ return out;
+}
+
+void CueParser::TrackInfo::reset()
+{
+ m_file.Empty();
+ m_meta.clear();
+ m_indexes.reset();
+ m_endOffset = 0;
+ m_pregap = 0;
+}
+
+void CueParser::GlobalInfo::reset()
+{
+ m_meta.clear();
+ m_flags.Empty();
+}
+
View
103 xbmc/music/cue/CueParser.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#pragma once
+#include "CueSheetIndexList.h"
+#include "music/Song.h"
+#include "CueMetaData.h"
+
+class CueParserCallback;
+
+/*! This class handles .cue format. The .cue-sheet contains all the
+ * track and timing information. An example file is:
+ *
+ * PERFORMER "Pink Floyd"
+ * TITLE "The Dark Side Of The Moon"
+ * PERFORMER "Pink Floyd"
+ * FILE "The Dark Side Of The Moon.mp3" WAVE
+ * TRACK 01 AUDIO
+ * TITLE "Speak To Me / Breathe"
+ * INDEX 00 00:00:00
+ * INDEX 01 00:00:32
+ * TRACK 02 AUDIO
+ * TITLE "On The Run"
+ * INDEX 00 03:58:72
+ * INDEX 01 04:00:72
+ * TRACK 03 AUDIO
+ * TITLE "Time"
+ * INDEX 00 07:31:70
+ * INDEX 01 07:33:70
+ */
+class CueParser
+{
+private:
+ struct GlobalInfo {
+ CueMetaData m_meta;
+ CStdString m_flags;
+ void reset();
+ };
+ struct TrackInfo {
+ CStdString m_file;
+ CueMetaData m_meta; // All data (artist, title, year...)
+ CueSheetIndexList m_indexes;
+ unsigned m_endOffset;
+ unsigned m_trackNumber;
+ unsigned m_pregap;
+ void reset();
+ };
+
+ typedef std::vector<TrackInfo> Tracks;
+
+ GlobalInfo m_globalData; // Global info for all tracks
+ Tracks m_tracks;
+
+ // Used by parser... Temporary...
+ CStdString m_file;
+ TrackInfo m_currentTrack; // Current parsed track
+ bool m_is_va;
+ CStdString m_albumArtist;
+public:
+ CueParser();
+ void reset();
+ /*! Run parsing and set callback for parser.
+ */
+ bool parse(CueParserCallback& callback);
+ struct TrackEntry
+ {
+ CStdString m_file;
+ unsigned m_trackNumber;
+ CueSheetIndexList m_indexes;
+ };
+private:
+ bool onMeta(const CStdString& name, const CStdString& value);
+ bool onIndex(const CStdString& strLine);
+ bool onTrack(const CStdString& strLine);
+ bool onFile(const CStdString& strLine);
+ bool onFlags(const CStdString& strLine);
+ bool onPregap(const CStdString& strLine);
+
+ bool finalizeTrack();
+
+ // Helper methods
+ static bool extractTime(const CStdString& strLine, unsigned& time);
+ static bool extractString(const CStdString& line, CStdString& outStr, bool spaceIsError);
+ static CStdString cutFirstWord(CStdString& inputStr);
+};
View
45 xbmc/music/cue/CueParserCallback.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#pragma once
+#include "music/Song.h"
+
+/*! Base virtual class for interaction with CueParser.
+ * Implementation MUST provide CUE-data to parser and can collect useful information from parser.
+ * CueParser call different virtual methods of callback for different reasons.
+ *
+ * All \b on* methods can return true if parser need continue otherwise methods returns false.
+ */
+class CueParserCallback
+{
+public:
+ /*! Implementation should fill \b dataLie with next portion of CUE-data.
+ */
+ virtual bool onDataNeeded(CStdString& dataLine) = 0;
+ /*! This method called every time when parser found FILE record in cue-sheet.
+ * Callback can modify filePath.
+ */
+ virtual bool onFile(CStdString& filePath) = 0;
+ /*! This method called for every track found by parser.
+ */
+ virtual bool onTrackReady(CSong& song) = 0;
+ virtual ~CueParserCallback() {}
+};
View
37 xbmc/music/cue/CueReader.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#pragma once
+#include "utils/StdString.h"
+
+/*! Base class for reading CUE-data from different sources.
+ */
+class CueReader
+{
+public:
+ virtual bool isValid() const = 0;
+ inline bool skipChar(char ch) const
+ {
+ return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
+ }
+ virtual bool ReadNextLine(CStdString &line) = 0;
+ virtual ~CueReader() {};
+};
View
84 xbmc/music/cue/CueSheetIndexList.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "CueSheetIndexList.h"
+
+void CueSheetIndexList::setIndex(unsigned index, unsigned value)
+{
+ m_positions[index] = value;
+}
+
+CueSheetIndexList::CueSheetIndexList()
+{
+ reset();
+}
+
+
+CueSheetIndexList::~CueSheetIndexList()
+{
+}
+
+void CueSheetIndexList::reset()
+{
+ for(unsigned n=0; n<count; n++)
+ m_positions[n]=0;
+}
+
+bool CueSheetIndexList::isEmpty() const
+{
+ for(unsigned n=0; n < count; n++)
+ {
+ if (m_positions[n] != m_positions[1])
+ return false;
+ }
+ return true;
+}
+
+bool CueSheetIndexList::isValid() const
+{
+ if (m_positions[1] < m_positions[0])
+ return false;
+ for(unsigned n = 2; n < count && m_positions[n] > 0; n++)
+ {
+ if (m_positions[n] < m_positions[n-1])
+ return false;
+ }
+ return true;
+}
+
+bool CueSheetIndexList::updatePreGap(unsigned pregap)
+{
+ if (pregap && m_positions[0] == 0)
+ m_positions[0] = m_positions[1] - pregap;
+ return isValid();
+}
+
+unsigned CueSheetIndexList::start() const
+{
+ return m_positions[1];
+}
+
+unsigned CueSheetIndexList::pregap() const
+{
+ if (m_positions[0] > 0)
+ return m_positions[1] - m_positions[0];
+ return m_positions[0];
+}
View
40 xbmc/music/cue/CueSheetIndexList.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#pragma once
+
+/*! Class for hold info about indexes in track.
+ */
+class CueSheetIndexList
+{
+ enum {count = 100};
+ unsigned m_positions[count];
+public:
+ CueSheetIndexList();
+ ~CueSheetIndexList();
+ void reset();
+ bool isEmpty() const;
+ bool isValid() const;
+ void setIndex(unsigned index, unsigned value);
+ bool updatePreGap(unsigned pregap);
+ unsigned start() const;
+ unsigned pregap() const;
+};
View
189 xbmc/music/cue/CueSongsCollector.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "CueSongsCollector.h"
+#include "TagCueReader.h"
+#include "FileCueReader.h"
+#include "music/tags/MusicInfoTag.h"
+#include "utils/URIUtils.h"
+#include "utils/StringUtils.h"
+#include "settings/Settings.h"
+
+
+CueSongsCollector::CueSongsCollector(const CFileItemList& container)
+ : m_container(container)
+ , m_external(true)
+{
+}
+
+const CFileItemList& CueSongsCollector::container()
+{
+ return m_container;
+}
+
+const MUSIC_INFO::CMusicInfoTag& CueSongsCollector::tag(const CStdString& mediaFile)
+{
+ // We cache MusicTag for prevent extra reading from disk.
+ Cache::iterator it = m_cache.find(mediaFile);
+ if (it == m_cache.end())
+ it = m_cache.insert(CacheItem(mediaFile, MUSIC_INFO::CMusicInfoTag(mediaFile))).first;
+ return it->second;
+}
+
+bool CueSongsCollector::load(const CStdString &filePath)
+{
+ m_cueFile = filePath;
+ CStdString extension;
+ URIUtils::GetExtension(m_cueFile, extension);
+ if (extension.Equals((char*)".cue"))
+ {
+ m_reader = boost::shared_ptr<CueReader>(new FileCueReader(m_cueFile));
+ m_external = true;
+ }
+ else
+ {
+ if (extension.Equals((char*)".ape") || extension.Equals((char*)".flac") ||
+ extension.Equals((char*)".wv"))
+ {
+ const MUSIC_INFO::CMusicInfoTag& t = tag(filePath);
+ if (t.hasEmbeddedCue())
+ {
+ m_reader = boost::shared_ptr<CueReader>(new TagCueReader(t.GetEmbeddedCue()));
+ m_external = false;
+ }
+ }
+ }
+ bool result = false;
+ if (m_reader)
+ result = m_reader->isValid();
+ if (result)
+ itemstodelete.insert(m_cueFile);
+ return result;
+}
+
+bool CueSongsCollector::onFile(CStdString& filePath)
+{
+ bool bFoundMediaFile = true;
+ if (m_external)
+ {
+ // Convert relative path to absolute.
+ if ((filePath.Left(1) != "/") && filePath.Mid(1, 3) != ":\\\\")
+ filePath = URIUtils::AddFileToFolder(container().GetPath(), filePath);
+ CStdString mediaFilePath = filePath;
+ bFoundMediaFile = XFILE::CFile::Exists(filePath) || container().Contains(filePath);
+ if (!bFoundMediaFile)
+ {
+ // try removing the .cue extension...
+ URIUtils::RemoveExtension(filePath);
+ CFileItem item(filePath, false);
+ bFoundMediaFile = (item.IsAudio() && container().Contains(filePath));
+ }
+ if (!bFoundMediaFile)
+ {
+ // try replacing the extension with one of our allowed ones.
+ CStdStringArray extensions;
+ StringUtils::SplitString(g_settings.m_musicExtensions, "|", extensions);
+ for (unsigned int i = 0; i < extensions.size(); i++)
+ {
+ filePath = URIUtils::ReplaceExtension(mediaFilePath, extensions[i]);
+ CFileItem item(filePath, false);
+ if (!item.IsCUESheet() && !item.IsPlayList() && container().Contains(filePath))
+ {
+ bFoundMediaFile = true;
+ break;
+ }
+ }
+ }
+ if (bFoundMediaFile)
+ { // if file has a cue, we stop parsing.
+ if (tag(filePath).hasEmbeddedCue())
+ {
+ itemstodelete.insert(filePath);
+ return false;
+ }
+ }
+ }
+ else // For embedded we always use self file
+ filePath = m_cueFile;
+ return bFoundMediaFile;
+}
+
+bool CueSongsCollector::onDataNeeded(CStdString& dataLine)
+{
+ return m_reader->ReadNextLine(dataLine);
+}
+
+bool CueSongsCollector::onTrackReady(CSong& song)
+{
+ // we might have a new media file from parser
+ const MUSIC_INFO::CMusicInfoTag& t = tag(song.strFileName);
+ if (t.Loaded())
+ {
+ if (song.strAlbum.empty() && !t.GetAlbum().empty())
+ song.strAlbum = t.GetAlbum();
+ if (song.albumArtist.empty() && !t.GetAlbumArtist().empty())
+ song.albumArtist = t.GetAlbumArtist();
+ if (song.genre.empty() && !t.GetGenre().empty())
+ song.genre = t.GetGenre();
+ if (song.artist.empty() && !t.GetArtist().empty())
+ song.artist = t.GetArtist();
+ if (t.GetDiscNumber())
+ song.iTrack |= (t.GetDiscNumber() << 16); // see CMusicInfoTag::GetDiscNumber()
+ SYSTEMTIME dateTime;
+ t.GetReleaseDate(dateTime);
+ if (dateTime.wYear)
+ song.iYear = dateTime.wYear;
+ }
+ if (!song.iDuration && t.GetDuration() > 0)
+ { // must be the last song
+ song.iDuration = (t.GetDuration() * 75 - song.iStartOffset + 37) / 75;
+ }
+ // add this item to the list
+ m_songs.push_back(song);
+ return true;
+}
+
+void CueSongsCollector::finalize(VECFILEITEMS& items)
+{
+ // now delete the .CUE files and underlying media files.
+ for (boost::unordered_set<CStdString>::const_iterator removeIt = itemstodelete.begin();
+ removeIt != itemstodelete.end(); ++removeIt)
+ {
+ for (VECFILEITEMS::iterator it = items.begin(); it != items.end(); ++it)
+ {
+ CFileItemPtr pItem = *it;
+ if (stricmp(pItem->GetPath().c_str(), removeIt->c_str()) == 0)
+ {
+ items.erase(it);
+ break;
+ }
+ }
+ }
+ for (VECSONGS::const_iterator it = m_songs.begin(); it != m_songs.end(); ++it)
+ {
+ CFileItemPtr pItem(new CFileItem(*it));
+ items.push_back(pItem);
+ }
+}
+
+CueSongsCollector::~CueSongsCollector()
+{
+}
View
72 xbmc/music/cue/CueSongsCollector.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#pragma once
+#include "CueParserCallback.h"
+#include "CStdStringHash.hpp"
+#include "FileItem.h"
+#include "music/Song.h"
+#include <boost/unordered/unordered_map.hpp>
+#include <boost/unordered/unordered_set.hpp>
+#include <boost/smart_ptr/shared_ptr.hpp>
+
+class CueReader;
+class CFileItemList;
+
+/*! Callback class for collecting metadata provided by CueParser.
+ */
+class CueSongsCollector
+ : public CueParserCallback
+{
+ const CFileItemList& m_container;
+ CStdString m_cueFile;
+ bool m_external;
+ typedef std::pair<CStdString, MUSIC_INFO::CMusicInfoTag> CacheItem;
+ typedef boost::unordered_map<CStdString, MUSIC_INFO::CMusicInfoTag, CStdStringHash> Cache;
+ Cache m_cache;
+ boost::shared_ptr<CueReader> m_reader;
+ VECSONGS m_songs;
+ boost::unordered_set<CStdString, CStdStringHash> itemstodelete;
+private:
+ const CFileItemList& container();
+ const MUSIC_INFO::CMusicInfoTag& tag(const CStdString& mediaFile);
+public:
+ CueSongsCollector(const CFileItemList& container);
+ /*! Load CUE-data from \b filePath and detect type of cuesheet.
+ * Returns true on success.
+ */
+ bool load(const CStdString &filePath);
+ /*! Provide next string to parser.
+ */
+ virtual bool onDataNeeded(CStdString& dataLine);
+ /*! Method called by parser when it found new file item.
+ */
+ virtual bool onFile(CStdString& filePath);
+ /*! Collect information about each track.
+ */
+ virtual bool onTrackReady(CSong& song);
+ /*! Finalize collecting process.
+ * Method delete all CUE and related media files from items list.
+ * Also appends all found media files to the list.
+ */
+ void finalize(VECFILEITEMS& items);
+ virtual ~CueSongsCollector();
+};
View
58 xbmc/music/cue/FileCueReader.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "FileCueReader.h"
+
+
+bool FileCueReader::isValid() const
+{
+ return m_opened;
+}
+
+FileCueReader::FileCueReader(const CStdString &strFile)
+{
+ m_opened = m_file.Open(strFile);
+}
+
+bool FileCueReader::ReadNextLine(CStdString &szLine)
+{
+ char *pos;
+ // Read the next line.
+ while (m_file.ReadString(m_szBuffer, 1023)) // Bigger than MAX_PATH_SIZE, for usage with relax!
+ {
+ // Remove the white space at the beginning of the line.
+ pos = m_szBuffer;
+ while (pos && skipChar(*pos)) pos++;
+ if (pos)
+ {
+ szLine = pos;
+ return true;
+ }
+ // If we are here, we have an empty line so try the next line
+ }
+ return false;
+}
+
+FileCueReader::~FileCueReader()
+{
+ if (m_opened)
+ m_file.Close();
+}
View
39 xbmc/music/cue/FileCueReader.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#pragma once
+#include "CueReader.h"
+#include "filesystem/File.h"
+
+/*! Class for reading CUE-data from *.cue files.
+ */
+class FileCueReader
+ : public CueReader
+{
+ XFILE::CFile m_file;
+ bool m_opened;
+ char m_szBuffer[1024];
+public:
+ virtual bool isValid() const;
+ FileCueReader(const CStdString &strFile);
+ virtual bool ReadNextLine(CStdString &szLine);
+ ~FileCueReader();
+};
View
62 xbmc/music/cue/TagCueReader.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "TagCueReader.h"
+
+TagCueReader::TagCueReader(const CStdString &cueData)
+ : m_data(cueData)
+ , m_currentPos(0)
+{
+}
+
+bool TagCueReader::isValid() const
+{
+ return !m_data.IsEmpty();
+}
+
+
+bool TagCueReader::ReadNextLine(CStdString &line)
+{
+ // Read the next line.
+ line = "";
+ bool stop = false;
+ while (m_currentPos < m_data.length())
+ {
+ // Remove the white space at the beginning of the line.
+ char ch = m_data.at(m_currentPos++);
+ stop |= (!skipChar(ch));
+ if (stop)
+ {
+ if (ch == '\r' || ch == '\n')
+ {
+ if (!line.IsEmpty())
+ return true;
+ }
+ else
+ line += ch;
+ }
+ }
+ return false;
+}
+
+TagCueReader::~TagCueReader()
+{
+}
View
37 xbmc/music/cue/TagCueReader.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#pragma once
+#include "CueReader.h"
+
+/*! Class for reading CUE-data from 'cuesheet' meta-tag.
+ */
+class TagCueReader
+ : public CueReader
+{
+ const CStdString& m_data;
+ unsigned int m_currentPos;
+public:
+ TagCueReader(const CStdString &cueData);
+ virtual bool isValid() const;
+ virtual bool ReadNextLine(CStdString &line);
+ ~TagCueReader();
+};
View
2  xbmc/music/tags/MusicInfoTag.cpp
@@ -24,7 +24,7 @@
#include "utils/StringUtils.h"
#include "settings/AdvancedSettings.h"
#include "utils/Variant.h"
-#include "filesystem\File.h"
+#include "filesystem/File.h"
#include "music/tags/MusicInfoTagLoaderFactory.h"
using namespace MUSIC_INFO;

0 comments on commit b0d50c7

Please sign in to comment.
Something went wrong with that request. Please try again.