32#include "id3/io_decorators.h"
33#include "io_strings.h"
39 uint32 readIntegerString(
ID3_Reader& reader,
size_t numBytes)
42 for (
size_t i = 0; i < numBytes && isdigit(reader.
peekChar()); ++i)
44 val = (val * 10) + (reader.
readChar() -
'0');
46 ID3D_NOTICE(
"readIntegerString: val = " << val );
58 if (reader.
getEnd() < cur + 7)
62 bool its = (
'[' == reader.
readChar() &&
70 ID3D_NOTICE(
"isTimeStamp(): found timestamp, cur = " << reader.
getCur() );
78 size_t sec = readIntegerString(reader, 2) * 60;
80 sec += readIntegerString(reader, 2);
82 ID3D_NOTICE(
"readTimeStamp(): timestamp = " << sec );
94 while (!reader.
atEnd())
97 if (ch == text[index])
101 else if (ch == text[0])
109 if (index == text.size())
112 ID3D_NOTICE(
"findText: found \"" << text <<
"\" at " <<
117 return !reader.
atEnd();
122 while (!reader.
atEnd())
127 while (isTimeStamp(reader))
132 readTimeStamp(reader);
136 ms = readTimeStamp(reader);
139 while (!reader.
atEnd() && !isTimeStamp(reader))
142 if (0x0A == ch && (reader.
atEnd() || isTimeStamp(reader)))
157 ID3D_NOTICE(
"lyrics3toSylt: ms = " << ms );
159 io::writeBENumber(writer, ms,
sizeof(uint32));
162 ID3D_NOTICE(
"lyrics3toSylt: adding lf" );
173 io::ExitTrigger et(reader);
175 if (end < reader.
getBeg() + 9 + 128)
177 ID3D_NOTICE(
"id3::v1::parse: bailing, not enough bytes to parse, pos = " << end );
180 reader.
setCur(end - (9 + 128));
183 if (io::readText(reader, 9) !=
"LYRICSEND" ||
184 io::readText(reader, 3) !=
"TAG")
191 if (end < reader.
getBeg() + 11 + 9 + 128)
194 ID3D_WARNING(
"id3::v1::parse: not enough data to parse lyrics3" );
199 size_t window = end - reader.
getBeg();
200 size_t lyrDataSize =
min<size_t>(window, 11 + 5100 + 9 + 128);
201 reader.
setCur(end - lyrDataSize);
202 io::WindowedReader wr(reader, lyrDataSize - (9 + 128));
204 if (!findText(wr,
"LYRICSBEGIN"))
206 ID3D_WARNING(
"id3::v1::parse: couldn't find LYRICSBEGIN, bailing" );
210 et.setExitPos(wr.getCur());
212 wr.setBeg(wr.getCur());
214 io::LineFeedReader lfr(wr);
215 String lyrics = io::readText(lfr, wr.remainingBytes());
224 io::ExitTrigger et(reader);
226 if (end < reader.
getBeg() + 6 + 9 + 128)
228 ID3D_NOTICE(
"lyr3::v2::parse: bailing, not enough bytes to parse, pos = " << reader.
getCur() );
232 reader.
setCur(end - (6 + 9 + 128));
236 lyrSize = readIntegerString(reader, 6);
237 if (reader.
getCur() < beg + 6)
239 ID3D_NOTICE(
"lyr3::v2::parse: couldn't find numeric string, lyrSize = " <<
244 if (io::readText(reader, 9) !=
"LYRICS200" ||
245 io::readText(reader, 3) !=
"TAG")
250 if (end < reader.
getBeg() + lyrSize + 6 + 9 + 128)
252 ID3D_WARNING(
"lyr3::v2::parse: not enough data to parse tag, lyrSize = " << lyrSize );
255 reader.
setCur(end - (lyrSize + 6 + 9 + 128));
257 io::WindowedReader wr(reader);
258 wr.setWindow(wr.getCur(), lyrSize);
262 if (io::readText(wr, 11) !=
"LYRICSBEGIN")
265 ID3D_WARNING(
"lyr3::v2::parse: couldn't find LYRICSBEGIN, bailing" );
269 bool has_time_stamps =
false;
277 String fldName = io::readText(wr, 3);
278 ID3D_NOTICE(
"lyr3::v2::parse: fldName = " << fldName );
279 fldSize = readIntegerString(wr, 5);
280 ID3D_NOTICE(
"lyr3::v2::parse: fldSize = " << fldSize );
284 io::WindowedReader wr2(wr, fldSize);
285 io::LineFeedReader lfr(wr2);
287 fldData = io::readText(lfr, fldSize);
288 ID3D_NOTICE(
"lyr3::v2::parse: fldData = \"" << fldData <<
"\"" );
291 if (fldName ==
"IND")
293 has_time_stamps = (fldData.size() > 1 && fldData[1] ==
'1');
318 else if (fldName ==
"AUT")
325 else if (fldName ==
"INF")
332 else if (fldName ==
"LYR")
335 String desc =
"Converted from Lyrics3 v2.00";
337 if (!has_time_stamps)
344 io::StringReader sr(fldData);
345 ID3D_NOTICE(
"lyr3::v2::parse: determining synced lyrics" );
347 io::BStringWriter sw(sylt);
348 lyrics3ToSylt(sr, sw);
352 ID3D_NOTICE(
"lyr3::v2::parse: determined synced lyrics" );
355 else if (fldName ==
"IMG")
358 ID3D_WARNING(
"lyr3::v2::parse: IMG field unsupported" );
362 ID3D_WARNING(
"lyr3::v2::parse: undefined field id: " <<
The representative class of an id3v2 frame.
virtual size_type skipChars(size_type len)
Skip up to len chars in the stream and advance the internal position accordingly.
virtual pos_type setCur(pos_type pos)=0
Set the value of the current position for reading.
virtual pos_type getCur()=0
Return the current position in the reader.
virtual int_type readChar()
Read a single character and advance the internal position.
virtual pos_type getEnd()
Return the ending position in the reader.
virtual size_type remainingBytes()
virtual pos_type getBeg()
Return the beginning position in the reader.
virtual int_type peekChar()=0
Return the next character to be read without advancing the internal position.
virtual int_type writeChar(char_type ch)
Write a single character and advance the internal position.
ID3_C_EXPORT ID3_Frame * setLyricist(ID3_TagImpl &, String)
ID3_C_EXPORT ID3_Frame * setLyrics(ID3_TagImpl &, String, String, String)
ID3_C_EXPORT ID3_Frame * setAlbum(ID3_TagImpl &, String)
ID3_C_EXPORT ID3_Frame * setTitle(ID3_TagImpl &, String)
ID3_C_EXPORT ID3_Frame * setArtist(ID3_TagImpl &, String)
ID3_C_EXPORT ID3_Frame * hasArtist(const ID3_TagImpl &)
ID3_C_EXPORT ID3_Frame * setComment(ID3_TagImpl &, String, String, String)
ID3_C_EXPORT ID3_Frame * hasTitle(const ID3_TagImpl &)
ID3_C_EXPORT ID3_Frame * hasAlbum(const ID3_TagImpl &)
ID3_C_EXPORT ID3_Frame * setSyncLyrics(ID3_TagImpl &, BString, ID3_TimeStampFormat, String, String, ID3_ContentType)
bool parse(ID3_TagImpl &, ID3_Reader &)
bool parse(ID3_TagImpl &, ID3_Reader &)
const T & min(const T &a, const T &b)