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