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