00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #if defined HAVE_CONFIG_H
00028 #include <config.h>
00029 #endif
00030
00031
00032
00033 #include <ctype.h>
00034
00035 #include "helpers.h"
00036 #include "tag_impl.h"
00037 #include "frame.h"
00038 #include "field.h"
00039 #include "utils.h"
00040
00041 using namespace dami;
00042
00043 String id3::v2::getString(const ID3_Frame* frame, ID3_FieldID fldName)
00044 {
00045 if (!frame)
00046 {
00047 return "";
00048 }
00049 ID3_Field* fp = frame->GetField(fldName);
00050 if (!fp)
00051 {
00052 return "";
00053 }
00054 ID3_TextEnc enc = fp->GetEncoding();
00055 fp->SetEncoding(ID3TE_ASCII);
00056
00057 String text(fp->GetRawText(), fp->Size());
00058
00059 fp->SetEncoding(enc);
00060 return text;
00061 }
00062
00063 String id3::v2::getStringAtIndex(const ID3_Frame* frame, ID3_FieldID fldName,
00064 size_t nIndex)
00065 {
00066 if (!frame)
00067 {
00068 return "";
00069 }
00070 String text;
00071 ID3_Field* fp = frame->GetField(fldName);
00072 if (fp && fp->GetNumTextItems() < nIndex)
00073 {
00074 ID3_TextEnc enc = fp->GetEncoding();
00075 fp->SetEncoding(ID3TE_ASCII);
00076
00077 text = fp->GetRawTextItem(nIndex);
00078
00079 fp->SetEncoding(enc);
00080 }
00081 return text;
00082 }
00083
00084 size_t id3::v2::removeFrames(ID3_TagImpl& tag, ID3_FrameID id)
00085 {
00086 size_t numRemoved = 0;
00087 ID3_Frame* frame = NULL;
00088
00089 while ((frame = tag.Find(id)) != NULL)
00090 {
00091 frame = tag.RemoveFrame(frame);
00092 delete frame;
00093 numRemoved++;
00094 }
00095
00096 return numRemoved;
00097 }
00098
00099 String id3::v2::getFrameText(const ID3_TagImpl& tag, ID3_FrameID id)
00100 {
00101 ID3_Frame* frame = tag.Find(id);
00102 return getString(frame, ID3FN_TEXT);
00103 }
00104
00105 ID3_Frame* id3::v2::setFrameText(ID3_TagImpl& tag, ID3_FrameID id, String text)
00106 {
00107 ID3_Frame* frame = tag.Find(id);
00108 if (!frame)
00109 {
00110 frame = new ID3_Frame(id);
00111 tag.AttachFrame(frame);
00112 }
00113 frame->GetField(ID3FN_TEXT)->Set(text.c_str());
00114
00115 return frame;
00116 }
00117
00118 ID3_Frame* id3::v2::hasArtist(const ID3_TagImpl& tag)
00119 {
00120 ID3_Frame* fp = NULL;
00121 (fp = tag.Find(ID3FID_LEADARTIST)) ||
00122 (fp = tag.Find(ID3FID_BAND)) ||
00123 (fp = tag.Find(ID3FID_CONDUCTOR)) ||
00124 (fp = tag.Find(ID3FID_COMPOSER));
00125 return fp;
00126 }
00127
00128 String id3::v2::getArtist(const ID3_TagImpl& tag)
00129 {
00130 ID3_Frame* frame = hasArtist(tag);
00131 return getString(frame, ID3FN_TEXT);
00132 }
00133
00134 ID3_Frame* id3::v2::setArtist(ID3_TagImpl& tag, String text)
00135 {
00136 removeArtists(tag);
00137 return setFrameText(tag, ID3FID_LEADARTIST, text);
00138 }
00139
00140 size_t id3::v2::removeArtists(ID3_TagImpl& tag)
00141 {
00142 size_t numRemoved = 0;
00143 ID3_Frame* frame = NULL;
00144
00145 while ((frame = hasArtist(tag)) != NULL)
00146 {
00147 frame = tag.RemoveFrame(frame);
00148 delete frame;
00149 numRemoved++;
00150 }
00151
00152 return numRemoved;
00153 }
00154
00155 String id3::v2::getAlbum(const ID3_TagImpl& tag)
00156 {
00157 return getFrameText(tag, ID3FID_ALBUM);
00158 }
00159
00160 ID3_Frame* id3::v2::setAlbum(ID3_TagImpl& tag, String text)
00161 {
00162 return setFrameText(tag, ID3FID_ALBUM, text);
00163 }
00164
00165 size_t id3::v2::removeAlbums(ID3_TagImpl& tag)
00166 {
00167 return removeFrames(tag, ID3FID_ALBUM);
00168 }
00169
00170 String id3::v2::getTitle(const ID3_TagImpl& tag)
00171 {
00172 return getFrameText(tag, ID3FID_TITLE);
00173 }
00174
00175 ID3_Frame* id3::v2::setTitle(ID3_TagImpl& tag, String text)
00176 {
00177 return setFrameText(tag, ID3FID_TITLE, text);
00178 }
00179
00180 size_t id3::v2::removeTitles(ID3_TagImpl& tag)
00181 {
00182 return removeFrames(tag, ID3FID_TITLE);
00183 }
00184
00185 String id3::v2::getYear(const ID3_TagImpl& tag)
00186 {
00187 return getFrameText(tag, ID3FID_YEAR);
00188 }
00189
00190 ID3_Frame* id3::v2::setYear(ID3_TagImpl& tag, String text)
00191 {
00192 return setFrameText(tag, ID3FID_YEAR, text);
00193 }
00194
00195 size_t id3::v2::removeYears(ID3_TagImpl& tag)
00196 {
00197 return removeFrames(tag, ID3FID_YEAR);
00198 }
00199
00200 String id3::v2::getV1Comment(const ID3_TagImpl& tag)
00201 {
00202 ID3_Frame* frame;
00203 (frame = tag.Find(ID3FID_COMMENT, ID3FN_DESCRIPTION, STR_V1_COMMENT_DESC)) ||
00204 (frame = tag.Find(ID3FID_COMMENT, ID3FN_DESCRIPTION, "" )) ||
00205 (frame = tag.Find(ID3FID_COMMENT));
00206 return getString(frame, ID3FN_TEXT);
00207 }
00208
00209 String id3::v2::getComment(const ID3_TagImpl& tag, String desc)
00210 {
00211 ID3_Frame* frame = tag.Find(ID3FID_COMMENT, ID3FN_DESCRIPTION, desc.c_str());
00212 return getString(frame, ID3FN_TEXT);
00213 }
00214
00215 ID3_Frame* id3::v2::setComment(ID3_TagImpl& tag, String text, String desc,
00216 String lang)
00217 {
00218 ID3D_NOTICE( "id3::v2::setComment: trying to find frame with description = " << desc );
00219 ID3_Frame* frame = NULL;
00220
00221 for (ID3_TagImpl::iterator iter = tag.begin(); iter != tag.end(); ++iter)
00222 {
00223 frame = *iter;
00224 if (frame == NULL)
00225 {
00226 continue;
00227 }
00228 if (frame->GetID() == ID3FID_COMMENT)
00229 {
00230 String tmpDesc = getString(frame, ID3FN_DESCRIPTION);
00231 if (tmpDesc == desc)
00232 {
00233 ID3D_NOTICE( "id3::v2::setComment: found frame with description = " << desc );
00234 break;
00235 }
00236 }
00237 frame = NULL;
00238 }
00239 if (frame == NULL)
00240 {
00241 ID3D_NOTICE( "id3::v2::setComment: creating new comment frame" );
00242 frame = new ID3_Frame(ID3FID_COMMENT);
00243 tag.AttachFrame(frame);
00244 }
00245 if (!frame)
00246 {
00247 ID3D_WARNING( "id3::v2::setComment: ack! no frame" );
00248 }
00249 else
00250 {
00251 frame->GetField(ID3FN_LANGUAGE)->Set(lang.c_str());
00252 frame->GetField(ID3FN_DESCRIPTION)->Set(desc.c_str());
00253 frame->GetField(ID3FN_TEXT)->Set(text.c_str());
00254 }
00255
00256 return frame;
00257 }
00258
00259
00260 size_t id3::v2::removeAllComments(ID3_TagImpl& tag)
00261 {
00262 return removeFrames(tag, ID3FID_COMMENT);
00263 }
00264
00265
00266 size_t id3::v2::removeComments(ID3_TagImpl& tag, String desc)
00267 {
00268 size_t numRemoved = 0;
00269
00270 for (ID3_TagImpl::iterator iter = tag.begin(); iter != tag.end(); ++iter)
00271 {
00272 ID3_Frame* frame = *iter;
00273 if (frame == NULL)
00274 {
00275 continue;
00276 }
00277 if (frame->GetID() == ID3FID_COMMENT)
00278 {
00279
00280
00281 String tmpDesc = getString(frame, ID3FN_DESCRIPTION);
00282 if (tmpDesc == desc)
00283 {
00284 frame = tag.RemoveFrame(frame);
00285 delete frame;
00286 numRemoved++;
00287 }
00288 }
00289 }
00290
00291 return numRemoved;
00292 }
00293
00294 String id3::v2::getTrack(const ID3_TagImpl& tag)
00295 {
00296 return getFrameText(tag, ID3FID_TRACKNUM);
00297 }
00298
00299 size_t id3::v2::getTrackNum(const ID3_TagImpl& tag)
00300 {
00301 String sTrack = getTrack(tag);
00302 return ::atoi(sTrack.c_str());
00303 }
00304
00305 ID3_Frame* id3::v2::setTrack(ID3_TagImpl& tag, uchar trk, uchar ttl)
00306 {
00307 ID3_Frame* frame = NULL;
00308 String track = toString((size_t)trk);
00309 if (ttl > 0)
00310 {
00311 track += "/";
00312 track += toString((size_t)ttl);
00313 }
00314 setFrameText(tag, ID3FID_TRACKNUM, track);
00315
00316 return frame;
00317 }
00318
00319 size_t id3::v2::removeTracks(ID3_TagImpl& tag)
00320 {
00321 return removeFrames(tag, ID3FID_TRACKNUM);
00322 }
00323
00324 String id3::v2::getGenre(const ID3_TagImpl& tag)
00325 {
00326 return getFrameText(tag, ID3FID_CONTENTTYPE);
00327 }
00328
00329 size_t id3::v2::getGenreNum(const ID3_TagImpl& tag)
00330 {
00331 String sGenre = getGenre(tag);
00332 size_t ulGenre = 0xFF;
00333 size_t size = sGenre.size();
00334
00335
00336
00337 index_t i = 0;
00338 if (i < size && size && sGenre[i] == '(')
00339 {
00340 ++i;
00341 while (i < size && isdigit(sGenre[i]))
00342 {
00343 ++i;
00344 }
00345 if (i < size && sGenre[i] == ')')
00346 {
00347
00348 ulGenre = min(0xFF, atoi(&sGenre[1]));
00349 }
00350 }
00351
00352 return ulGenre;
00353 }
00354
00355 ID3_Frame* id3::v2::setGenre(ID3_TagImpl& tag, size_t genre)
00356 {
00357 String sGenre = "(";
00358 sGenre += toString(genre) + ")";
00359 return setFrameText(tag, ID3FID_CONTENTTYPE, sGenre);
00360 }
00361
00362 size_t id3::v2::removeGenres(ID3_TagImpl& tag)
00363 {
00364 return removeFrames(tag, ID3FID_CONTENTTYPE);
00365 }
00366
00367 String id3::v2::getLyrics(const ID3_TagImpl& tag)
00368 {
00369 return getFrameText(tag, ID3FID_UNSYNCEDLYRICS);
00370 }
00371
00372 ID3_Frame* id3::v2::setLyrics(ID3_TagImpl& tag, String text, String desc,
00373 String lang)
00374 {
00375 ID3_Frame* frame = NULL;
00376
00377 for (ID3_TagImpl::iterator iter = tag.begin(); iter != tag.end(); ++iter)
00378 {
00379 frame = *iter;
00380 if (frame == NULL)
00381 {
00382 continue;
00383 }
00384 if (frame->GetID() == ID3FID_COMMENT)
00385 {
00386 String tmpDesc = getString(frame, ID3FN_DESCRIPTION);
00387 if (tmpDesc == desc)
00388 {
00389 break;
00390 }
00391 }
00392 frame = NULL;
00393 }
00394 if (frame == NULL)
00395 {
00396 frame = new ID3_Frame(ID3FID_UNSYNCEDLYRICS);
00397 tag.AttachFrame(frame);
00398 }
00399 frame->GetField(ID3FN_LANGUAGE)->Set(lang.c_str());
00400 frame->GetField(ID3FN_DESCRIPTION)->Set(desc.c_str());
00401 frame->GetField(ID3FN_TEXT)->Set(text.c_str());
00402
00403 return frame;
00404 }
00405
00406 size_t id3::v2::removeLyrics(ID3_TagImpl& tag)
00407 {
00408 return removeFrames(tag, ID3FID_UNSYNCEDLYRICS);
00409 }
00410
00411 String id3::v2::getLyricist(const ID3_TagImpl& tag)
00412 {
00413 return getFrameText(tag, ID3FID_LYRICIST);
00414 }
00415
00416 ID3_Frame* id3::v2::setLyricist(ID3_TagImpl& tag, String text)
00417 {
00418 return setFrameText(tag, ID3FID_LYRICIST, text);
00419 }
00420
00421 size_t id3::v2::removeLyricists(ID3_TagImpl& tag)
00422 {
00423 return removeFrames(tag, ID3FID_LYRICIST);
00424 }
00425
00426 ID3_Frame* id3::v2::setSyncLyrics(ID3_TagImpl& tag, BString data,
00427 ID3_TimeStampFormat format, String desc,
00428 String lang, ID3_ContentType type)
00429 {
00430 ID3_Frame* frame = NULL;
00431
00432
00433 (frame = tag.Find(ID3FID_SYNCEDLYRICS, ID3FN_LANGUAGE, lang)) ||
00434 (frame = tag.Find(ID3FID_SYNCEDLYRICS, ID3FN_DESCRIPTION, desc));
00435
00436 if (!frame)
00437 {
00438 frame = new ID3_Frame(ID3FID_SYNCEDLYRICS);
00439 tag.AttachFrame(frame);
00440 }
00441 frame->GetField(ID3FN_LANGUAGE)->Set(lang.c_str());
00442 frame->GetField(ID3FN_DESCRIPTION)->Set(desc.c_str());
00443 frame->GetField(ID3FN_TIMESTAMPFORMAT)->Set(format);
00444 frame->GetField(ID3FN_CONTENTTYPE)->Set(type);
00445 frame->GetField(ID3FN_DATA)->Set(data.data(), data.size());
00446
00447 return frame;
00448 }
00449
00450 BString id3::v2::getSyncLyrics(const ID3_TagImpl& tag, String lang, String desc)
00451 {
00452
00453 ID3_Frame* frame = NULL;
00454 (frame = tag.Find(ID3FID_SYNCEDLYRICS, ID3FN_LANGUAGE, lang)) ||
00455 (frame = tag.Find(ID3FID_SYNCEDLYRICS, ID3FN_DESCRIPTION, desc)) ||
00456 (frame = tag.Find(ID3FID_SYNCEDLYRICS));
00457
00458
00459 ID3_Field* fld = frame->GetField(ID3FN_DATA);
00460 return BString(reinterpret_cast<const BString::value_type *>(fld->GetRawBinary()), fld->Size());
00461 }
00462