cannam@85: %{ cannam@85: /* cannam@85: * libid3tag - ID3 tag manipulation library cannam@85: * Copyright (C) 2000-2004 Underbit Technologies, Inc. cannam@85: * cannam@85: * This program is free software; you can redistribute it and/or modify cannam@85: * it under the terms of the GNU General Public License as published by cannam@85: * the Free Software Foundation; either version 2 of the License, or cannam@85: * (at your option) any later version. cannam@85: * cannam@85: * This program is distributed in the hope that it will be useful, cannam@85: * but WITHOUT ANY WARRANTY; without even the implied warranty of cannam@85: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the cannam@85: * GNU General Public License for more details. cannam@85: * cannam@85: * You should have received a copy of the GNU General Public License cannam@85: * along with this program; if not, write to the Free Software cannam@85: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA cannam@85: * cannam@85: * $Id: compat.gperf,v 1.11 2004/01/23 09:41:32 rob Exp $ cannam@85: */ cannam@85: cannam@85: # ifdef HAVE_CONFIG_H cannam@85: # include "config.h" cannam@85: # endif cannam@85: cannam@85: # include "global.h" cannam@85: cannam@85: # include cannam@85: # include cannam@85: cannam@85: # ifdef HAVE_ASSERT_H cannam@85: # include cannam@85: # endif cannam@85: cannam@85: # include "id3tag.h" cannam@85: # include "compat.h" cannam@85: # include "frame.h" cannam@85: # include "field.h" cannam@85: # include "parse.h" cannam@85: # include "ucs4.h" cannam@85: cannam@85: # define EQ(id) #id, 0 cannam@85: # define OBSOLETE 0, 0 cannam@85: # define TX(id) #id, translate_##id cannam@85: cannam@85: static id3_compat_func_t translate_TCON; cannam@85: %} cannam@85: struct id3_compat; cannam@85: %% cannam@85: # cannam@85: # ID3v2.2 and ID3v2.3 frames cannam@85: # cannam@85: # Only obsolete frames or frames with an equivalent ID3v2.4 frame ID are cannam@85: # listed here. If a frame ID is not listed, it is assumed that the same cannam@85: # frame ID is itself the equivalent ID3v2.4 frame ID. cannam@85: # cannam@85: # This list may also include frames with new content interpretations; the cannam@85: # translation function will rewrite the contents to comply with ID3v2.4. cannam@85: # cannam@85: BUF, EQ(RBUF) /* Recommended buffer size */ cannam@85: CNT, EQ(PCNT) /* Play counter */ cannam@85: COM, EQ(COMM) /* Comments */ cannam@85: CRA, EQ(AENC) /* Audio encryption */ cannam@85: CRM, OBSOLETE /* Encrypted meta frame [obsolete] */ cannam@85: EQU, OBSOLETE /* Equalization [obsolete] */ cannam@85: EQUA, OBSOLETE /* Equalization [obsolete] */ cannam@85: ETC, EQ(ETCO) /* Event timing codes */ cannam@85: GEO, EQ(GEOB) /* General encapsulated object */ cannam@85: IPL, EQ(TIPL) /* Involved people list */ cannam@85: IPLS, EQ(TIPL) /* Involved people list */ cannam@85: LNK, EQ(LINK) /* Linked information */ cannam@85: MCI, EQ(MCDI) /* Music CD identifier */ cannam@85: MLL, EQ(MLLT) /* MPEG location lookup table */ cannam@85: PIC, EQ(APIC) /* Attached picture */ cannam@85: POP, EQ(POPM) /* Popularimeter */ cannam@85: REV, EQ(RVRB) /* Reverb */ cannam@85: RVA, OBSOLETE /* Relative volume adjustment [obsolete] */ cannam@85: RVAD, OBSOLETE /* Relative volume adjustment [obsolete] */ cannam@85: SLT, EQ(SYLT) /* Synchronised lyric/text */ cannam@85: STC, EQ(SYTC) /* Synchronised tempo codes */ cannam@85: TAL, EQ(TALB) /* Album/movie/show title */ cannam@85: TBP, EQ(TBPM) /* BPM (beats per minute) */ cannam@85: TCM, EQ(TCOM) /* Composer */ cannam@85: TCO, TX(TCON) /* Content type */ cannam@85: TCON, TX(TCON) /* Content type */ cannam@85: TCR, EQ(TCOP) /* Copyright message */ cannam@85: TDA, OBSOLETE /* Date [obsolete] */ cannam@85: TDAT, OBSOLETE /* Date [obsolete] */ cannam@85: TDY, EQ(TDLY) /* Playlist delay */ cannam@85: TEN, EQ(TENC) /* Encoded by */ cannam@85: TFT, EQ(TFLT) /* File type */ cannam@85: TIM, OBSOLETE /* Time [obsolete] */ cannam@85: TIME, OBSOLETE /* Time [obsolete] */ cannam@85: TKE, EQ(TKEY) /* Initial key */ cannam@85: TLA, EQ(TLAN) /* Language(s) */ cannam@85: TLE, EQ(TLEN) /* Length */ cannam@85: TMT, EQ(TMED) /* Media type */ cannam@85: TOA, EQ(TOPE) /* Original artist(s)/performer(s) */ cannam@85: TOF, EQ(TOFN) /* Original filename */ cannam@85: TOL, EQ(TOLY) /* Original lyricist(s)/text writer(s) */ cannam@85: TOR, EQ(TDOR) /* Original release year [obsolete] */ cannam@85: TORY, EQ(TDOR) /* Original release year [obsolete] */ cannam@85: TOT, EQ(TOAL) /* Original album/movie/show title */ cannam@85: TP1, EQ(TPE1) /* Lead performer(s)/soloist(s) */ cannam@85: TP2, EQ(TPE2) /* Band/orchestra/accompaniment */ cannam@85: TP3, EQ(TPE3) /* Conductor/performer refinement */ cannam@85: TP4, EQ(TPE4) /* Interpreted, remixed, or otherwise modified by */ cannam@85: TPA, EQ(TPOS) /* Part of a set */ cannam@85: TPB, EQ(TPUB) /* Publisher */ cannam@85: TRC, EQ(TSRC) /* ISRC (international standard recording code) */ cannam@85: TRD, OBSOLETE /* Recording dates [obsolete] */ cannam@85: TRDA, OBSOLETE /* Recording dates [obsolete] */ cannam@85: TRK, EQ(TRCK) /* Track number/position in set */ cannam@85: TSI, OBSOLETE /* Size [obsolete] */ cannam@85: TSIZ, OBSOLETE /* Size [obsolete] */ cannam@85: TSS, EQ(TSSE) /* Software/hardware and settings used for encoding */ cannam@85: TT1, EQ(TIT1) /* Content group description */ cannam@85: TT2, EQ(TIT2) /* Title/songname/content description */ cannam@85: TT3, EQ(TIT3) /* Subtitle/description refinement */ cannam@85: TXT, EQ(TEXT) /* Lyricist/text writer */ cannam@85: TXX, EQ(TXXX) /* User defined text information frame */ cannam@85: TYE, OBSOLETE /* Year [obsolete] */ cannam@85: TYER, OBSOLETE /* Year [obsolete] */ cannam@85: UFI, EQ(UFID) /* Unique file identifier */ cannam@85: ULT, EQ(USLT) /* Unsynchronised lyric/text transcription */ cannam@85: WAF, EQ(WOAF) /* Official audio file webpage */ cannam@85: WAR, EQ(WOAR) /* Official artist/performer webpage */ cannam@85: WAS, EQ(WOAS) /* Official audio source webpage */ cannam@85: WCM, EQ(WCOM) /* Commercial information */ cannam@85: WCP, EQ(WCOP) /* Copyright/legal information */ cannam@85: WPB, EQ(WPUB) /* Publishers official webpage */ cannam@85: WXX, EQ(WXXX) /* User defined URL link frame */ cannam@85: %% cannam@85: cannam@85: static cannam@85: int translate_TCON(struct id3_frame *frame, char const *oldid, cannam@85: id3_byte_t const *data, id3_length_t length) cannam@85: { cannam@85: id3_byte_t const *end; cannam@85: enum id3_field_textencoding encoding; cannam@85: id3_ucs4_t *string = 0, *ptr, *endptr; cannam@85: int result = 0; cannam@85: cannam@85: /* translate old TCON syntax into multiple strings */ cannam@85: cannam@85: assert(frame->nfields == 2); cannam@85: cannam@85: encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1; cannam@85: cannam@85: end = data + length; cannam@85: cannam@85: if (id3_field_parse(&frame->fields[0], &data, end - data, &encoding) == -1) cannam@85: goto fail; cannam@85: cannam@85: string = id3_parse_string(&data, end - data, encoding, 0); cannam@85: if (string == 0) cannam@85: goto fail; cannam@85: cannam@85: ptr = string; cannam@85: while (*ptr == '(') { cannam@85: if (*++ptr == '(') cannam@85: break; cannam@85: cannam@85: endptr = ptr; cannam@85: while (*endptr && *endptr != ')') cannam@85: ++endptr; cannam@85: cannam@85: if (*endptr) cannam@85: *endptr++ = 0; cannam@85: cannam@85: if (id3_field_addstring(&frame->fields[1], ptr) == -1) cannam@85: goto fail; cannam@85: cannam@85: ptr = endptr; cannam@85: } cannam@85: cannam@85: if (*ptr && id3_field_addstring(&frame->fields[1], ptr) == -1) cannam@85: goto fail; cannam@85: cannam@85: if (0) { cannam@85: fail: cannam@85: result = -1; cannam@85: } cannam@85: cannam@85: if (string) cannam@85: free(string); cannam@85: cannam@85: return result; cannam@85: } cannam@85: cannam@85: /* cannam@85: * NAME: compat->fixup() cannam@85: * DESCRIPTION: finish compatibility translations cannam@85: */ cannam@85: int id3_compat_fixup(struct id3_tag *tag) cannam@85: { cannam@85: struct id3_frame *frame; cannam@85: unsigned int index; cannam@85: id3_ucs4_t timestamp[17] = { 0 }; cannam@85: int result = 0; cannam@85: cannam@85: /* create a TDRC frame from obsolete TYER/TDAT/TIME frames */ cannam@85: cannam@85: /* cannam@85: * TYE/TYER: YYYY cannam@85: * TDA/TDAT: DDMM cannam@85: * TIM/TIME: HHMM cannam@85: * cannam@85: * TDRC: yyyy-MM-ddTHH:mm cannam@85: */ cannam@85: cannam@85: index = 0; cannam@85: while ((frame = id3_tag_findframe(tag, ID3_FRAME_OBSOLETE, index++))) { cannam@85: char const *id; cannam@85: id3_byte_t const *data, *end; cannam@85: id3_length_t length; cannam@85: enum id3_field_textencoding encoding; cannam@85: id3_ucs4_t *string; cannam@85: cannam@85: id = id3_field_getframeid(&frame->fields[0]); cannam@85: assert(id); cannam@85: cannam@85: if (strcmp(id, "TYER") != 0 && strcmp(id, "YTYE") != 0 && cannam@85: strcmp(id, "TDAT") != 0 && strcmp(id, "YTDA") != 0 && cannam@85: strcmp(id, "TIME") != 0 && strcmp(id, "YTIM") != 0) cannam@85: continue; cannam@85: cannam@85: data = id3_field_getbinarydata(&frame->fields[1], &length); cannam@85: assert(data); cannam@85: cannam@85: if (length < 1) cannam@85: continue; cannam@85: cannam@85: end = data + length; cannam@85: cannam@85: encoding = id3_parse_uint(&data, 1); cannam@85: string = id3_parse_string(&data, end - data, encoding, 0); cannam@85: cannam@85: if (id3_ucs4_length(string) < 4) { cannam@85: free(string); cannam@85: continue; cannam@85: } cannam@85: cannam@85: if (strcmp(id, "TYER") == 0 || cannam@85: strcmp(id, "YTYE") == 0) { cannam@85: timestamp[0] = string[0]; cannam@85: timestamp[1] = string[1]; cannam@85: timestamp[2] = string[2]; cannam@85: timestamp[3] = string[3]; cannam@85: } cannam@85: else if (strcmp(id, "TDAT") == 0 || cannam@85: strcmp(id, "YTDA") == 0) { cannam@85: timestamp[4] = '-'; cannam@85: timestamp[5] = string[2]; cannam@85: timestamp[6] = string[3]; cannam@85: timestamp[7] = '-'; cannam@85: timestamp[8] = string[0]; cannam@85: timestamp[9] = string[1]; cannam@85: } cannam@85: else { /* TIME or YTIM */ cannam@85: timestamp[10] = 'T'; cannam@85: timestamp[11] = string[0]; cannam@85: timestamp[12] = string[1]; cannam@85: timestamp[13] = ':'; cannam@85: timestamp[14] = string[2]; cannam@85: timestamp[15] = string[3]; cannam@85: } cannam@85: cannam@85: free(string); cannam@85: } cannam@85: cannam@85: if (timestamp[0]) { cannam@85: id3_ucs4_t *strings; cannam@85: cannam@85: frame = id3_frame_new("TDRC"); cannam@85: if (frame == 0) cannam@85: goto fail; cannam@85: cannam@85: strings = timestamp; cannam@85: cannam@85: if (id3_field_settextencoding(&frame->fields[0], cannam@85: ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1 || cannam@85: id3_field_setstrings(&frame->fields[1], 1, &strings) == -1 || cannam@85: id3_tag_attachframe(tag, frame) == -1) { cannam@85: id3_frame_delete(frame); cannam@85: goto fail; cannam@85: } cannam@85: } cannam@85: cannam@85: if (0) { cannam@85: fail: cannam@85: result = -1; cannam@85: } cannam@85: cannam@85: return result; cannam@85: }