aboutsummaryrefslogtreecommitdiff
path: root/src/tag_parse_lyrics3.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tag_parse_lyrics3.cpp')
-rw-r--r--src/tag_parse_lyrics3.cpp370
1 files changed, 370 insertions, 0 deletions
diff --git a/src/tag_parse_lyrics3.cpp b/src/tag_parse_lyrics3.cpp
new file mode 100644
index 0000000..e502888
--- /dev/null
+++ b/src/tag_parse_lyrics3.cpp
@@ -0,0 +1,370 @@
+// $Id: tag_parse_lyrics3.cpp,v 1.35 2002/10/04 08:52:23 t1mpy Exp $
+
+// id3lib: a C++ library for creating and manipulating id3v1/v2 tags
+// Copyright 1999, 2000 Scott Thomas Haug
+// Copyright 2002 Thijmen Klok (thijmen@id3lib.org)
+
+// This library is free software; you can redistribute it and/or modify it
+// under the terms of the GNU Library General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or (at your
+// option) any later version.
+//
+// This library 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 Library General Public
+// License for more details.
+//
+// You should have received a copy of the GNU Library General Public License
+// along with this library; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+// The id3lib authors encourage improvements and optimisations to be sent to
+// the id3lib coordinator. Please see the README file for details on where to
+// send such submissions. See the AUTHORS file for a list of people who have
+// contributed to id3lib. See the ChangeLog file for a list of changes to
+// id3lib. These files are distributed with id3lib at
+// http://download.sourceforge.net/id3lib/
+
+#include <ctype.h>
+#include <memory.h>
+#include "tag_impl.h" //has <stdio.h> "tag.h" "header_tag.h" "frame.h" "field.h" "spec.h" "id3lib_strings.h" "utils.h"
+#include "helpers.h"
+#include "id3/io_decorators.h" //has "readers.h" "io_helpers.h" "utils.h"
+#include "io_strings.h"
+
+using namespace dami;
+
+namespace
+{
+ uint32 readIntegerString(ID3_Reader& reader, size_t numBytes)
+ {
+ uint32 val = 0;
+ for (size_t i = 0; i < numBytes && isdigit(reader.peekChar()); ++i)
+ {
+ val = (val * 10) + (reader.readChar() - '0');
+ }
+ ID3D_NOTICE( "readIntegerString: val = " << val );
+ return val;
+ }
+
+ uint32 readIntegerString(ID3_Reader& reader)
+ {
+ return readIntegerString(reader, reader.remainingBytes());
+ }
+
+ bool isTimeStamp(ID3_Reader& reader)
+ {
+ ID3_Reader::pos_type cur = reader.getCur();
+ if (reader.getEnd() < cur + 7)
+ {
+ return false;
+ }
+ bool its = ('[' == reader.readChar() &&
+ isdigit(reader.readChar()) && isdigit(reader.readChar()) &&
+ ':' == reader.readChar() &&
+ isdigit(reader.readChar()) && isdigit(reader.readChar()) &&
+ ']' == reader.readChar());
+ reader.setCur(cur);
+ if (its)
+ {
+ ID3D_NOTICE( "isTimeStamp(): found timestamp, cur = " << reader.getCur() );
+ }
+ return its;
+ }
+
+ uint32 readTimeStamp(ID3_Reader& reader)
+ {
+ reader.skipChars(1);
+ size_t sec = readIntegerString(reader, 2) * 60;
+ reader.skipChars(1);
+ sec += readIntegerString(reader, 2);
+ reader.skipChars(1);
+ ID3D_NOTICE( "readTimeStamp(): timestamp = " << sec );
+ return sec * 1000;
+ }
+
+ bool findText(ID3_Reader& reader, String text)
+ {
+ if (text.empty())
+ {
+ return true;
+ }
+
+ size_t index = 0;
+ while (!reader.atEnd())
+ {
+ ID3_Reader::char_type ch = reader.readChar();
+ if (ch == text[index])
+ {
+ index++;
+ }
+ else if (ch == text[0])
+ {
+ index = 1;
+ }
+ else
+ {
+ index = 0;
+ }
+ if (index == text.size())
+ {
+ reader.setCur(reader.getCur() - index);
+ ID3D_NOTICE( "findText: found \"" << text << "\" at " <<
+ reader.getCur() );
+ break;
+ }
+ }
+ return !reader.atEnd();
+ };
+
+ void lyrics3ToSylt(ID3_Reader& reader, ID3_Writer& writer)
+ {
+ while (!reader.atEnd())
+ {
+ bool lf = false;
+ size_t ms = 0;
+ size_t count = 0;
+ while (isTimeStamp(reader))
+ {
+ // For now, just skip over multiple time stamps
+ if (count++ > 0)
+ {
+ readTimeStamp(reader);
+ }
+ else
+ {
+ ms = readTimeStamp(reader);
+ }
+ }
+ while (!reader.atEnd() && !isTimeStamp(reader))
+ {
+ ID3_Reader::char_type ch = reader.readChar();
+ if (0x0A == ch && (reader.atEnd() || isTimeStamp(reader)))
+ {
+ lf = true;
+ break;
+ }
+ else
+ {
+ writer.writeChar(ch);
+ }
+ }
+
+ // put synch identifier
+ writer.writeChar('\0');
+
+ // put timestamp
+ ID3D_NOTICE( "lyrics3toSylt: ms = " << ms );
+
+ io::writeBENumber(writer, ms, sizeof(uint32));
+ if (lf)
+ {
+ ID3D_NOTICE( "lyrics3toSylt: adding lf" );
+
+ // put the LF
+ writer.writeChar(0x0A);
+ }
+ }
+ }
+};
+
+bool lyr3::v1::parse(ID3_TagImpl& tag, ID3_Reader& reader)
+{
+ io::ExitTrigger et(reader);
+ ID3_Reader::pos_type end = reader.getCur();
+ if (end < reader.getBeg() + 9 + 128)
+ {
+ ID3D_NOTICE( "id3::v1::parse: bailing, not enough bytes to parse, pos = " << end );
+ return false;
+ }
+ reader.setCur(end - (9 + 128));
+
+ {
+ if (io::readText(reader, 9) != "LYRICSEND" ||
+ io::readText(reader, 3) != "TAG")
+ {
+ return false;
+ }
+ }
+
+ // we have a Lyrics3 v1.00 tag
+ if (end < reader.getBeg() + 11 + 9 + 128)
+ {
+ // the file size isn't large enough to actually hold lyrics
+ ID3D_WARNING( "id3::v1::parse: not enough data to parse lyrics3" );
+ return false;
+ }
+
+ // reserve enough space for lyrics3 + id3v1 tag
+ size_t window = end - reader.getBeg();
+ size_t lyrDataSize = min<size_t>(window, 11 + 5100 + 9 + 128);
+ reader.setCur(end - lyrDataSize);
+ io::WindowedReader wr(reader, lyrDataSize - (9 + 128));
+
+ if (!findText(wr, "LYRICSBEGIN"))
+ {
+ ID3D_WARNING( "id3::v1::parse: couldn't find LYRICSBEGIN, bailing" );
+ return false;
+ }
+
+ et.setExitPos(wr.getCur());
+ wr.skipChars(11);
+ wr.setBeg(wr.getCur());
+
+ io::LineFeedReader lfr(wr);
+ String lyrics = io::readText(lfr, wr.remainingBytes());
+ id3::v2::setLyrics(tag, lyrics, "Converted from Lyrics3 v1.00", "XXX");
+
+ return true;
+}
+
+//bool parse(TagImpl& tag, ID3_Reader& reader)
+bool lyr3::v2::parse(ID3_TagImpl& tag, ID3_Reader& reader)
+{
+ io::ExitTrigger et(reader);
+ ID3_Reader::pos_type end = reader.getCur();
+ if (end < reader.getBeg() + 6 + 9 + 128)
+ {
+ ID3D_NOTICE( "lyr3::v2::parse: bailing, not enough bytes to parse, pos = " << reader.getCur() );
+ return false;
+ }
+
+ reader.setCur(end - (6 + 9 + 128));
+ uint32 lyrSize = 0;
+
+ ID3_Reader::pos_type beg = reader.getCur();
+ lyrSize = readIntegerString(reader, 6);
+ if (reader.getCur() < beg + 6)
+ {
+ ID3D_NOTICE( "lyr3::v2::parse: couldn't find numeric string, lyrSize = " <<
+ lyrSize );
+ return false;
+ }
+
+ if (io::readText(reader, 9) != "LYRICS200" ||
+ io::readText(reader, 3) != "TAG")
+ {
+ return false;
+ }
+
+ if (end < reader.getBeg() + lyrSize + 6 + 9 + 128)
+ {
+ ID3D_WARNING( "lyr3::v2::parse: not enough data to parse tag, lyrSize = " << lyrSize );
+ return false;
+ }
+ reader.setCur(end - (lyrSize + 6 + 9 + 128));
+
+ io::WindowedReader wr(reader);
+ wr.setWindow(wr.getCur(), lyrSize);
+
+ beg = wr.getCur();
+
+ if (io::readText(wr, 11) != "LYRICSBEGIN")
+ {
+ // not a lyrics v2.00 tag
+ ID3D_WARNING( "lyr3::v2::parse: couldn't find LYRICSBEGIN, bailing" );
+ return false;
+ }
+
+ bool has_time_stamps = false;
+
+ ID3_Frame* lyr_frame = NULL;
+
+ while (!wr.atEnd())
+ {
+ uint32 fldSize;
+
+ String fldName = io::readText(wr, 3);
+ ID3D_NOTICE( "lyr3::v2::parse: fldName = " << fldName );
+ fldSize = readIntegerString(wr, 5);
+ ID3D_NOTICE( "lyr3::v2::parse: fldSize = " << fldSize );
+
+ String fldData;
+
+ io::WindowedReader wr2(wr, fldSize);
+ io::LineFeedReader lfr(wr2);
+
+ fldData = io::readText(lfr, fldSize);
+ ID3D_NOTICE( "lyr3::v2::parse: fldData = \"" << fldData << "\"" );
+
+ // the IND field
+ if (fldName == "IND")
+ {
+ has_time_stamps = (fldData.size() > 1 && fldData[1] == '1');
+ }
+
+ // the TITLE field
+ else if (fldName == "ETT" && !id3::v2::hasTitle(tag))
+ {
+ //tag.setTitle(fldData);
+ id3::v2::setTitle(tag, fldData);
+ }
+
+ // the ARTIST field
+ else if (fldName == "EAR" && !id3::v2::hasArtist(tag))
+ {
+ //tag.setArtist(fldData);
+ id3::v2::setArtist(tag, fldData);
+ }
+
+ // the ALBUM field
+ else if (fldName == "EAL" && !id3::v2::hasAlbum(tag))
+ {
+ //tag.setAlbum(fldData);
+ id3::v2::setAlbum(tag, fldData);
+ }
+
+ // the Lyrics/Music AUTHOR field
+ else if (fldName == "AUT")
+ {
+ //tag.setAuthor(fldData);
+ id3::v2::setLyricist(tag, fldData);
+ }
+
+ // the INFORMATION field
+ else if (fldName == "INF")
+ {
+ //tag.setInfo(fldData);
+ id3::v2::setComment(tag, fldData, "Lyrics3 v2.00 INF", "XXX");
+ }
+
+ // the LYRICS field
+ else if (fldName == "LYR")
+ {
+ // if already found an INF field, use it as description
+ String desc = "Converted from Lyrics3 v2.00";
+ //tag.setLyrics(fldData);
+ if (!has_time_stamps)
+ {
+ lyr_frame = id3::v2::setLyrics(tag, fldData, desc, "XXX");
+ }
+ else
+ {
+ // converts from lyrics3 to SYLT in-place
+ io::StringReader sr(fldData);
+ ID3D_NOTICE( "lyr3::v2::parse: determining synced lyrics" );
+ BString sylt;
+ io::BStringWriter sw(sylt);
+ lyrics3ToSylt(sr, sw);
+
+ lyr_frame = id3::v2::setSyncLyrics(tag, sylt, ID3TSF_MS, desc,
+ "XXX", ID3CT_LYRICS);
+ ID3D_NOTICE( "lyr3::v2::parse: determined synced lyrics" );
+ }
+ }
+ else if (fldName == "IMG")
+ {
+ // currently unsupported
+ ID3D_WARNING( "lyr3::v2::parse: IMG field unsupported" );
+ }
+ else
+ {
+ ID3D_WARNING( "lyr3::v2::parse: undefined field id: " <<
+ fldName );
+ }
+ }
+
+ et.setExitPos(beg);
+ return true;
+}
+