Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

src/tag_parse_lyrics3.cpp

Go to the documentation of this file.
00001 // $Id: tag_parse_lyrics3.cpp,v 1.35 2002/10/04 08:52:23 t1mpy Exp $ 00002 00003 // id3lib: a C++ library for creating and manipulating id3v1/v2 tags 00004 // Copyright 1999, 2000 Scott Thomas Haug 00005 // Copyright 2002 Thijmen Klok (thijmen@id3lib.org) 00006 00007 // This library is free software; you can redistribute it and/or modify it 00008 // under the terms of the GNU Library General Public License as published by 00009 // the Free Software Foundation; either version 2 of the License, or (at your 00010 // option) any later version. 00011 // 00012 // This library is distributed in the hope that it will be useful, but WITHOUT 00013 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00015 // License for more details. 00016 // 00017 // You should have received a copy of the GNU Library General Public License 00018 // along with this library; if not, write to the Free Software Foundation, 00019 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00020 00021 // The id3lib authors encourage improvements and optimisations to be sent to 00022 // the id3lib coordinator. Please see the README file for details on where to 00023 // send such submissions. See the AUTHORS file for a list of people who have 00024 // contributed to id3lib. See the ChangeLog file for a list of changes to 00025 // id3lib. These files are distributed with id3lib at 00026 // http://download.sourceforge.net/id3lib/ 00027 00028 #include <ctype.h> 00029 #include <memory.h> 00030 #include "tag_impl.h" //has <stdio.h> "tag.h" "header_tag.h" "frame.h" "field.h" "spec.h" "id3lib_strings.h" "utils.h" 00031 #include "helpers.h" 00032 #include "id3/io_decorators.h" //has "readers.h" "io_helpers.h" "utils.h" 00033 #include "io_strings.h" 00034 00035 using namespace dami; 00036 00037 namespace 00038 { 00039 uint32 readIntegerString(ID3_Reader& reader, size_t numBytes) 00040 { 00041 uint32 val = 0; 00042 for (size_t i = 0; i < numBytes && isdigit(reader.peekChar()); ++i) 00043 { 00044 val = (val * 10) + (reader.readChar() - '0'); 00045 } 00046 ID3D_NOTICE( "readIntegerString: val = " << val ); 00047 return val; 00048 } 00049 00050 uint32 readIntegerString(ID3_Reader& reader) 00051 { 00052 return readIntegerString(reader, reader.remainingBytes()); 00053 } 00054 00055 bool isTimeStamp(ID3_Reader& reader) 00056 { 00057 ID3_Reader::pos_type cur = reader.getCur(); 00058 if (reader.getEnd() < cur + 7) 00059 { 00060 return false; 00061 } 00062 bool its = ('[' == reader.readChar() && 00063 isdigit(reader.readChar()) && isdigit(reader.readChar()) && 00064 ':' == reader.readChar() && 00065 isdigit(reader.readChar()) && isdigit(reader.readChar()) && 00066 ']' == reader.readChar()); 00067 reader.setCur(cur); 00068 if (its) 00069 { 00070 ID3D_NOTICE( "isTimeStamp(): found timestamp, cur = " << reader.getCur() ); 00071 } 00072 return its; 00073 } 00074 00075 uint32 readTimeStamp(ID3_Reader& reader) 00076 { 00077 reader.skipChars(1); 00078 size_t sec = readIntegerString(reader, 2) * 60; 00079 reader.skipChars(1); 00080 sec += readIntegerString(reader, 2); 00081 reader.skipChars(1); 00082 ID3D_NOTICE( "readTimeStamp(): timestamp = " << sec ); 00083 return sec * 1000; 00084 } 00085 00086 bool findText(ID3_Reader& reader, String text) 00087 { 00088 if (text.empty()) 00089 { 00090 return true; 00091 } 00092 00093 size_t index = 0; 00094 while (!reader.atEnd()) 00095 { 00096 ID3_Reader::char_type ch = reader.readChar(); 00097 if (ch == text[index]) 00098 { 00099 index++; 00100 } 00101 else if (ch == text[0]) 00102 { 00103 index = 1; 00104 } 00105 else 00106 { 00107 index = 0; 00108 } 00109 if (index == text.size()) 00110 { 00111 reader.setCur(reader.getCur() - index); 00112 ID3D_NOTICE( "findText: found \"" << text << "\" at " << 00113 reader.getCur() ); 00114 break; 00115 } 00116 } 00117 return !reader.atEnd(); 00118 }; 00119 00120 void lyrics3ToSylt(ID3_Reader& reader, ID3_Writer& writer) 00121 { 00122 while (!reader.atEnd()) 00123 { 00124 bool lf = false; 00125 size_t ms = 0; 00126 size_t count = 0; 00127 while (isTimeStamp(reader)) 00128 { 00129 // For now, just skip over multiple time stamps 00130 if (count++ > 0) 00131 { 00132 readTimeStamp(reader); 00133 } 00134 else 00135 { 00136 ms = readTimeStamp(reader); 00137 } 00138 } 00139 while (!reader.atEnd() && !isTimeStamp(reader)) 00140 { 00141 ID3_Reader::char_type ch = reader.readChar(); 00142 if (0x0A == ch && (reader.atEnd() || isTimeStamp(reader))) 00143 { 00144 lf = true; 00145 break; 00146 } 00147 else 00148 { 00149 writer.writeChar(ch); 00150 } 00151 } 00152 00153 // put synch identifier 00154 writer.writeChar('\0'); 00155 00156 // put timestamp 00157 ID3D_NOTICE( "lyrics3toSylt: ms = " << ms ); 00158 00159 io::writeBENumber(writer, ms, sizeof(uint32)); 00160 if (lf) 00161 { 00162 ID3D_NOTICE( "lyrics3toSylt: adding lf" ); 00163 00164 // put the LF 00165 writer.writeChar(0x0A); 00166 } 00167 } 00168 } 00169 }; 00170 00171 bool lyr3::v1::parse(ID3_TagImpl& tag, ID3_Reader& reader) 00172 { 00173 io::ExitTrigger et(reader); 00174 ID3_Reader::pos_type end = reader.getCur(); 00175 if (end < reader.getBeg() + 9 + 128) 00176 { 00177 ID3D_NOTICE( "id3::v1::parse: bailing, not enough bytes to parse, pos = " << end ); 00178 return false; 00179 } 00180 reader.setCur(end - (9 + 128)); 00181 00182 { 00183 if (io::readText(reader, 9) != "LYRICSEND" || 00184 io::readText(reader, 3) != "TAG") 00185 { 00186 return false; 00187 } 00188 } 00189 00190 // we have a Lyrics3 v1.00 tag 00191 if (end < reader.getBeg() + 11 + 9 + 128) 00192 { 00193 // the file size isn't large enough to actually hold lyrics 00194 ID3D_WARNING( "id3::v1::parse: not enough data to parse lyrics3" ); 00195 return false; 00196 } 00197 00198 // reserve enough space for lyrics3 + id3v1 tag 00199 size_t window = end - reader.getBeg(); 00200 size_t lyrDataSize = min<size_t>(window, 11 + 5100 + 9 + 128); 00201 reader.setCur(end - lyrDataSize); 00202 io::WindowedReader wr(reader, lyrDataSize - (9 + 128)); 00203 00204 if (!findText(wr, "LYRICSBEGIN")) 00205 { 00206 ID3D_WARNING( "id3::v1::parse: couldn't find LYRICSBEGIN, bailing" ); 00207 return false; 00208 } 00209 00210 et.setExitPos(wr.getCur()); 00211 wr.skipChars(11); 00212 wr.setBeg(wr.getCur()); 00213 00214 io::LineFeedReader lfr(wr); 00215 String lyrics = io::readText(lfr, wr.remainingBytes()); 00216 id3::v2::setLyrics(tag, lyrics, "Converted from Lyrics3 v1.00", "XXX"); 00217 00218 return true; 00219 } 00220 00221 //bool parse(TagImpl& tag, ID3_Reader& reader) 00222 bool lyr3::v2::parse(ID3_TagImpl& tag, ID3_Reader& reader) 00223 { 00224 io::ExitTrigger et(reader); 00225 ID3_Reader::pos_type end = reader.getCur(); 00226 if (end < reader.getBeg() + 6 + 9 + 128) 00227 { 00228 ID3D_NOTICE( "lyr3::v2::parse: bailing, not enough bytes to parse, pos = " << reader.getCur() ); 00229 return false; 00230 } 00231 00232 reader.setCur(end - (6 + 9 + 128)); 00233 uint32 lyrSize = 0; 00234 00235 ID3_Reader::pos_type beg = reader.getCur(); 00236 lyrSize = readIntegerString(reader, 6); 00237 if (reader.getCur() < beg + 6) 00238 { 00239 ID3D_NOTICE( "lyr3::v2::parse: couldn't find numeric string, lyrSize = " << 00240 lyrSize ); 00241 return false; 00242 } 00243 00244 if (io::readText(reader, 9) != "LYRICS200" || 00245 io::readText(reader, 3) != "TAG") 00246 { 00247 return false; 00248 } 00249 00250 if (end < reader.getBeg() + lyrSize + 6 + 9 + 128) 00251 { 00252 ID3D_WARNING( "lyr3::v2::parse: not enough data to parse tag, lyrSize = " << lyrSize ); 00253 return false; 00254 } 00255 reader.setCur(end - (lyrSize + 6 + 9 + 128)); 00256 00257 io::WindowedReader wr(reader); 00258 wr.setWindow(wr.getCur(), lyrSize); 00259 00260 beg = wr.getCur(); 00261 00262 if (io::readText(wr, 11) != "LYRICSBEGIN") 00263 { 00264 // not a lyrics v2.00 tag 00265 ID3D_WARNING( "lyr3::v2::parse: couldn't find LYRICSBEGIN, bailing" ); 00266 return false; 00267 } 00268 00269 bool has_time_stamps = false; 00270 00271 ID3_Frame* lyr_frame = NULL; 00272 00273 while (!wr.atEnd()) 00274 { 00275 uint32 fldSize; 00276 00277 String fldName = io::readText(wr, 3); 00278 ID3D_NOTICE( "lyr3::v2::parse: fldName = " << fldName ); 00279 fldSize = readIntegerString(wr, 5); 00280 ID3D_NOTICE( "lyr3::v2::parse: fldSize = " << fldSize ); 00281 00282 String fldData; 00283 00284 io::WindowedReader wr2(wr, fldSize); 00285 io::LineFeedReader lfr(wr2); 00286 00287 fldData = io::readText(lfr, fldSize); 00288 ID3D_NOTICE( "lyr3::v2::parse: fldData = \"" << fldData << "\"" ); 00289 00290 // the IND field 00291 if (fldName == "IND") 00292 { 00293 has_time_stamps = (fldData.size() > 1 && fldData[1] == '1'); 00294 } 00295 00296 // the TITLE field 00297 else if (fldName == "ETT" && !id3::v2::hasTitle(tag)) 00298 { 00299 //tag.setTitle(fldData); 00300 id3::v2::setTitle(tag, fldData); 00301 } 00302 00303 // the ARTIST field 00304 else if (fldName == "EAR" && !id3::v2::hasArtist(tag)) 00305 { 00306 //tag.setArtist(fldData); 00307 id3::v2::setArtist(tag, fldData); 00308 } 00309 00310 // the ALBUM field 00311 else if (fldName == "EAL" && !id3::v2::hasAlbum(tag)) 00312 { 00313 //tag.setAlbum(fldData); 00314 id3::v2::setAlbum(tag, fldData); 00315 } 00316 00317 // the Lyrics/Music AUTHOR field 00318 else if (fldName == "AUT") 00319 { 00320 //tag.setAuthor(fldData); 00321 id3::v2::setLyricist(tag, fldData); 00322 } 00323 00324 // the INFORMATION field 00325 else if (fldName == "INF") 00326 { 00327 //tag.setInfo(fldData); 00328 id3::v2::setComment(tag, fldData, "Lyrics3 v2.00 INF", "XXX"); 00329 } 00330 00331 // the LYRICS field 00332 else if (fldName == "LYR") 00333 { 00334 // if already found an INF field, use it as description 00335 String desc = "Converted from Lyrics3 v2.00"; 00336 //tag.setLyrics(fldData); 00337 if (!has_time_stamps) 00338 { 00339 lyr_frame = id3::v2::setLyrics(tag, fldData, desc, "XXX"); 00340 } 00341 else 00342 { 00343 // converts from lyrics3 to SYLT in-place 00344 io::StringReader sr(fldData); 00345 ID3D_NOTICE( "lyr3::v2::parse: determining synced lyrics" ); 00346 BString sylt; 00347 io::BStringWriter sw(sylt); 00348 lyrics3ToSylt(sr, sw); 00349 00350 lyr_frame = id3::v2::setSyncLyrics(tag, sylt, ID3TSF_MS, desc, 00351 "XXX", ID3CT_LYRICS); 00352 ID3D_NOTICE( "lyr3::v2::parse: determined synced lyrics" ); 00353 } 00354 } 00355 else if (fldName == "IMG") 00356 { 00357 // currently unsupported 00358 ID3D_WARNING( "lyr3::v2::parse: IMG field unsupported" ); 00359 } 00360 else 00361 { 00362 ID3D_WARNING( "lyr3::v2::parse: undefined field id: " << 00363 fldName ); 00364 } 00365 } 00366 00367 et.setExitPos(beg); 00368 return true; 00369 } 00370

Generated on Thu Jun 3 16:57:09 2004 for id3lib by doxygen 1.3.7