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