1/*
2 * libid3tag - ID3 tag manipulation library
3 * Copyright (C) 2000-2003 Underbit Technologies, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 *
19 * $Id: frame.c,v 1.14 2003/04/19 00:14:33 rob Exp $
20 */
21
22# ifdef HAVE_CONFIG_H
23#  include "config.h"
24# endif
25
26# include "global.h"
27
28# include <stdlib.h>
29# include <string.h>
30
31# ifdef HAVE_ASSERT_H
32#  include <assert.h>
33# endif
34
35# include "id3tag.h"
36# include "frame.h"
37# include "frametype.h"
38# include "compat.h"
39# include "field.h"
40# include "render.h"
41# include "parse.h"
42# include "util.h"
43
44static
45int valid_idchar(char c)
46{
47  return (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
48}
49
50/*
51 * NAME:	frame->validid()
52 * DESCRIPTION:	return true if the parameter string is a legal frame ID
53 */
54int id3_frame_validid(char const *id)
55{
56  return id &&
57    valid_idchar(id[0]) &&
58    valid_idchar(id[1]) &&
59    valid_idchar(id[2]) &&
60    valid_idchar(id[3]);
61}
62
63/*
64 * NAME:	frame->new()
65 * DESCRIPTION:	allocate and return a new frame
66 */
67struct id3_frame *id3_frame_new(char const *id)
68{
69  struct id3_frametype const *frametype;
70  struct id3_frame *frame;
71  unsigned int i;
72
73  if (!id3_frame_validid(id))
74    return 0;
75
76  frametype = id3_frametype_lookup(id, 4);
77  if (frametype == 0) {
78    switch (id[0]) {
79    case 'T':
80      frametype = &id3_frametype_text;
81      break;
82
83    case 'W':
84      frametype = &id3_frametype_url;
85      break;
86
87    case 'X':
88    case 'Y':
89    case 'Z':
90      frametype = &id3_frametype_experimental;
91      break;
92
93    default:
94      frametype = &id3_frametype_unknown;
95      if (id3_compat_lookup(id, 4))
96	frametype = &id3_frametype_obsolete;
97      break;
98    }
99  }
100
101  frame = malloc(sizeof(*frame) + frametype->nfields * sizeof(*frame->fields));
102  if (frame) {
103    frame->id[0] = id[0];
104    frame->id[1] = id[1];
105    frame->id[2] = id[2];
106    frame->id[3] = id[3];
107    frame->id[4] = 0;
108
109    frame->description       = frametype->description;
110    frame->refcount          = 0;
111    frame->flags             = frametype->defaultflags;
112    frame->group_id          = 0;
113    frame->encryption_method = 0;
114    frame->encoded           = 0;
115    frame->encoded_length    = 0;
116    frame->decoded_length    = 0;
117    frame->nfields           = frametype->nfields;
118    frame->fields            = (union id3_field *) &frame[1];
119
120    for (i = 0; i < frame->nfields; ++i)
121      id3_field_init(&frame->fields[i], frametype->fields[i]);
122  }
123
124  return frame;
125}
126
127void id3_frame_delete(struct id3_frame *frame)
128{
129  assert(frame);
130
131  if (frame->refcount == 0) {
132    unsigned int i;
133
134    for (i = 0; i < frame->nfields; ++i)
135      id3_field_finish(&frame->fields[i]);
136
137    if (frame->encoded)
138      free(frame->encoded);
139
140    free(frame);
141  }
142}
143
144/*
145 * NAME:	frame->addref()
146 * DESCRIPTION:	add an external reference to a frame
147 */
148void id3_frame_addref(struct id3_frame *frame)
149{
150  assert(frame);
151
152  ++frame->refcount;
153}
154
155/*
156 * NAME:	frame->delref()
157 * DESCRIPTION:	remove an external reference to a frame
158 */
159void id3_frame_delref(struct id3_frame *frame)
160{
161  assert(frame && frame->refcount > 0);
162
163  --frame->refcount;
164}
165
166/*
167 * NAME:	frame->field()
168 * DESCRIPTION:	return a pointer to a field in a frame
169 */
170union id3_field *id3_frame_field(struct id3_frame const *frame,
171				 unsigned int index)
172{
173  assert(frame);
174
175  return (index < frame->nfields) ? &frame->fields[index] : 0;
176}
177
178static
179struct id3_frame *obsolete(char const *id, id3_byte_t const *data,
180			   id3_length_t length)
181{
182  struct id3_frame *frame;
183
184  frame = id3_frame_new(ID3_FRAME_OBSOLETE);
185  if (frame) {
186    if (id3_field_setframeid(&frame->fields[0], id) == -1 ||
187	id3_field_setbinarydata(&frame->fields[1], data, length) == -1)
188      goto fail;
189  }
190
191  if (0) {
192  fail:
193    if (frame) {
194      id3_frame_delete(frame);
195      frame = 0;
196    }
197  }
198
199  return frame;
200}
201
202static
203struct id3_frame *unparseable(char const *id, id3_byte_t const **ptr,
204			      id3_length_t length, int flags,
205			      int group_id, int encryption_method,
206			      id3_length_t decoded_length)
207{
208  struct id3_frame *frame = 0;
209  id3_byte_t *mem;
210
211  mem = malloc(length ? length : 1);
212  if (mem == 0)
213    goto fail;
214
215  frame = id3_frame_new(id);
216  if (frame == 0)
217    free(mem);
218  else {
219    memcpy(mem, *ptr, length);
220
221    frame->flags             = flags;
222    frame->group_id          = group_id;
223    frame->encryption_method = encryption_method;
224    frame->encoded           = mem;
225    frame->encoded_length    = length;
226    frame->decoded_length    = decoded_length;
227  }
228
229  if (0) {
230  fail:
231    ;
232  }
233
234  *ptr += length;
235
236  return frame;
237}
238
239static
240int parse_data(struct id3_frame *frame,
241	       id3_byte_t const *data, id3_length_t length)
242{
243  enum id3_field_textencoding encoding;
244  id3_byte_t const *end;
245  unsigned int i;
246
247  encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
248
249  end = data + length;
250
251  for (i = 0; i < frame->nfields; ++i) {
252    if (id3_field_parse(&frame->fields[i], &data, end - data, &encoding) == -1)
253      return -1;
254  }
255
256  return 0;
257}
258
259/*
260 * NAME:	frame->parse()
261 * DESCRIPTION:	parse raw frame data according to the specified ID3 tag version
262 */
263struct id3_frame *id3_frame_parse(id3_byte_t const **ptr, id3_length_t length,
264				  unsigned int version)
265{
266  struct id3_frame *frame = 0;
267  id3_byte_t const *id, *end, *data;
268  id3_length_t size, decoded_length = 0;
269  int flags = 0, group_id = 0, encryption_method = 0;
270  struct id3_compat const *compat = 0;
271  id3_byte_t *mem = 0;
272  char xid[4];
273
274  id  = *ptr;
275  end = *ptr + length;
276
277  if (ID3_TAG_VERSION_MAJOR(version) < 4) {
278    switch (ID3_TAG_VERSION_MAJOR(version)) {
279    case 2:
280      if (length < 6)
281	goto fail;
282
283      compat = id3_compat_lookup(id, 3);
284
285      *ptr += 3;
286      size  = id3_parse_uint(ptr, 3);
287
288      if (size > end - *ptr)
289	goto fail;
290
291      end = *ptr + size;
292
293      break;
294
295    case 3:
296      if (length < 10)
297	goto fail;
298
299      compat = id3_compat_lookup(id, 4);
300
301      *ptr += 4;
302      size  = id3_parse_uint(ptr, 4);
303      flags = id3_parse_uint(ptr, 2);
304
305      if (size > end - *ptr)
306	goto fail;
307
308      end = *ptr + size;
309
310      if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~0x00e0)) {
311	frame = unparseable(id, ptr, end - *ptr, 0, 0, 0, 0);
312	goto done;
313      }
314
315      flags =
316	((flags >> 1) & ID3_FRAME_FLAG_STATUSFLAGS) |
317	((flags >> 4) & (ID3_FRAME_FLAG_COMPRESSION |
318			 ID3_FRAME_FLAG_ENCRYPTION)) |
319	((flags << 1) & ID3_FRAME_FLAG_GROUPINGIDENTITY);
320
321      if (flags & ID3_FRAME_FLAG_COMPRESSION) {
322	if (end - *ptr < 4)
323	  goto fail;
324
325	decoded_length = id3_parse_uint(ptr, 4);
326      }
327
328      if (flags & ID3_FRAME_FLAG_ENCRYPTION) {
329	if (end - *ptr < 1)
330	  goto fail;
331
332	encryption_method = id3_parse_uint(ptr, 1);
333      }
334
335      if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) {
336	if (end - *ptr < 1)
337	  goto fail;
338
339	group_id = id3_parse_uint(ptr, 1);
340      }
341
342      break;
343
344    default:
345      goto fail;
346    }
347
348    /* canonicalize frame ID for ID3v2.4 */
349
350    if (compat && compat->equiv)
351      id = compat->equiv;
352    else if (ID3_TAG_VERSION_MAJOR(version) == 2) {
353      xid[0] = 'Y';
354      xid[1] = id[0];
355      xid[2] = id[1];
356      xid[3] = id[2];
357
358      id = xid;
359
360      flags |=
361	ID3_FRAME_FLAG_TAGALTERPRESERVATION |
362	ID3_FRAME_FLAG_FILEALTERPRESERVATION;
363    }
364  }
365  else {  /* ID3v2.4 */
366    if (length < 10)
367      goto fail;
368
369    *ptr += 4;
370    size  = id3_parse_syncsafe(ptr, 4);
371    flags = id3_parse_uint(ptr, 2);
372
373    if (size > end - *ptr)
374      goto fail;
375
376    end = *ptr + size;
377
378    if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) {
379      frame = unparseable(id, ptr, end - *ptr, flags, 0, 0, 0);
380      goto done;
381    }
382
383    if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) {
384      if (end - *ptr < 1)
385	goto fail;
386
387      group_id = id3_parse_uint(ptr, 1);
388    }
389
390    if ((flags & ID3_FRAME_FLAG_COMPRESSION) &&
391	!(flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR))
392      goto fail;
393
394    if (flags & ID3_FRAME_FLAG_ENCRYPTION) {
395      if (end - *ptr < 1)
396	goto fail;
397
398      encryption_method = id3_parse_uint(ptr, 1);
399    }
400
401    if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) {
402      if (end - *ptr < 4)
403	goto fail;
404
405      decoded_length = id3_parse_syncsafe(ptr, 4);
406    }
407  }
408
409  data = *ptr;
410  *ptr = end;
411
412  /* undo frame encodings */
413
414  if ((flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) && end - data > 0) {
415    mem = malloc(end - data);
416    if (mem == 0)
417      goto fail;
418
419    memcpy(mem, data, end - data);
420
421    end  = mem + id3_util_deunsynchronise(mem, end - data);
422    data = mem;
423  }
424
425  if (flags & ID3_FRAME_FLAG_ENCRYPTION) {
426    frame = unparseable(id, &data, end - data, flags,
427			group_id, encryption_method, decoded_length);
428    goto done;
429  }
430
431  if (flags & ID3_FRAME_FLAG_COMPRESSION) {
432    id3_byte_t *decomp;
433
434    decomp = id3_util_decompress(data, end - data, decoded_length);
435    if (decomp == 0)
436      goto fail;
437
438    if (mem)
439      free(mem);
440
441    data = mem = decomp;
442    end  = data + decoded_length;
443  }
444
445  /* check for obsolescence */
446
447  if (compat && !compat->equiv) {
448    frame = obsolete(id, data, end - data);
449    goto done;
450  }
451
452  /* generate the internal frame structure */
453
454  frame = id3_frame_new(id);
455  if (frame) {
456    frame->flags    = flags;
457    frame->group_id = group_id;
458
459    if (compat && compat->translate) {
460      if (compat->translate(frame, compat->id, data, end - data) == -1)
461	goto fail;
462    }
463    else {
464      if (parse_data(frame, data, end - data) == -1)
465	goto fail;
466    }
467  }
468
469  if (0) {
470  fail:
471    if (frame) {
472      id3_frame_delete(frame);
473      frame = 0;
474    }
475  }
476
477 done:
478  if (mem)
479    free(mem);
480
481  return frame;
482}
483
484static
485id3_length_t render_data(id3_byte_t **ptr,
486			 union id3_field *fields, unsigned int length)
487{
488  id3_length_t size = 0;
489  enum id3_field_textencoding encoding;
490  unsigned int i;
491
492  encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
493
494  for (i = 0; i < length; ++i)
495    size += id3_field_render(&fields[i], ptr, &encoding, i < length - 1);
496
497  return size;
498}
499
500/*
501 * NAME:	frame->render()
502 * DESCRIPTION:	render a single, complete frame
503 */
504id3_length_t id3_frame_render(struct id3_frame const *frame,
505			      id3_byte_t **ptr, int options)
506{
507  id3_length_t size = 0, decoded_length, datalen;
508  id3_byte_t *size_ptr = 0, *flags_ptr = 0, *data = 0;
509  int flags;
510
511  assert(frame);
512
513  if ((frame->flags & ID3_FRAME_FLAG_TAGALTERPRESERVATION) ||
514      ((options & ID3_TAG_OPTION_FILEALTERED) &&
515       (frame->flags & ID3_FRAME_FLAG_FILEALTERPRESERVATION)))
516    return 0;
517
518  /* a frame must be at least 1 byte big, excluding the header */
519
520  decoded_length = render_data(0, frame->fields, frame->nfields);
521  if (decoded_length == 0 && frame->encoded == 0)
522    return 0;
523
524  /* header */
525
526  size += id3_render_immediate(ptr, frame->id, 4);
527
528  if (ptr)
529    size_ptr = *ptr;
530
531  size += id3_render_syncsafe(ptr, 0, 4);
532
533  if (ptr)
534    flags_ptr = *ptr;
535
536  flags = frame->flags;
537
538  size += id3_render_int(ptr, flags, 2);
539
540  if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) {
541    size += id3_render_binary(ptr, frame->encoded, frame->encoded_length);
542    if (size_ptr)
543      id3_render_syncsafe(&size_ptr, size - 10, 4);
544
545    return size;
546  }
547
548  flags &= ID3_FRAME_FLAG_KNOWNFLAGS;
549
550  flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION;
551  if (options & ID3_TAG_OPTION_UNSYNCHRONISATION)
552    flags |= ID3_FRAME_FLAG_UNSYNCHRONISATION;
553
554  if (!(flags & ID3_FRAME_FLAG_ENCRYPTION)) {
555    flags &= ~ID3_FRAME_FLAG_COMPRESSION;
556    if (options & ID3_TAG_OPTION_COMPRESSION)
557      flags |= ID3_FRAME_FLAG_COMPRESSION | ID3_FRAME_FLAG_DATALENGTHINDICATOR;
558  }
559
560  if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY)
561    size += id3_render_int(ptr, frame->group_id, 1);
562  if (flags & ID3_FRAME_FLAG_ENCRYPTION)
563    size += id3_render_int(ptr, frame->encryption_method, 1);
564  if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) {
565    if (flags & ID3_FRAME_FLAG_ENCRYPTION)
566      decoded_length = frame->decoded_length;
567    size += id3_render_syncsafe(ptr, decoded_length, 4);
568  }
569
570  if (ptr)
571    data = *ptr;
572
573  if (flags & ID3_FRAME_FLAG_ENCRYPTION)
574    datalen = id3_render_binary(ptr, frame->encoded, frame->encoded_length);
575  else {
576    if (ptr == 0)
577      datalen = decoded_length;
578    else {
579      datalen = render_data(ptr, frame->fields, frame->nfields);
580
581      if (flags & ID3_FRAME_FLAG_COMPRESSION) {
582	id3_byte_t *comp;
583	id3_length_t complen;
584
585	comp = id3_util_compress(data, datalen, &complen);
586	if (comp == 0)
587	  flags &= ~ID3_FRAME_FLAG_COMPRESSION;
588	else {
589	  *ptr = data;
590	  datalen = id3_render_binary(ptr, comp, complen);
591
592	  free(comp);
593	}
594      }
595    }
596  }
597
598  /* unsynchronisation */
599
600  if (flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) {
601    if (data == 0)
602      datalen *= 2;
603    else {
604      id3_length_t newlen;
605
606      newlen = id3_util_unsynchronise(data, datalen);
607      if (newlen == datalen)
608	flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION;
609      else {
610	*ptr   += newlen - datalen;
611	datalen = newlen;
612      }
613    }
614  }
615
616  size += datalen;
617
618  /* patch size and flags */
619
620  if (size_ptr)
621    id3_render_syncsafe(&size_ptr, size - 10, 4);
622  if (flags_ptr)
623    id3_render_int(&flags_ptr, flags, 2);
624
625  return size;
626}
627