~ubuntu-dev/ubuntu/lucid/mpd/lucid-201002101854

« back to all changes in this revision

Viewing changes to src/libid3tag/frame.c

  • Committer: Bazaar Package Importer
  • Author(s): Charles Majola
  • Date: 2005-02-15 10:43:58 UTC
  • Revision ID: james.westby@ubuntu.com-20050215104358-w8b7yaqqfmsoxj5k
Tags: upstream-0.11.5
ImportĀ upstreamĀ versionĀ 0.11.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * libid3tag - ID3 tag manipulation library
 
3
 * Copyright (C) 2000-2004 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.15 2004/01/23 09:41:32 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
 
 
44
static
 
45
int 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
 */
 
54
int 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
 */
 
67
struct 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
 
 
127
void 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
 */
 
148
void 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
 */
 
159
void 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
 */
 
170
union 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
 
 
178
static
 
179
struct 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
 
 
202
static
 
203
struct 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
 
 
239
static
 
240
int 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
 */
 
263
struct 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
 
 
484
static
 
485
id3_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
 */
 
504
id3_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
}