diff options
author | Alexander Sulfrian <alexander@sulfrian.net> | 2010-01-15 05:10:30 +0100 |
---|---|---|
committer | Alexander Sulfrian <alexander@sulfrian.net> | 2013-01-05 17:17:44 +0100 |
commit | f5d2afb357c7581536da91022986872cd41b68d3 (patch) | |
tree | 2422faa56d75827d265223248832df611974a45b | |
parent | 750505e136531c44d0c6530562509eacfb1e3e56 (diff) | |
download | usdx-f5d2afb357c7581536da91022986872cd41b68d3.tar.gz usdx-f5d2afb357c7581536da91022986872cd41b68d3.tar.xz usdx-f5d2afb357c7581536da91022986872cd41b68d3.zip |
added txt header loading with test and some preparations for loading notes
-rw-r--r-- | src/base/song.cpp | 115 | ||||
-rw-r--r-- | src/base/song.hpp | 17 | ||||
-rw-r--r-- | src/base/songloading/songloader.cpp | 4 | ||||
-rw-r--r-- | src/base/songloading/songloader.hpp | 4 | ||||
-rw-r--r-- | src/base/songloading/songloading_strategy.hpp | 3 | ||||
-rw-r--r-- | src/base/songloading/songloading_strategy_txt.cpp | 137 | ||||
-rw-r--r-- | src/base/songloading/songloading_strategy_txt.hpp | 27 | ||||
-rw-r--r-- | src/base/songloading/songloading_strategy_xml.cpp | 7 | ||||
-rw-r--r-- | src/base/songloading/songloading_strategy_xml.hpp | 3 | ||||
-rw-r--r-- | test/base/songloading.cpp | 59 |
10 files changed, 364 insertions, 12 deletions
diff --git a/src/base/song.cpp b/src/base/song.cpp new file mode 100644 index 00000000..fe93d781 --- /dev/null +++ b/src/base/song.cpp @@ -0,0 +1,115 @@ +/* + * UltraStar Deluxe - Karaoke Game + * + * UltraStar Deluxe is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 + * of the License, 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 this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#include "song.hpp" + +namespace usdx +{ + log4cxx::LoggerPtr Song::log = + log4cxx::Logger::getLogger("usdx.base.Song"); + + const std::string& Song::get_filename(void) + { + return filename; + } + + Song::Song(const std::string& filename, const std::map<std::string, std::string>& header) : + filename(filename), custom_header_tags(header) + { + std::map<std::string, std::string>::iterator it; + + title = get_header_tag("TITLE", true); + artist = get_header_tag("ARTIST", true); + mp3 = get_header_tag("MP3", true); + bpm = get_header_tag("BPM", true); + + // TODO: float + // gap = get_header_tag("GAP"); + cover = get_header_tag("COVER"); + background = get_header_tag("BACKGROUND"); + + video = get_header_tag("VIDEO"); + // TODO + // EncFile := DecodeFilename(Value); + // if (self.Path.Append(EncFile).IsFile) then + // self.Video := EncFile + // else + // Log.LogError('Can''t find video file in song: ' + + // Fulfilling); + + // TODO: float + // videogap = get_header_tag("VIDEOGAP"); + + genre = get_header_tag("GENRE"); + edition = get_header_tag("EDITION"); + creator = get_header_tag("CREATOR"); + language = get_header_tag("LANGUAGE"); + + // TODO: int + // year = get_header_tag("YEAR"); + + // TODO: float + // start = get_header_tag("START"); + + // TODO: int + // end = get_header_tag("END"); + // resolution = get_header_tag("RESOLUTION"); + // notesgap = get_header_tag("NOTESGAP"); + + // TODO: bool + // relative = get_header_tag("RELATIVE"); + + // TODO + // encoding = get_header_tag("ENCODING"); + } + + std::string Song::get_header_tag(const std::string& tag, const bool required) + { + std::map<std::string, std::string>::iterator it; + std::string result = ""; + + if ((it = custom_header_tags.find(tag)) != custom_header_tags.end()) { + result = it->second; + custom_header_tags.erase(it); + } + else if (required) { + LOG4CXX_ERROR(log, "Incomplete Song! Missing '" << tag << "' Tag in: '" << get_filename() << "'"); + throw "Incomplete Song! Missing Tag."; + } + + return result; + } + + const std::string& Song::get_title(void) + { + return title; + } + + const std::string& Song::get_artist(void) + { + return artist; + } +}; diff --git a/src/base/song.hpp b/src/base/song.hpp index 90226932..ae9c3f24 100644 --- a/src/base/song.hpp +++ b/src/base/song.hpp @@ -28,12 +28,18 @@ #define SONG_HPP #include <string> +#include <map> +#include <log4cxx/logger.h> namespace usdx { class Song { private: + static log4cxx::LoggerPtr log; + + std::string filename; + std::string title; std::string artist; @@ -62,12 +68,21 @@ namespace usdx bool relative; int resolution; // TODO: bpm: array of TBPM + std::string bpm; // TODO: list of LyricLines // TODO: Encoding: TEncoding; - // TODO: CustomTags: array of TCustomHeaderTag; + std::map<std::string, std::string> custom_header_tags; + + std::string get_header_tag(const std::string& tag, const bool required = false); public: + const std::string& get_filename(void); + + Song(const std::string& filename, const std::map<std::string, std::string>& header); + + const std::string& get_title(void); + const std::string& get_artist(void); }; }; diff --git a/src/base/songloading/songloader.cpp b/src/base/songloading/songloader.cpp index c4d1054d..8bffa607 100644 --- a/src/base/songloading/songloader.cpp +++ b/src/base/songloading/songloader.cpp @@ -56,7 +56,7 @@ namespace usdx return instance; } - Song *Songloader::load(std::string filename) + Song *Songloader::load_header(std::string filename) { std::string extension = ""; @@ -71,6 +71,6 @@ namespace usdx throw "Unknown file format."; } - return it->second->loadSong(filename); + return it->second->load_header(filename); } }; diff --git a/src/base/songloading/songloader.hpp b/src/base/songloading/songloader.hpp index 3c0b8e6f..8a5cbe03 100644 --- a/src/base/songloading/songloader.hpp +++ b/src/base/songloading/songloader.hpp @@ -49,11 +49,11 @@ namespace usdx static Songloader *instance; public: - Songloader *get_instance(void); + static Songloader *get_instance(void); virtual ~Songloader(void); - Song *load(std::string filename); + Song *load_header(std::string filename); }; }; diff --git a/src/base/songloading/songloading_strategy.hpp b/src/base/songloading/songloading_strategy.hpp index 4f5edd0f..5cded02d 100644 --- a/src/base/songloading/songloading_strategy.hpp +++ b/src/base/songloading/songloading_strategy.hpp @@ -40,7 +40,8 @@ namespace usdx public: virtual ~SongloadingStrategy() {}; - virtual Song* loadSong(std::string filename) = 0; + virtual Song* load_song(Song* song) = 0; + virtual Song* load_header(const std::string& filename) = 0; }; }; diff --git a/src/base/songloading/songloading_strategy_txt.cpp b/src/base/songloading/songloading_strategy_txt.cpp index e8238f4a..31604191 100644 --- a/src/base/songloading/songloading_strategy_txt.cpp +++ b/src/base/songloading/songloading_strategy_txt.cpp @@ -24,10 +24,17 @@ * $Id$ */ +#include <string> +#include <algorithm> #include "songloading_strategy_txt.hpp" +#include "utils/file.hpp" namespace usdx { + log4cxx::LoggerPtr SongloadingStrategyTxt::log = + log4cxx::Logger::getLogger( + "usdx.base.songloading.SongloadingStrategyTxt"); + SongloadingStrategyTxt::SongloadingStrategyTxt(void) { } @@ -36,9 +43,133 @@ namespace usdx { } - Song* SongloadingStrategyTxt::loadSong(std::string filename) + std::pair<std::string, std::string> SongloadingStrategyTxt::split_header_field(std::string &line) + { + std::size_t pos = line.find(':'); + + if (line[0] != '#' || pos == std::string::npos) { + LOG4CXX_DEBUG(log, "Tried to parse invalid header line: '" << line << "'"); + throw "Invalid header!"; + } + + std::pair<std::string, std::string> result; + + // copy the substring to : without # to result.first and + // transform to upper case + result.first.resize(pos - 1); + std::transform(line.begin() + 1, line.begin() + pos, + result.first.begin(), toupper); + + // line is already ltrimmed + rtrim(result.first); + + result.second = line.substr(pos + 1); + + // line is already rtrimmed + ltrim(result.second); + + LOG4CXX_DEBUG(log, "Found header: '" << result.first << "' with value '" << result.second << "'"); + + return result; + } + + std::string& SongloadingStrategyTxt::ltrim(std::string& line) + { + std::size_t found = line.find_first_not_of(" \t\n\r"); + if (found != std::string::npos && found >= 1) { + line.erase(0, found - 1); + } + + return line; + } + + std::string& SongloadingStrategyTxt::rtrim(std::string& line) + { + std::size_t found = line.find_last_not_of(" \t\n\r"); + if (found != std::string::npos) { + line.erase(found + 1); + } + + return line; + } + + std::string& SongloadingStrategyTxt::trim(std::string& line) { - // TODO - return NULL; + return ltrim(rtrim(line)); + } + + Song* SongloadingStrategyTxt::load_song(Song *song) + { + File file(song->get_filename()); + std::string line; + + while (file.stream().good()) { + file.stream() >> line; + + // do not remove spaces at line ending, that are maybe + // spaces in lyrics + ltrim(line); + + if (line[0] == '#') { + // ignore, header already read + } + else if (line[0] == 'E') { + // song end + break; + } + else if (line[0] == '-') { + // line break + } + else if (line[0] == 'B') { + // new bpm + } + else { + // normal line + } + } + + // fill song + + return song; + } + + Song* SongloadingStrategyTxt::load_header(const std::string& filename) + { + File file(filename); + std::string line; + std::map<std::string, std::string> header_fields; + + bool header = true, notes_found = false; + while (file.stream().good()) { + std::getline(file.stream(), line); + + trim(line); + LOG4CXX_DEBUG(log, "Line: " << line); + + if (header && line[0] == '#') { + + // header + header_fields.insert(split_header_field(line)); + } + else { + if (header) { + // end of header + header = false; + } + + if (line[0] == ':' || line[0] == '*' || line[0] == 'F') { + notes_found = true; + break; + } + } + } + + if (! notes_found) { + LOG4CXX_WARN(log, "Song: '" << filename << "' has no notes. Ignoring!"); + throw "No notes."; + } + + // fill song + return new Song(filename, header_fields); } }; diff --git a/src/base/songloading/songloading_strategy_txt.hpp b/src/base/songloading/songloading_strategy_txt.hpp index 7a298e41..31a9815a 100644 --- a/src/base/songloading/songloading_strategy_txt.hpp +++ b/src/base/songloading/songloading_strategy_txt.hpp @@ -28,17 +28,42 @@ #define SONGLOADING_STRATEGY_TXT_HPP #include <string> +#include <log4cxx/logger.h> #include "songloading_strategy.hpp" namespace usdx { class SongloadingStrategyTxt : public SongloadingStrategy { + private: + static log4cxx::LoggerPtr log; + + /** + * Split the header field in name and value. + */ + std::pair<std::string, std::string> split_header_field(std::string &line); + + /** + * Removes whitespaces in front of the string. + */ + std::string& ltrim(std::string& line); + + /** + * Removes whitespaces in behind the string. + */ + std::string& rtrim(std::string& line); + + /** + * Removes whitespaces in front of the string and behind it. + */ + std::string& trim(std::string& line); + public: SongloadingStrategyTxt(); virtual ~SongloadingStrategyTxt(); - virtual Song* loadSong(std::string filename); + virtual Song* load_song(Song* song); + virtual Song* load_header(const std::string& filename); }; }; diff --git a/src/base/songloading/songloading_strategy_xml.cpp b/src/base/songloading/songloading_strategy_xml.cpp index 52d1f7cf..f7fea886 100644 --- a/src/base/songloading/songloading_strategy_xml.cpp +++ b/src/base/songloading/songloading_strategy_xml.cpp @@ -36,9 +36,14 @@ namespace usdx { } - Song* SongloadingStrategyXml::loadSong(std::string filename) + Song* SongloadingStrategyXml::load_song(Song *song) { // TODO + return song; + } + + Song* SongloadingStrategyXml::load_header(const std::string& filename) + { return NULL; } }; diff --git a/src/base/songloading/songloading_strategy_xml.hpp b/src/base/songloading/songloading_strategy_xml.hpp index b656fe9a..a01f9c11 100644 --- a/src/base/songloading/songloading_strategy_xml.hpp +++ b/src/base/songloading/songloading_strategy_xml.hpp @@ -37,7 +37,8 @@ namespace usdx SongloadingStrategyXml(void); virtual ~SongloadingStrategyXml(void); - virtual Song* loadSong(std::string filename); + virtual Song* load_song(Song* song); + virtual Song* load_header(const std::string& filename); }; }; diff --git a/test/base/songloading.cpp b/test/base/songloading.cpp new file mode 100644 index 00000000..823bfced --- /dev/null +++ b/test/base/songloading.cpp @@ -0,0 +1,59 @@ +/* + * UltraStar Deluxe - Karaoke Game + * + * UltraStar Deluxe is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 + * of the License, 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 this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#include <iostream> +#include <cppunit/extensions/HelperMacros.h> +#include "song.hpp" +#include "songloading/songloader.hpp" + +namespace usdx +{ + class SongloadingTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(SongloadingTest); + CPPUNIT_TEST(testSongloadingTxt); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() + { + } + + void tearDown() + { + } + + void testSongloadingTxt() + { + Song *song = Songloader::get_instance()->load_header( + "../game/songs/Dead Smiling Pirates - I 18 [DEMO]/Dead Smiling Pirates - I 18.txt"); + + CPPUNIT_ASSERT( "Dead Smiling Pirates" == song->get_artist() ); + CPPUNIT_ASSERT( "I 18" == song->get_title() ); + } + }; + + CPPUNIT_TEST_SUITE_REGISTRATION(SongloadingTest); +}; |