id3lib 3.8.3
tag_parse_lyrics3.cpp
Go to the documentation of this file.
1// $Id: tag_parse_lyrics3.cpp,v 1.35 2002/10/04 08:52:23 t1mpy Exp $
2
3// id3lib: a C++ library for creating and manipulating id3v1/v2 tags
4// Copyright 1999, 2000 Scott Thomas Haug
5// Copyright 2002 Thijmen Klok (thijmen@id3lib.org)
6
7// This library is free software; you can redistribute it and/or modify it
8// under the terms of the GNU Library General Public License as published by
9// the Free Software Foundation; either version 2 of the License, or (at your
10// option) any later version.
11//
12// This library is distributed in the hope that it will be useful, but WITHOUT
13// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
15// License for more details.
16//
17// You should have received a copy of the GNU Library General Public License
18// along with this library; if not, write to the Free Software Foundation,
19// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21// The id3lib authors encourage improvements and optimisations to be sent to
22// the id3lib coordinator. Please see the README file for details on where to
23// send such submissions. See the AUTHORS file for a list of people who have
24// contributed to id3lib. See the ChangeLog file for a list of changes to
25// id3lib. These files are distributed with id3lib at
26// http://download.sourceforge.net/id3lib/
27
28#include <ctype.h>
29#include <memory.h>
30#include "tag_impl.h" //has <stdio.h> "tag.h" "header_tag.h" "frame.h" "field.h" "spec.h" "id3lib_strings.h" "utils.h"
31#include "helpers.h"
32#include "id3/io_decorators.h" //has "readers.h" "io_helpers.h" "utils.h"
33#include "io_strings.h"
34
35using namespace dami;
36
37namespace
38{
39 uint32 readIntegerString(ID3_Reader& reader, size_t numBytes)
40 {
41 uint32 val = 0;
42 for (size_t i = 0; i < numBytes && isdigit(reader.peekChar()); ++i)
43 {
44 val = (val * 10) + (reader.readChar() - '0');
45 }
46 ID3D_NOTICE( "readIntegerString: val = " << val );
47 return val;
48 }
49
50 uint32 readIntegerString(ID3_Reader& reader)
51 {
52 return readIntegerString(reader, reader.remainingBytes());
53 }
54
55 bool isTimeStamp(ID3_Reader& reader)
56 {
57 ID3_Reader::pos_type cur = reader.getCur();
58 if (reader.getEnd() < cur + 7)
59 {
60 return false;
61 }
62 bool its = ('[' == reader.readChar() &&
63 isdigit(reader.readChar()) && isdigit(reader.readChar()) &&
64 ':' == reader.readChar() &&
65 isdigit(reader.readChar()) && isdigit(reader.readChar()) &&
66 ']' == reader.readChar());
67 reader.setCur(cur);
68 if (its)
69 {
70 ID3D_NOTICE( "isTimeStamp(): found timestamp, cur = " << reader.getCur() );
71 }
72 return its;
73 }
74
75 uint32 readTimeStamp(ID3_Reader& reader)
76 {
77 reader.skipChars(1);
78 size_t sec = readIntegerString(reader, 2) * 60;
79 reader.skipChars(1);
80 sec += readIntegerString(reader, 2);
81 reader.skipChars(1);
82 ID3D_NOTICE( "readTimeStamp(): timestamp = " << sec );
83 return sec * 1000;
84 }
85
86 bool findText(ID3_Reader& reader, String text)
87 {
88 if (text.empty())
89 {
90 return true;
91 }
92
93 size_t index = 0;
94 while (!reader.atEnd())
95 {
96 ID3_Reader::char_type ch = reader.readChar();
97 if (ch == text[index])
98 {
99 index++;
100 }
101 else if (ch == text[0])
102 {
103 index = 1;
104 }
105 else
106 {
107 index = 0;
108 }
109 if (index == text.size())
110 {
111 reader.setCur(reader.getCur() - index);
112 ID3D_NOTICE( "findText: found \"" << text << "\" at " <<
113 reader.getCur() );
114 break;
115 }
116 }
117 return !reader.atEnd();
118 };
119
120 void lyrics3ToSylt(ID3_Reader& reader, ID3_Writer& writer)
121 {
122 while (!reader.atEnd())
123 {
124 bool lf = false;
125 size_t ms = 0;
126 size_t count = 0;
127 while (isTimeStamp(reader))
128 {
129 // For now, just skip over multiple time stamps
130 if (count++ > 0)
131 {
132 readTimeStamp(reader);
133 }
134 else
135 {
136 ms = readTimeStamp(reader);
137 }
138 }
139 while (!reader.atEnd() && !isTimeStamp(reader))
140 {
141 ID3_Reader::char_type ch = reader.readChar();
142 if (0x0A == ch && (reader.atEnd() || isTimeStamp(reader)))
143 {
144 lf = true;
145 break;
146 }
147 else
148 {
149 writer.writeChar(ch);
150 }
151 }
152
153 // put synch identifier
154 writer.writeChar('\0');
155
156 // put timestamp
157 ID3D_NOTICE( "lyrics3toSylt: ms = " << ms );
158
159 io::writeBENumber(writer, ms, sizeof(uint32));
160 if (lf)
161 {
162 ID3D_NOTICE( "lyrics3toSylt: adding lf" );
163
164 // put the LF
165 writer.writeChar(0x0A);
166 }
167 }
168 }
169};
170
172{
173 io::ExitTrigger et(reader);
174 ID3_Reader::pos_type end = reader.getCur();
175 if (end < reader.getBeg() + 9 + 128)
176 {
177 ID3D_NOTICE( "id3::v1::parse: bailing, not enough bytes to parse, pos = " << end );
178 return false;
179 }
180 reader.setCur(end - (9 + 128));
181
182 {
183 if (io::readText(reader, 9) != "LYRICSEND" ||
184 io::readText(reader, 3) != "TAG")
185 {
186 return false;
187 }
188 }
189
190 // we have a Lyrics3 v1.00 tag
191 if (end < reader.getBeg() + 11 + 9 + 128)
192 {
193 // the file size isn't large enough to actually hold lyrics
194 ID3D_WARNING( "id3::v1::parse: not enough data to parse lyrics3" );
195 return false;
196 }
197
198 // reserve enough space for lyrics3 + id3v1 tag
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));
203
204 if (!findText(wr, "LYRICSBEGIN"))
205 {
206 ID3D_WARNING( "id3::v1::parse: couldn't find LYRICSBEGIN, bailing" );
207 return false;
208 }
209
210 et.setExitPos(wr.getCur());
211 wr.skipChars(11);
212 wr.setBeg(wr.getCur());
213
214 io::LineFeedReader lfr(wr);
215 String lyrics = io::readText(lfr, wr.remainingBytes());
216 id3::v2::setLyrics(tag, lyrics, "Converted from Lyrics3 v1.00", "XXX");
217
218 return true;
219}
220
221//bool parse(TagImpl& tag, ID3_Reader& reader)
223{
224 io::ExitTrigger et(reader);
225 ID3_Reader::pos_type end = reader.getCur();
226 if (end < reader.getBeg() + 6 + 9 + 128)
227 {
228 ID3D_NOTICE( "lyr3::v2::parse: bailing, not enough bytes to parse, pos = " << reader.getCur() );
229 return false;
230 }
231
232 reader.setCur(end - (6 + 9 + 128));
233 uint32 lyrSize = 0;
234
235 ID3_Reader::pos_type beg = reader.getCur();
236 lyrSize = readIntegerString(reader, 6);
237 if (reader.getCur() < beg + 6)
238 {
239 ID3D_NOTICE( "lyr3::v2::parse: couldn't find numeric string, lyrSize = " <<
240 lyrSize );
241 return false;
242 }
243
244 if (io::readText(reader, 9) != "LYRICS200" ||
245 io::readText(reader, 3) != "TAG")
246 {
247 return false;
248 }
249
250 if (end < reader.getBeg() + lyrSize + 6 + 9 + 128)
251 {
252 ID3D_WARNING( "lyr3::v2::parse: not enough data to parse tag, lyrSize = " << lyrSize );
253 return false;
254 }
255 reader.setCur(end - (lyrSize + 6 + 9 + 128));
256
257 io::WindowedReader wr(reader);
258 wr.setWindow(wr.getCur(), lyrSize);
259
260 beg = wr.getCur();
261
262 if (io::readText(wr, 11) != "LYRICSBEGIN")
263 {
264 // not a lyrics v2.00 tag
265 ID3D_WARNING( "lyr3::v2::parse: couldn't find LYRICSBEGIN, bailing" );
266 return false;
267 }
268
269 bool has_time_stamps = false;
270
271 ID3_Frame* lyr_frame = NULL;
272
273 while (!wr.atEnd())
274 {
275 uint32 fldSize;
276
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 );
281
282 String fldData;
283
284 io::WindowedReader wr2(wr, fldSize);
285 io::LineFeedReader lfr(wr2);
286
287 fldData = io::readText(lfr, fldSize);
288 ID3D_NOTICE( "lyr3::v2::parse: fldData = \"" << fldData << "\"" );
289
290 // the IND field
291 if (fldName == "IND")
292 {
293 has_time_stamps = (fldData.size() > 1 && fldData[1] == '1');
294 }
295
296 // the TITLE field
297 else if (fldName == "ETT" && !id3::v2::hasTitle(tag))
298 {
299 //tag.setTitle(fldData);
300 id3::v2::setTitle(tag, fldData);
301 }
302
303 // the ARTIST field
304 else if (fldName == "EAR" && !id3::v2::hasArtist(tag))
305 {
306 //tag.setArtist(fldData);
307 id3::v2::setArtist(tag, fldData);
308 }
309
310 // the ALBUM field
311 else if (fldName == "EAL" && !id3::v2::hasAlbum(tag))
312 {
313 //tag.setAlbum(fldData);
314 id3::v2::setAlbum(tag, fldData);
315 }
316
317 // the Lyrics/Music AUTHOR field
318 else if (fldName == "AUT")
319 {
320 //tag.setAuthor(fldData);
321 id3::v2::setLyricist(tag, fldData);
322 }
323
324 // the INFORMATION field
325 else if (fldName == "INF")
326 {
327 //tag.setInfo(fldData);
328 id3::v2::setComment(tag, fldData, "Lyrics3 v2.00 INF", "XXX");
329 }
330
331 // the LYRICS field
332 else if (fldName == "LYR")
333 {
334 // if already found an INF field, use it as description
335 String desc = "Converted from Lyrics3 v2.00";
336 //tag.setLyrics(fldData);
337 if (!has_time_stamps)
338 {
339 lyr_frame = id3::v2::setLyrics(tag, fldData, desc, "XXX");
340 }
341 else
342 {
343 // converts from lyrics3 to SYLT in-place
344 io::StringReader sr(fldData);
345 ID3D_NOTICE( "lyr3::v2::parse: determining synced lyrics" );
346 BString sylt;
347 io::BStringWriter sw(sylt);
348 lyrics3ToSylt(sr, sw);
349
350 lyr_frame = id3::v2::setSyncLyrics(tag, sylt, ID3TSF_MS, desc,
351 "XXX", ID3CT_LYRICS);
352 ID3D_NOTICE( "lyr3::v2::parse: determined synced lyrics" );
353 }
354 }
355 else if (fldName == "IMG")
356 {
357 // currently unsupported
358 ID3D_WARNING( "lyr3::v2::parse: IMG field unsupported" );
359 }
360 else
361 {
362 ID3D_WARNING( "lyr3::v2::parse: undefined field id: " <<
363 fldName );
364 }
365 }
366
367 et.setExitPos(beg);
368 return true;
369}
370
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.
Definition reader.h:97
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 bool atEnd()
Definition reader.h:125
virtual int_type readChar()
Read a single character and advance the internal position.
Definition reader.h:65
virtual pos_type getEnd()
Return the ending position in the reader.
Definition reader.h:51
uint32 pos_type
Definition reader.h:38
virtual size_type remainingBytes()
Definition reader.h:109
uint8 char_type
Definition reader.h:37
virtual pos_type getBeg()
Return the beginning position in the reader.
Definition reader.h:48
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.
Definition writer.h:71
#define NULL
Definition globals.h:743
@ ID3CT_LYRICS
Definition globals.h:384
@ ID3TSF_MS
Definition globals.h:420
bool parse(ID3_TagImpl &, ID3_Reader &)
bool parse(ID3_TagImpl &, ID3_Reader &)

Generated for id3lib by doxygen 1.10.0