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

src/tag_parse_lyrics3.cpp

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

Generated at Sat Sep 8 15:51:10 2001 for id3lib by doxygen1.2.8 written by Dimitri van Heesch, © 1997-2001