//========================================================================= // FILENAME : tagutils-misc.c // DESCRIPTION : Misc routines for supporting tagutils //========================================================================= // Copyright (c) 2008- NETGEAR, Inc. All Rights Reserved. //========================================================================= /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /************************************************************************** * Language **************************************************************************/ #define MAX_ICONV_BUF 1024 typedef enum { ICONV_OK, ICONV_TRYNEXT, ICONV_FATAL } iconv_result; static iconv_result do_iconv(const char* to_ces, const char* from_ces, char *inbuf, size_t inbytesleft, char *outbuf_orig, size_t outbytesleft_orig) { size_t rc; iconv_result ret = ICONV_OK; size_t outbytesleft = outbytesleft_orig - 1; char* outbuf = outbuf_orig; iconv_t cd = iconv_open(to_ces, from_ces); if (cd == (iconv_t)-1) { return ICONV_FATAL; } rc = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); if (rc == (size_t)-1) { if (errno == E2BIG) { ret = ICONV_FATAL; } else { ret = ICONV_TRYNEXT; memset(outbuf_orig, '\0', outbytesleft_orig); } } iconv_close(cd); return ret; } #define N_LANG_ALT 8 struct { char *lang; char *cpnames[N_LANG_ALT]; } iconv_map[] = { {"JA", {"ISO-8859-1", "CP932", "ISO8859-1", "CP950", "CP936", 0}}, {"ZH_CN", {"ISO-8859-1", "CP936", "CP950", "CP932", 0}}, {"ZH_TW", {"ISO-8859-1", "CP950", "CP936", "CP932", 0}}, {0, {0}} }; static int lang_index = -1; static int _lang2cp(char *lang) { int cp; if (!lang || lang[0]=='\0') return -1; for (cp=0; iconv_map[cp].lang; cp++) { if (!strcasecmp(iconv_map[cp].lang, lang)) return cp; } return -1; } static unsigned char* _get_utf8_text(const id3_ucs4_t* native_text) { unsigned char *utf8_text = NULL; char *in, *in8, *iconv_buf; iconv_result rc; int i, n; in = (char*) id3_ucs4_latin1duplicate(native_text); if (!in) { goto out; } in8 = (char*) id3_ucs4_utf8duplicate(native_text); if (!in8) { free(in); goto out; } iconv_buf = (char*) calloc(MAX_ICONV_BUF, sizeof(char)); if (!iconv_buf) { free(in); free(in8); goto out; } i = lang_index; // (1) try utf8 -> default rc = do_iconv(iconv_map[i].cpnames[0], "UTF-8", in8, strlen(in8), iconv_buf, MAX_ICONV_BUF); if (rc == ICONV_OK) { utf8_text = (unsigned char*) in8; free(iconv_buf); } else if (rc == ICONV_TRYNEXT) { // (2) try default -> utf8 rc = do_iconv("UTF-8", iconv_map[i].cpnames[0], in, strlen(in), iconv_buf, MAX_ICONV_BUF); if (rc == ICONV_OK) { utf8_text = (unsigned char*) iconv_buf; } else if (rc == ICONV_TRYNEXT) { // (3) try other encodes for (n=1; n(sizeof(strbuf)-1)) { DPRINTF(E_ERROR, L_SCAN, "Vorbis Comment too long\n"); return; } strncpy(strbuf, comment, length); strbuf[length] = '\0'; // ALBUM, ARTIST, PUBLISHER, COPYRIGHT, DISCNUMBER, ISRC, EAN/UPN, LABEL, LABELNO, // LICENSE, OPUS, SOURCEMEDIA, TITLE, TRACKNUMBER, VERSION, ENCODED-BY, ENCODING, // -- foollowing tags are muliples // COMPOSER, ARRANGER, LYRICIST, AUTHOR, CONDUCTOR, PERFORMER, ENSEMBLE, PART // PARTNUMBER, GENRE, DATE, LOCATION, COMMENT if (!strncasecmp(strbuf, "ALBUM=", 6)) { psong->album = strdup(strbuf+6); } else if (!strncasecmp(strbuf, "ARTIST=", 7)) { psong->contributor[ROLE_ARTIST] = strdup(strbuf+7); } else if (!strncasecmp(strbuf, "ARTISTSORT=", 11)) { psong->contributor_sort[ROLE_ARTIST] = strdup(strbuf+11); } else if (!strncasecmp(strbuf, "TITLE=",6)) { psong->title = strdup(strbuf+6); } else if (!strncasecmp(strbuf, "TRACKNUMBER=", 12)) { psong->track = atoi(strbuf+12); } else if (!strncasecmp(strbuf, "DISCNUMBER=", 11)) { psong->disc = atoi(strbuf+11); } else if (!strncasecmp(strbuf, "GENRE=", 6)) { psong->genre = strdup(strbuf+6); } else if (!strncasecmp(strbuf, "DATE=", 5)) { if (length>=(5+10) && isdigit(strbuf[5+0]) && isdigit(strbuf[5+1]) && ispunct(strbuf[5+2]) && isdigit(strbuf[5+3]) && isdigit(strbuf[5+4]) && ispunct(strbuf[5+5]) && isdigit(strbuf[5+6]) && isdigit(strbuf[5+7]) && isdigit(strbuf[5+8]) && isdigit(strbuf[5+9])) { // nn-nn-yyyy strbuf[5+10] = '\0'; psong->year = atoi(strbuf+5+6); } else { // year first. year is at most 4 digit. strbuf[5+4] = '\0'; psong->year = atoi(strbuf+5); } } else if (!strncasecmp(strbuf, "COMMENT=", 8)) { psong->comment = strdup(strbuf+8); } else if (!strncasecmp(strbuf, "MUSICBRAINZ_ALBUMID=",20)) { psong->musicbrainz_albumid = strdup(strbuf+20); } else if (!strncasecmp(strbuf, "MUSICBRAINZ_TRACKID=",20)) { psong->musicbrainz_trackid = strdup(strbuf+20); } else if (!strncasecmp(strbuf, "MUSICBRAINZ_TRACKID=",20)) { psong->musicbrainz_trackid = strdup(strbuf+20); } else if (!strncasecmp(strbuf, "MUSICBRAINZ_ARTISTID=",21)) { psong->musicbrainz_artistid = strdup(strbuf+21); } else if (!strncasecmp(strbuf, "MUSICBRAINZ_ALBUMARTISTID=",26)) { psong->musicbrainz_albumartistid = strdup(strbuf+26); } }