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
valid_idchar(char c)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 */
id3_frame_validid(char const * id)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 */
id3_frame_new(char const * id)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
id3_frame_delete(struct id3_frame * frame)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 */
id3_frame_addref(struct id3_frame * frame)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 */
id3_frame_delref(struct id3_frame * frame)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 */
id3_frame_field(struct id3_frame const * frame,unsigned int index)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
obsolete(char const * id,id3_byte_t const * data,id3_length_t length)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
unparseable(char const * id,id3_byte_t const ** ptr,id3_length_t length,int flags,int group_id,int encryption_method,id3_length_t decoded_length)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
parse_data(struct id3_frame * frame,id3_byte_t const * data,id3_length_t length)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 */
id3_frame_parse(id3_byte_t const ** ptr,id3_length_t length,unsigned int version)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
render_data(id3_byte_t ** ptr,union id3_field * fields,unsigned int length)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 */
id3_frame_render(struct id3_frame const * frame,id3_byte_t ** ptr,int options)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 }
627