1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087 |
- #include "ID3v2Metadata.h"
- #include "metadata/MetadataKeys.h"
- #include "nswasabi/ReferenceCounted.h"
- #include <stdlib.h>
- #include <stdio.h>
- api_metadata *ID3v2Metadata::metadata_api=0;
- static inline bool TestFlag(int flags, int flag_to_check)
- {
- if (flags & flag_to_check)
- return true;
- return false;
- }
- ID3v2Metadata::ID3v2Metadata()
- {
- id3v2_tag=0;
- #ifdef __APPLE__
- number_formatter = NULL;
- #endif
- }
- ID3v2Metadata::~ID3v2Metadata()
- {
- #ifdef __APPLE__
- if (NULL != number_formatter)
- CFRelease(number_formatter);
- #endif
- }
- int ID3v2Metadata::Initialize(api_metadata *metadata_api)
- {
- ID3v2Metadata::metadata_api = metadata_api;
- return NErr_Success;
- }
- int ID3v2Metadata::Initialize(nsid3v2_tag_t tag)
- {
- id3v2_tag = tag;
- return NErr_Success;
- }
- int ID3v2Metadata::GetGenre(int index, nx_string_t *value)
- {
- nx_string_t genre=0;
- int ret = NSID3v2_Tag_Text_Get(id3v2_tag, NSID3V2_FRAME_CONTENTTYPE, &genre, 0);
- if (ret != NErr_Success)
- return ret;
- if (index > 0)
- return NErr_EndOfEnumeration;
- if (genre)
- {
- *value = genre;
- #ifdef _WIN32
- // parse the (##) out of it
- wchar_t *tmp = genre->string;
- while (*tmp == ' ') tmp++;
- if (!wcsncmp(tmp, L"(RX)", 4))
- {
- *value = NXStringCreateFromUTF8("Remix");
- NXStringRelease(genre);
- if (*value)
- return NErr_Success;
- else
- return NErr_OutOfMemory;
- }
- else if (!wcsncmp(tmp, L"(CR)", 4))
- {
- *value = NXStringCreateFromUTF8("Cover");
- NXStringRelease(genre);
- if (*value)
- return NErr_Success;
- else
- return NErr_OutOfMemory;
- }
- if (*tmp == '(' || (*tmp >= '0' && *tmp <= '9')) // both (%d) and %d forms
- {
- int noparam = 0;
- if (*tmp == '(') tmp++;
- else noparam = 1;
- size_t genre_index = _wtoi(tmp);
- int cnt = 0;
- while (*tmp >= '0' && *tmp <= '9') cnt++, tmp++;
- while (*tmp == ' ') tmp++;
- if (((!*tmp && noparam) || (!noparam && *tmp == ')')) && cnt > 0)
- {
- if (genre_index < 256 && metadata_api)
- {
- int ret = metadata_api->GetGenre(genre_index, value);
- if (ret == NErr_Success)
- {
- NXStringRetain(*value);
- NXStringRelease(genre);
- return ret;
- }
- }
- }
- }
- #elif defined(__APPLE__)
- int ret = NErr_Success;
-
- CFMutableStringRef mutable_genre = CFStringCreateMutableCopy(NULL, 0, genre);
- CFStringTrimWhitespace(mutable_genre);
-
- CFIndex mutable_genre_length = CFStringGetLength(mutable_genre);
-
- if (kCFCompareEqualTo == CFStringCompareWithOptionsAndLocale(mutable_genre,
- CFSTR("(RX)"),
- CFRangeMake(0, mutable_genre_length),
- 0,
- NULL))
- {
- NXStringRelease(genre);
- *value = CFSTR("Remix");
- ret = NErr_Success;
- }
- else if (kCFCompareEqualTo == CFStringCompareWithOptionsAndLocale(mutable_genre,
- CFSTR("(CR)"),
- CFRangeMake(0, mutable_genre_length),
- 0,
- NULL))
- {
- NXStringRelease(genre);
- *value = CFSTR("Cover");
- ret = NErr_Success;
- }
- else
- {
- CFStringTrim(mutable_genre, CFSTR("("));
- CFStringTrim(mutable_genre, CFSTR(")"));
- mutable_genre_length = CFStringGetLength(mutable_genre);
- if (mutable_genre_length > 0
- && mutable_genre_length < 4)
- {
- if (NULL == number_formatter)
- {
- CFLocaleRef locale = CFLocaleCreate(NULL, CFSTR("en_US_POSIX"));
- number_formatter = CFNumberFormatterCreate(NULL, locale, kCFNumberFormatterDecimalStyle);
- CFRelease(locale);
- }
-
- SInt8 genre_index;
- CFRange number_range = CFRangeMake(0, mutable_genre_length);
- if (NULL != number_formatter
- && false != CFNumberFormatterGetValueFromString(number_formatter,
- mutable_genre,
- &number_range,
- kCFNumberSInt8Type,
- &genre_index)
- && number_range.length == mutable_genre_length
- && number_range.location == 0)
- {
-
- if (genre_index >= 0
- && genre_index < 256
- && metadata_api)
- {
- int ret = metadata_api->GetGenre(genre_index, value);
- if (ret == NErr_Success)
- {
- NXStringRetain(*value);
- NXStringRelease(genre);
- }
- ret = NErr_Success;
- }
- }
- }
- }
-
- CFRelease(mutable_genre);
- return ret;
- #elif defined(__linux__)
- char *tmp = genre->string;
- while (*tmp == ' ') tmp++;
- if (!strncmp(tmp, "(RX)", 4))
- {
- NXStringRelease(genre);
- return NXStringCreateWithUTF8(value, "Remix");
- }
- else if (!strncmp(tmp, "(CR)", 4))
- {
- NXStringRelease(genre);
- return NXStringCreateWithUTF8(value, "Cover");
- }
- if (*tmp == '(' || (*tmp >= '0' && *tmp <= '9')) // both (%d) and %d forms
- {
- int noparam = 0;
- if (*tmp == '(') tmp++;
- else noparam = 1;
- size_t genre_index = atoi(tmp);
- int cnt = 0;
- while (*tmp >= '0' && *tmp <= '9') cnt++, tmp++;
- while (*tmp == ' ') tmp++;
- if (((!*tmp && noparam) || (!noparam && *tmp == ')')) && cnt > 0)
- {
- if (genre_index < 256 && metadata_api)
- {
- int ret = metadata_api->GetGenre(genre_index, value);
- if (ret == NErr_Success)
- {
- NXStringRetain(*value);
- NXStringRelease(genre);
- return ret;
- }
- }
- }
- }
- #else
- #error port me!
- #endif
- }
- return NErr_Success;
- }
- static int ID3v2_GetText(nsid3v2_tag_t id3v2_tag, int frame_enum, unsigned int index, nx_string_t *value)
- {
- if (!id3v2_tag)
- return NErr_Empty;
- nsid3v2_frame_t frame;
- int ret = NSID3v2_Tag_GetFrame(id3v2_tag, frame_enum, &frame);
- if (ret != NErr_Success)
- return ret;
- if (index > 0)
- return NErr_EndOfEnumeration;
- return NSID3v2_Frame_Text_Get(frame, value, 0);
- }
- static int ID3v2_GetTXXX(nsid3v2_tag_t id3v2_tag, const char *description, unsigned int index, nx_string_t *value)
- {
- if (!id3v2_tag)
- return NErr_Empty;
- nsid3v2_frame_t frame;
- int ret = NSID3v2_Tag_TXXX_Find(id3v2_tag, description, &frame, 0);
- if (ret != NErr_Success)
- return ret;
- if (index > 0)
- return NErr_EndOfEnumeration;
- return NSID3v2_Frame_UserText_Get(frame, 0, value, 0);
- }
- static int ID3v2_GetComments(nsid3v2_tag_t id3v2_tag, const char *description, unsigned int index, nx_string_t *value)
- {
- if (!id3v2_tag)
- return NErr_Empty;
- nsid3v2_frame_t frame;
- int ret = NSID3v2_Tag_Comments_Find(id3v2_tag, description, &frame, 0);
- if (ret != NErr_Success)
- return ret;
- if (index > 0)
- return NErr_EndOfEnumeration;
- return NSID3v2_Frame_Comments_Get(frame, 0, 0, value, 0);
- }
- // only one of value1 or value2 should be non-NULL
- static int SplitSlash(nx_string_t track, nx_string_t *value1, nx_string_t *value2)
- {
- char track_utf8[64];
- size_t bytes_copied;
- int ret;
- ret = NXStringGetBytes(&bytes_copied, track, track_utf8, 64, nx_charset_utf8, nx_string_get_bytes_size_null_terminate);
- if (ret == NErr_Success)
- {
- size_t len = strcspn(track_utf8, "/");
- if (value2)
- {
- const char *second = &track_utf8[len];
- if (*second)
- second++;
-
- if (!*second)
- return NErr_Empty;
- return NXStringCreateWithUTF8(value2, second);
- }
- else
- {
- if (len == 0)
- return NErr_Empty;
- return NXStringCreateWithBytes(value1, track_utf8, len, nx_charset_utf8);
- }
- return NErr_Success;
- }
- return ret;
- }
- /* ifc_metadata implementation */
- int ID3v2Metadata::Metadata_GetField(int field, unsigned int index, nx_string_t *value)
- {
- if (!id3v2_tag)
- return NErr_Unknown;
- int ret;
- switch (field)
- {
- case MetadataKeys::ARTIST:
- return ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_LEADARTIST, index, value);
- case MetadataKeys::ALBUM_ARTIST:
- ret = ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_BAND, index, value); /* Windows Media Player style */
- if (ret == NErr_Success || ret == NErr_EndOfEnumeration)
- return ret;
- ret = ID3v2_GetTXXX(id3v2_tag, "ALBUM ARTIST", index, value); /* foobar 2000 style */
- if (ret == NErr_Success || ret == NErr_EndOfEnumeration)
- return ret;
- ret = ID3v2_GetTXXX(id3v2_tag, "ALBUMARTIST", index, value); /* mp3tag style */
- if (ret == NErr_Success || ret == NErr_EndOfEnumeration)
- return ret;
- return ID3v2_GetTXXX(id3v2_tag, "Band", index, value); /* audacity style */
- case MetadataKeys::ALBUM:
- return ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_ALBUM, index, value);
- case MetadataKeys::TITLE:
- return ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_TITLE, index, value);
- case MetadataKeys::GENRE:
- return GetGenre(index, value);
- case MetadataKeys::TRACK:
- {
- ReferenceCountedNXString track;
- ret = ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_TRACK, index, &track);
- if (ret == NErr_Success)
- return SplitSlash(track, value, 0);
- return ret;
- }
- break;
- case MetadataKeys::TRACKS:
- {
- ReferenceCountedNXString track;
- ret = ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_TRACK, index, &track);
- if (ret == NErr_Success)
- return SplitSlash(track, 0, value);
- return ret;
- }
- break;
- case MetadataKeys::YEAR:
- ret = ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_RECORDINGTIME, index, value);
- if (ret == NErr_Success || ret == NErr_EndOfEnumeration)
- return ret;
- return ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_YEAR, index, value);
- case MetadataKeys::DISC:
- {
- ReferenceCountedNXString track;
- ret = ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_PARTOFSET, index, &track);
- if (ret == NErr_Success)
- return SplitSlash(track, value, 0);
- return ret;
- }
- break;
- case MetadataKeys::DISCS:
- {
- ReferenceCountedNXString track;
- ret = ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_PARTOFSET, index, &track);
- if (ret == NErr_Success)
- return SplitSlash(track, 0, value);
- return ret;
- }
- break;
- case MetadataKeys::COMPOSER:
- return ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_COMPOSER, index, value);
- case MetadataKeys::PUBLISHER:
- return ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_PUBLISHER, index, value);
- case MetadataKeys::BPM:
- return ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_BPM, index, value);
- case MetadataKeys::COMMENT:
- return ID3v2_GetComments(id3v2_tag, "", index, value);
- // TODO case MetadataKeys::PLAY_COUNT:
- // TODO case MetadataKeys::RATING:
- case MetadataKeys::TRACK_GAIN:
- return ID3v2_GetTXXX(id3v2_tag, "replaygain_track_gain", index, value);
- case MetadataKeys::TRACK_PEAK:
- return ID3v2_GetTXXX(id3v2_tag, "replaygain_track_peak", index, value);
- case MetadataKeys::ALBUM_GAIN:
- return ID3v2_GetTXXX(id3v2_tag, "replaygain_album_gain", index, value);
- case MetadataKeys::ALBUM_PEAK:
- return ID3v2_GetTXXX(id3v2_tag, "replaygain_album_peak", index, value);
- }
- return NErr_Unknown;
- }
- static int IncSafe(const char *&value, size_t &value_length, size_t increment_length)
- {
- /* eat leading spaces */
- while (*value == ' ' && value_length)
- {
- value++;
- value_length--;
- }
- if (increment_length > value_length)
- return NErr_NeedMoreData;
- value += increment_length;
- value_length -= increment_length;
- /* eat trailing spaces */
- while (*value == ' ' && value_length)
- {
- value++;
- value_length--;
- }
- return NErr_Success;
- }
- static int SplitSlashInteger(nx_string_t track, unsigned int *value1, unsigned int *value2)
- {
- char track_utf8[64];
- size_t bytes_copied;
- int ret;
- ret = NXStringGetBytes(&bytes_copied, track, track_utf8, 64, nx_charset_utf8, nx_string_get_bytes_size_null_terminate);
- if (ret == NErr_Success)
- {
- size_t len = strcspn(track_utf8, "/");
- if (track_utf8[len])
- *value2 = strtoul(&track_utf8[len+1], 0, 10);
- else
- *value2 = 0;
- track_utf8[len]=0;
- *value1 = strtoul(track_utf8, 0, 10);
- return NErr_Success;
- }
- return ret;
- }
- int ID3v2Metadata::Metadata_GetInteger(int field, unsigned int index, int64_t *value)
- {
- if (!id3v2_tag)
- return NErr_Unknown;
- switch(field)
- {
- case MetadataKeys::TRACK:
- {
- ReferenceCountedNXString track;
- int ret;
- ret = ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_TRACK, index, &track);
- if (ret == NErr_Success)
- {
- unsigned int itrack, itracks;
- ret = SplitSlashInteger(track, &itrack, &itracks);
- if (ret == NErr_Success)
- {
- if (itrack == 0)
- return NErr_Empty;
- *value = itrack;
- return NErr_Success;
- }
- }
- return ret;
- }
- break;
- case MetadataKeys::TRACKS:
- {
- ReferenceCountedNXString track;
- int ret;
- ret = ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_TRACK, index, &track);
- if (ret == NErr_Success)
- {
- unsigned int itrack, itracks;
- ret = SplitSlashInteger(track, &itrack, &itracks);
- if (ret == NErr_Success)
- {
- if (itracks == 0)
- return NErr_Empty;
- *value = itracks;
- return NErr_Success;
- }
- }
- return ret;
- }
- break;
- case MetadataKeys::DISC:
- {
- ReferenceCountedNXString track;
- int ret;
- ret = ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_PARTOFSET, index, &track);
- if (ret == NErr_Success)
- {
- unsigned int idisc, idiscs;
- ret = SplitSlashInteger(track, &idisc, &idiscs);
- if (ret == NErr_Success)
- {
- if (idisc == 0)
- return NErr_Empty;
- *value = idisc;
- return NErr_Success;
- }
- }
- return ret;
- }
- break;
- case MetadataKeys::DISCS:
- {
- ReferenceCountedNXString track;
- int ret;
- ret = ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_PARTOFSET, index, &track);
- if (ret == NErr_Success)
- {
- unsigned int idisc, idiscs;
- ret = SplitSlashInteger(track, &idisc, &idiscs);
- if (ret == NErr_Success)
- {
- if (idiscs == 0)
- return NErr_Empty;
- *value = idiscs;
- return NErr_Success;
- }
- }
- return ret;
- }
- break;
- case MetadataKeys::BPM:
- {
- ReferenceCountedNXString bpm;
- int ret;
- ret = ID3v2_GetText(id3v2_tag, NSID3V2_FRAME_BPM, index, &bpm);
- if (ret == NErr_Success)
- {
- /* TODO: benski> implement NXStringGetInt64Value */
- int value32;
- ret = NXStringGetIntegerValue(bpm, &value32);
- if (ret != NErr_Success)
- return ret;
- *value = value32;
- return NErr_Success;
- }
- return ret;
- }
- case MetadataKeys::PREGAP:
- {
- ReferenceCountedNXString str;
- char language[3];
- int ret = NSID3v2_Tag_Comments_Get(id3v2_tag, "iTunSMPB", language, &str, 0);
- if (ret == NErr_Success)
- {
- if (index > 0)
- return NErr_EndOfEnumeration;
- const char *itunsmpb;
- size_t itunsmpb_length;
- char temp[64] = {0};
- if (NXStringGetCString(str, temp, sizeof(temp)/sizeof(*temp), &itunsmpb, &itunsmpb_length) == NErr_Success)
- {
- /* skip first set of meaningless values */
- if (IncSafe(itunsmpb, itunsmpb_length, 8) == NErr_Success && itunsmpb_length >= 8)
- {
- /* read pre-gap */
- *value = strtoul(itunsmpb, 0, 16);
- return NErr_Success;
- }
- }
- return NErr_Error;
- }
- else
- return ret;
- }
- case MetadataKeys::POSTGAP:
- {
- ReferenceCountedNXString str;
- char language[3];
- int ret = NSID3v2_Tag_Comments_Get(id3v2_tag, "iTunSMPB", language, &str, 0);
- if (ret == NErr_Success)
- {
- if (index > 0)
- return NErr_EndOfEnumeration;
- const char *itunsmpb;
- size_t itunsmpb_length;
- char temp[64] = {0};
- if (NXStringGetCString(str, temp, sizeof(temp)/sizeof(*temp), &itunsmpb, &itunsmpb_length) == NErr_Success)
- {
- /* two separate calls so we can skip spaces properly */
- if (IncSafe(itunsmpb, itunsmpb_length, 8) == NErr_Success && itunsmpb_length >= 8
- && IncSafe(itunsmpb, itunsmpb_length, 8) == NErr_Success && itunsmpb_length >= 8)
- {
- *value = strtoul(itunsmpb, 0, 16);
- return NErr_Success;
- }
- }
- return NErr_Error;
- }
- else
- return ret;
- }
- }
- return NErr_Unknown;
- }
- int ID3v2Metadata::Metadata_GetReal(int field, unsigned int index, double *value)
- {
- if (!id3v2_tag)
- return NErr_Unknown;
- int ret;
- nx_string_t str;
- switch (field)
- {
- case MetadataKeys::TRACK_GAIN:
- ret = ID3v2_GetTXXX(id3v2_tag, "replaygain_track_gain", index, &str);
- if (ret == NErr_Success)
- {
- ret = NXStringGetDoubleValue(str, value);
- NXStringRelease(str);
- }
- return ret;
- case MetadataKeys::TRACK_PEAK:
- ret = ID3v2_GetTXXX(id3v2_tag, "replaygain_track_peak", index, &str);
- if (ret == NErr_Success)
- {
- ret = NXStringGetDoubleValue(str, value);
- NXStringRelease(str);
- }
- return ret;
- case MetadataKeys::ALBUM_GAIN:
- ret = ID3v2_GetTXXX(id3v2_tag, "replaygain_album_gain", index, &str);
- if (ret == NErr_Success)
- {
- ret = NXStringGetDoubleValue(str, value);
- NXStringRelease(str);
- }
- return ret;
- case MetadataKeys::ALBUM_PEAK:
- ret = ID3v2_GetTXXX(id3v2_tag, "replaygain_album_peak", index, &str);
- if (ret == NErr_Success)
- {
- ret = NXStringGetDoubleValue(str, value);
- NXStringRelease(str);
- }
- return ret;
- }
- return NErr_Unknown;
- }
- static int ArtLookupType(uint8_t *id3v2_type, int metadata_key)
- {
- switch(metadata_key)
- {
- case MetadataKeys::ALBUM:
- *id3v2_type = 3;
- return NErr_Success;
- }
- return NErr_Unknown;
- }
- static int NXStringCreateWithMIME(nx_string_t *mime_type, nx_string_t in)
- {
- if (!mime_type)
- return NErr_Success;
- char temp[128];
- size_t copied;
- int ret = NXStringGetBytes(&copied, in, temp, 128, nx_charset_ascii, nx_string_get_bytes_size_null_terminate);
- if (ret != NErr_Success)
- return ret;
- if (strstr(temp, "/") != 0)
- {
- *mime_type = NXStringRetain(in);
- return NErr_Success;
- }
- else
- {
- char temp2[128];
- #ifdef _WIN32
- _snprintf(temp2, 127, "image/%s", temp);
- #else
- snprintf(temp2, 127, "image/%s", temp);
- #endif
- temp2[127]=0;
- return NXStringCreateWithUTF8(mime_type, temp2);
- }
- }
- int ID3v2Metadata::Metadata_GetArtwork(int field, unsigned int index, artwork_t *artwork, data_flags_t flags)
- {
- if (!id3v2_tag)
- return NErr_Unknown;
- uint8_t id3v2_picture_type;
- int ret = ArtLookupType(&id3v2_picture_type, field);
- if (ret != NErr_Success)
- return ret;
- if (!id3v2_tag)
- return NErr_Empty;
- bool found_one=false;
- nsid3v2_frame_t frame=0;
- ret = NSID3v2_Tag_GetFrame(id3v2_tag, NSID3V2_FRAME_PICTURE, &frame);
- if (ret != NErr_Success)
- return ret;
- for (;;)
- {
- uint8_t this_type;
- if (NSID3v2_Frame_Picture_Get(frame, 0, &this_type, 0, 0, 0, 0) == NErr_Success && (this_type == id3v2_picture_type || (id3v2_picture_type == 3 && this_type == 0)))
- {
- found_one=true;
- if (index == 0)
- {
- if (artwork)
- {
- nx_data_t data=0;
- if (flags != DATA_FLAG_NONE)
- {
- const void *picture_data;
- size_t picture_length;
- ReferenceCountedNXString mime_local, description;
- ret = NSID3v2_Frame_Picture_Get(frame, TestFlag(flags, DATA_FLAG_MIME)?(&mime_local):0, &this_type, TestFlag(flags, DATA_FLAG_DESCRIPTION)?(&description):0, &picture_data, &picture_length, 0);
- if (ret != NErr_Success)
- return ret;
- if (TestFlag(flags, DATA_FLAG_DATA))
- {
- ret = NXDataCreate(&data, picture_data, picture_length);
- if (ret != NErr_Success)
- return ret;
- }
- else
- {
- ret = NXDataCreateEmpty(&data);
- if (ret != NErr_Success)
- return ret;
- }
- if (mime_local)
- {
- ReferenceCountedNXString mime_type;
- ret = NXStringCreateWithMIME(&mime_type, mime_local);
- if (ret != NErr_Success)
- {
- NXDataRelease(data);
- return ret;
- }
- NXDataSetMIME(data, mime_type);
- }
- if (description)
- {
- NXDataSetDescription(data, description);
- }
- }
- artwork->data = data;
- /* id3v2 doesn't store height and width, so zero these */
- artwork->width=0;
- artwork->height=0;
- }
- return NErr_Success;
- }
- else
- {
- index--; // keep looking
- }
- }
- if (NSID3v2_Tag_GetNextFrame(id3v2_tag, frame, &frame) != NErr_Success)
- {
- if (found_one)
- return NErr_EndOfEnumeration;
- else
- return NErr_Empty;
- }
- }
- }
- static int SetText(nsid3v2_tag_t id3v2_tag, int frame_id, unsigned int index, nx_string_t value)
- {
- if (index > 0)
- return NErr_Success;
- if (!value)
- {
- nsid3v2_frame_t frame;
- if (NSID3v2_Tag_GetFrame(id3v2_tag, frame_id, &frame) == NErr_Success)
- {
- for(;;)
- {
- nsid3v2_frame_t next;
- int ret = NSID3v2_Tag_GetNextFrame(id3v2_tag, frame, &next);
- NSID3v2_Tag_RemoveFrame(id3v2_tag, frame);
- if (ret != NErr_Success)
- break;
- frame=next;
- }
- }
- return NErr_Success;
- }
- else
- {
- return NSID3v2_Tag_Text_Set(id3v2_tag, frame_id, value, 0);
- }
- }
- static int SetTXXX(nsid3v2_tag_t id3v2_tag, const char *description, unsigned int index, nx_string_t value, int text_flags)
- {
- if (index > 0)
- return NErr_EndOfEnumeration;
- if (!value)
- {
- nsid3v2_frame_t frame;
- for(;;)
- {
- if (NSID3v2_Tag_TXXX_Find(id3v2_tag, description, &frame, text_flags) == NErr_Success)
- NSID3v2_Tag_RemoveFrame(id3v2_tag, frame);
- else
- return NErr_Success;
- }
- }
- else
- {
- return NSID3v2_Tag_TXXX_Set(id3v2_tag, description, value, 0);
- }
- }
- static int SetComments(nsid3v2_tag_t id3v2_tag, const char *description, unsigned int index, nx_string_t value, int text_flags)
- {
- if (index > 0)
- return NErr_EndOfEnumeration;
- if (!value)
- {
- nsid3v2_frame_t frame;
- for(;;)
- {
- if (NSID3v2_Tag_Comments_Find(id3v2_tag, description, &frame, text_flags) == NErr_Success)
- NSID3v2_Tag_RemoveFrame(id3v2_tag, frame);
- else
- return NErr_Success;
- }
- }
- else
- {
- return NSID3v2_Tag_Comments_Set(id3v2_tag, description, "\0\0\0", value, 0);
- }
- }
- int ID3v2Metadata::MetadataEditor_SetField(int field, unsigned int index, nx_string_t value)
- {
- int ret;
- switch (field)
- {
- case MetadataKeys::ARTIST:
- return SetText(id3v2_tag, NSID3V2_FRAME_LEADARTIST, index, value);
- case MetadataKeys::ALBUM_ARTIST:
- ret = SetText(id3v2_tag, NSID3V2_FRAME_BAND, index, value);
- /* delete some of the alternates */
- SetTXXX(id3v2_tag, "ALBUM ARTIST", index, 0, 0); /* foobar 2000 style */
- SetTXXX(id3v2_tag, "ALBUMARTIST", index, 0, 0); /* mp3tag style */
- if (!value) /* this might be a valid field, so only delete it if we're specifically deleting album artist (because otherwise, if it's here it's going to get picked up by GetField */
- SetTXXX(id3v2_tag, "Band", index, 0, 0); /* audacity style */
- return ret;
- case MetadataKeys::ALBUM:
- return SetText(id3v2_tag, NSID3V2_FRAME_ALBUM, index, value);
- case MetadataKeys::TITLE:
- return SetText(id3v2_tag, NSID3V2_FRAME_TITLE, index, value);
- case MetadataKeys::GENRE:
- return SetText(id3v2_tag, NSID3V2_FRAME_CONTENTTYPE, index, value);
- case MetadataKeys::YEAR:
- /* try to set "newer" style TDRC, first */
- ret = SetText(id3v2_tag, NSID3V2_FRAME_RECORDINGTIME, index, value);
- if (ret == NErr_Success)
- {
- /* if it succeeded, remove the older TYER tag */
- SetText(id3v2_tag, NSID3V2_FRAME_RECORDINGTIME, index, 0);
- return ret;
- }
- /* fall back to using TYER */
- return SetText(id3v2_tag, NSID3V2_FRAME_RECORDINGTIME, index, 0);
- case MetadataKeys::TRACK:
- return SetText(id3v2_tag, NSID3V2_FRAME_TRACK, index, value);
- case MetadataKeys::DISC:
- return SetText(id3v2_tag, NSID3V2_FRAME_PARTOFSET, index, value);
- case MetadataKeys::COMPOSER:
- return SetText(id3v2_tag, NSID3V2_FRAME_COMPOSER, index, value);
- case MetadataKeys::PUBLISHER:
- return SetText(id3v2_tag, NSID3V2_FRAME_PUBLISHER, index, value);
- case MetadataKeys::BPM:
- return SetText(id3v2_tag, NSID3V2_FRAME_BPM, index, value);
- case MetadataKeys::COMMENT:
- return SetComments(id3v2_tag, "", index, value, 0);
- case MetadataKeys::TRACK_GAIN:
- return SetTXXX(id3v2_tag, "replaygain_track_gain", index, value, 0);
- case MetadataKeys::TRACK_PEAK:
- return SetTXXX(id3v2_tag, "replaygain_track_peak", index, value, 0);
- case MetadataKeys::ALBUM_GAIN:
- return SetTXXX(id3v2_tag, "replaygain_album_gain", index, value, 0);
- case MetadataKeys::ALBUM_PEAK:
- return SetTXXX(id3v2_tag, "replaygain_album_peak", index, value, 0);
- }
- return NErr_Unknown;
- }
- static int ID3v2_SetPicture(nsid3v2_frame_t frame, uint8_t id3v2_picture_type, artwork_t *artwork, data_flags_t flags)
- {
- int ret;
- const void *picture_data;
- size_t picture_length;
- ret = NXDataGet(artwork->data, &picture_data, &picture_length);
- if (ret != NErr_Success)
- return ret;
- ReferenceCountedNXString mime_type, description;
- if (TestFlag(flags, DATA_FLAG_MIME))
- NXDataGetMIME(artwork->data, &mime_type);
- if (TestFlag(flags, DATA_FLAG_DESCRIPTION))
- NXDataGetDescription(artwork->data, &description);
- return NSID3v2_Frame_Picture_Set(frame, mime_type, id3v2_picture_type, description, picture_data, picture_length, 0);
- }
- int ID3v2Metadata::MetadataEditor_SetArtwork(int field, unsigned int index, artwork_t *artwork, data_flags_t flags)
- {
- uint8_t id3v2_picture_type;
- int ret = ArtLookupType(&id3v2_picture_type, field);
- if (ret != NErr_Success)
- return ret;
- nsid3v2_frame_t frame=0;
- ret = NSID3v2_Tag_GetFrame(id3v2_tag, NSID3V2_FRAME_PICTURE, &frame);
- if (ret != NErr_Success)
- {
- if (artwork && artwork->data)
- {
- /* create a new one and store */
- int ret = NSID3v2_Tag_CreateFrame(id3v2_tag, NSID3V2_FRAME_PICTURE, 0, &frame);
- if (ret == NErr_Success)
- {
- ret = ID3v2_SetPicture(frame, id3v2_picture_type, artwork, flags);
- if (ret == NErr_Success)
- {
- ret = NSID3v2_Tag_AddFrame(id3v2_tag, frame);
- if (ret != NErr_Success)
- {
- NSID3v2_Tag_RemoveFrame(id3v2_tag, frame);
- }
- }
- }
- return ret;
- }
- else
- return NErr_Success;
- }
- for (;;)
- {
- /* iterate now, because we might delete the current frame */
- nsid3v2_frame_t next_frame=0;
- if (NSID3v2_Tag_GetNextFrame(id3v2_tag, frame, &next_frame) != NErr_Success)
- next_frame=0; /* just in case */
- uint8_t this_type;
- if (NSID3v2_Frame_Picture_Get(frame, 0, &this_type, 0, 0, 0, 0) == NErr_Success && (this_type == id3v2_picture_type || (id3v2_picture_type == 3 && this_type == 0)))
- {
- if (index == 0)
- {
- if (artwork && artwork->data)
- {
- return ID3v2_SetPicture(frame, id3v2_picture_type, artwork, flags);
- }
- else
- {
- NSID3v2_Tag_RemoveFrame(id3v2_tag, frame);
- }
- }
- else
- {
- index--; // keep looking
- }
- }
- if (!next_frame)
- {
- if (!artwork || !artwork->data)
- return NErr_Success;
- else
- {
- /* create a new one and store */
- int ret = NSID3v2_Tag_CreateFrame(id3v2_tag, NSID3V2_FRAME_PICTURE, 0, &frame);
- if (ret != NErr_Success)
- return ret;
- ret = ID3v2_SetPicture(frame, id3v2_picture_type, artwork, flags);
- if (ret != NErr_Success)
- return ret;
- ret = NSID3v2_Tag_AddFrame(id3v2_tag, frame);
- if (ret != NErr_Success)
- {
- NSID3v2_Tag_RemoveFrame(id3v2_tag, frame);
- }
- return ret;
- }
- }
- frame = next_frame;
- }
- return NErr_NotImplemented;
- }
|