1%{
2/*
3 * libid3tag - ID3 tag manipulation library
4 * Copyright (C) 2000-2004 Underbit Technologies, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 *
20 * $Id: compat.gperf,v 1.11 2004/01/23 09:41:32 rob Exp $
21 */
22
23# ifdef HAVE_CONFIG_H
24#  include "config.h"
25# endif
26
27# include "global.h"
28
29# include <stdlib.h>
30# include <string.h>
31
32# ifdef HAVE_ASSERT_H
33#  include <assert.h>
34# endif
35
36# include "id3tag.h"
37# include "compat.h"
38# include "frame.h"
39# include "field.h"
40# include "parse.h"
41# include "ucs4.h"
42
43# define EQ(id)    #id, 0
44# define OBSOLETE    0, 0
45# define TX(id)    #id, translate_##id
46
47static id3_compat_func_t translate_TCON;
48%}
49struct id3_compat;
50%%
51#
52# ID3v2.2 and ID3v2.3 frames
53#
54# Only obsolete frames or frames with an equivalent ID3v2.4 frame ID are
55# listed here. If a frame ID is not listed, it is assumed that the same
56# frame ID is itself the equivalent ID3v2.4 frame ID.
57#
58# This list may also include frames with new content interpretations; the
59# translation function will rewrite the contents to comply with ID3v2.4.
60#
61BUF,  EQ(RBUF)  /* Recommended buffer size */
62CNT,  EQ(PCNT)  /* Play counter */
63COM,  EQ(COMM)  /* Comments */
64CRA,  EQ(AENC)  /* Audio encryption */
65CRM,  OBSOLETE  /* Encrypted meta frame [obsolete] */
66EQU,  OBSOLETE  /* Equalization [obsolete] */
67EQUA, OBSOLETE  /* Equalization [obsolete] */
68ETC,  EQ(ETCO)  /* Event timing codes */
69GEO,  EQ(GEOB)  /* General encapsulated object */
70IPL,  EQ(TIPL)  /* Involved people list */
71IPLS, EQ(TIPL)  /* Involved people list */
72LNK,  EQ(LINK)  /* Linked information */
73MCI,  EQ(MCDI)  /* Music CD identifier */
74MLL,  EQ(MLLT)  /* MPEG location lookup table */
75PIC,  EQ(APIC)  /* Attached picture */
76POP,  EQ(POPM)  /* Popularimeter */
77REV,  EQ(RVRB)  /* Reverb */
78RVA,  OBSOLETE  /* Relative volume adjustment [obsolete] */
79RVAD, OBSOLETE  /* Relative volume adjustment [obsolete] */
80SLT,  EQ(SYLT)  /* Synchronised lyric/text */
81STC,  EQ(SYTC)  /* Synchronised tempo codes */
82TAL,  EQ(TALB)  /* Album/movie/show title */
83TBP,  EQ(TBPM)  /* BPM (beats per minute) */
84TCM,  EQ(TCOM)  /* Composer */
85TCO,  TX(TCON)  /* Content type */
86TCON, TX(TCON)  /* Content type */
87TCR,  EQ(TCOP)  /* Copyright message */
88TDA,  OBSOLETE  /* Date [obsolete] */
89TDAT, OBSOLETE  /* Date [obsolete] */
90TDY,  EQ(TDLY)  /* Playlist delay */
91TEN,  EQ(TENC)  /* Encoded by */
92TFT,  EQ(TFLT)  /* File type */
93TIM,  OBSOLETE  /* Time [obsolete] */
94TIME, OBSOLETE  /* Time [obsolete] */
95TKE,  EQ(TKEY)  /* Initial key */
96TLA,  EQ(TLAN)  /* Language(s) */
97TLE,  EQ(TLEN)  /* Length */
98TMT,  EQ(TMED)  /* Media type */
99TOA,  EQ(TOPE)  /* Original artist(s)/performer(s) */
100TOF,  EQ(TOFN)  /* Original filename */
101TOL,  EQ(TOLY)  /* Original lyricist(s)/text writer(s) */
102TOR,  EQ(TDOR)  /* Original release year [obsolete] */
103TORY, EQ(TDOR)  /* Original release year [obsolete] */
104TOT,  EQ(TOAL)  /* Original album/movie/show title */
105TP1,  EQ(TPE1)  /* Lead performer(s)/soloist(s) */
106TP2,  EQ(TPE2)  /* Band/orchestra/accompaniment */
107TP3,  EQ(TPE3)  /* Conductor/performer refinement */
108TP4,  EQ(TPE4)  /* Interpreted, remixed, or otherwise modified by */
109TPA,  EQ(TPOS)  /* Part of a set */
110TPB,  EQ(TPUB)  /* Publisher */
111TRC,  EQ(TSRC)  /* ISRC (international standard recording code) */
112TRD,  OBSOLETE  /* Recording dates [obsolete] */
113TRDA, OBSOLETE  /* Recording dates [obsolete] */
114TRK,  EQ(TRCK)  /* Track number/position in set */
115TSI,  OBSOLETE  /* Size [obsolete] */
116TSIZ, OBSOLETE  /* Size [obsolete] */
117TSS,  EQ(TSSE)  /* Software/hardware and settings used for encoding */
118TT1,  EQ(TIT1)  /* Content group description */
119TT2,  EQ(TIT2)  /* Title/songname/content description */
120TT3,  EQ(TIT3)  /* Subtitle/description refinement */
121TXT,  EQ(TEXT)  /* Lyricist/text writer */
122TXX,  EQ(TXXX)  /* User defined text information frame */
123TYE,  OBSOLETE  /* Year [obsolete] */
124TYER, OBSOLETE  /* Year [obsolete] */
125UFI,  EQ(UFID)  /* Unique file identifier */
126ULT,  EQ(USLT)  /* Unsynchronised lyric/text transcription */
127WAF,  EQ(WOAF)  /* Official audio file webpage */
128WAR,  EQ(WOAR)  /* Official artist/performer webpage */
129WAS,  EQ(WOAS)  /* Official audio source webpage */
130WCM,  EQ(WCOM)  /* Commercial information */
131WCP,  EQ(WCOP)  /* Copyright/legal information */
132WPB,  EQ(WPUB)  /* Publishers official webpage */
133WXX,  EQ(WXXX)  /* User defined URL link frame */
134%%
135
136static
137int translate_TCON(struct id3_frame *frame, char const *oldid,
138		   id3_byte_t const *data, id3_length_t length)
139{
140  id3_byte_t const *end;
141  enum id3_field_textencoding encoding;
142  id3_ucs4_t *string = 0, *ptr, *endptr;
143  int result = 0;
144
145  /* translate old TCON syntax into multiple strings */
146
147  assert(frame->nfields == 2);
148
149  encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
150
151  end = data + length;
152
153  if (id3_field_parse(&frame->fields[0], &data, end - data, &encoding) == -1)
154    goto fail;
155
156  string = id3_parse_string(&data, end - data, encoding, 0);
157  if (string == 0)
158    goto fail;
159
160  ptr = string;
161  while (*ptr == '(') {
162    if (*++ptr == '(')
163      break;
164
165    endptr = ptr;
166    while (*endptr && *endptr != ')')
167      ++endptr;
168
169    if (*endptr)
170      *endptr++ = 0;
171
172    if (id3_field_addstring(&frame->fields[1], ptr) == -1)
173      goto fail;
174
175    ptr = endptr;
176  }
177
178  if (*ptr && id3_field_addstring(&frame->fields[1], ptr) == -1)
179    goto fail;
180
181  if (0) {
182  fail:
183    result = -1;
184  }
185
186  if (string)
187    free(string);
188
189  return result;
190}
191
192/*
193 * NAME:	compat->fixup()
194 * DESCRIPTION:	finish compatibility translations
195 */
196int id3_compat_fixup(struct id3_tag *tag)
197{
198  struct id3_frame *frame;
199  unsigned int index;
200  id3_ucs4_t timestamp[17] = { 0 };
201  int result = 0;
202
203  /* create a TDRC frame from obsolete TYER/TDAT/TIME frames */
204
205  /*
206   * TYE/TYER: YYYY
207   * TDA/TDAT: DDMM
208   * TIM/TIME: HHMM
209   *
210   * TDRC: yyyy-MM-ddTHH:mm
211   */
212
213  index = 0;
214  while ((frame = id3_tag_findframe(tag, ID3_FRAME_OBSOLETE, index++))) {
215    char const *id;
216    id3_byte_t const *data, *end;
217    id3_length_t length;
218    enum id3_field_textencoding encoding;
219    id3_ucs4_t *string;
220
221    id = id3_field_getframeid(&frame->fields[0]);
222    assert(id);
223
224    if (strcmp(id, "TYER") != 0 && strcmp(id, "YTYE") != 0 &&
225	strcmp(id, "TDAT") != 0 && strcmp(id, "YTDA") != 0 &&
226	strcmp(id, "TIME") != 0 && strcmp(id, "YTIM") != 0)
227      continue;
228
229    data = id3_field_getbinarydata(&frame->fields[1], &length);
230    assert(data);
231
232    if (length < 1)
233      continue;
234
235    end = data + length;
236
237    encoding = id3_parse_uint(&data, 1);
238    string   = id3_parse_string(&data, end - data, encoding, 0);
239
240    if (id3_ucs4_length(string) < 4) {
241      free(string);
242      continue;
243    }
244
245    if (strcmp(id, "TYER") == 0 ||
246	strcmp(id, "YTYE") == 0) {
247      timestamp[0] = string[0];
248      timestamp[1] = string[1];
249      timestamp[2] = string[2];
250      timestamp[3] = string[3];
251    }
252    else if (strcmp(id, "TDAT") == 0 ||
253	     strcmp(id, "YTDA") == 0) {
254      timestamp[4] = '-';
255      timestamp[5] = string[2];
256      timestamp[6] = string[3];
257      timestamp[7] = '-';
258      timestamp[8] = string[0];
259      timestamp[9] = string[1];
260    }
261    else {  /* TIME or YTIM */
262      timestamp[10] = 'T';
263      timestamp[11] = string[0];
264      timestamp[12] = string[1];
265      timestamp[13] = ':';
266      timestamp[14] = string[2];
267      timestamp[15] = string[3];
268    }
269
270    free(string);
271  }
272
273  if (timestamp[0]) {
274    id3_ucs4_t *strings;
275
276    frame = id3_frame_new("TDRC");
277    if (frame == 0)
278      goto fail;
279
280    strings = timestamp;
281
282    if (id3_field_settextencoding(&frame->fields[0],
283				  ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1 ||
284	id3_field_setstrings(&frame->fields[1], 1, &strings) == -1 ||
285	id3_tag_attachframe(tag, frame) == -1) {
286      id3_frame_delete(frame);
287      goto fail;
288    }
289  }
290
291  if (0) {
292  fail:
293    result = -1;
294  }
295
296  return result;
297}
298