Extended MOTD with GUI
[tomato.git] / release / src / router / libid3tag / frame.c
blob1c680d9e965da5cbdaa15bbd588140ea1d96df7f
1 /*
2 * libid3tag - ID3 tag manipulation library
3 * Copyright (C) 2000-2004 Underbit Technologies, Inc.
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.
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.
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
19 * $Id: frame.c,v 1.15 2004/01/23 09:41:32 rob Exp $
22 # ifdef HAVE_CONFIG_H
23 # include "config.h"
24 # endif
26 # include "global.h"
28 # include <stdlib.h>
29 # include <string.h>
31 # ifdef HAVE_ASSERT_H
32 # include <assert.h>
33 # endif
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"
44 static
45 int valid_idchar(char c)
47 return (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
51 * NAME: frame->validid()
52 * DESCRIPTION: return true if the parameter string is a legal frame ID
54 int id3_frame_validid(char const *id)
56 return id &&
57 valid_idchar(id[0]) &&
58 valid_idchar(id[1]) &&
59 valid_idchar(id[2]) &&
60 valid_idchar(id[3]);
64 * NAME: frame->new()
65 * DESCRIPTION: allocate and return a new frame
67 struct id3_frame *id3_frame_new(char const *id)
69 struct id3_frametype const *frametype;
70 struct id3_frame *frame;
71 unsigned int i;
73 if (!id3_frame_validid(id))
74 return 0;
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;
83 case 'W':
84 frametype = &id3_frametype_url;
85 break;
87 case 'X':
88 case 'Y':
89 case 'Z':
90 frametype = &id3_frametype_experimental;
91 break;
93 default:
94 frametype = &id3_frametype_unknown;
95 if (id3_compat_lookup(id, 4))
96 frametype = &id3_frametype_obsolete;
97 break;
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;
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];
120 for (i = 0; i < frame->nfields; ++i)
121 id3_field_init(&frame->fields[i], frametype->fields[i]);
124 return frame;
127 void id3_frame_delete(struct id3_frame *frame)
129 assert(frame);
131 if (frame->refcount == 0) {
132 unsigned int i;
134 for (i = 0; i < frame->nfields; ++i)
135 id3_field_finish(&frame->fields[i]);
137 if (frame->encoded)
138 free(frame->encoded);
140 free(frame);
145 * NAME: frame->addref()
146 * DESCRIPTION: add an external reference to a frame
148 void id3_frame_addref(struct id3_frame *frame)
150 assert(frame);
152 ++frame->refcount;
156 * NAME: frame->delref()
157 * DESCRIPTION: remove an external reference to a frame
159 void id3_frame_delref(struct id3_frame *frame)
161 assert(frame && frame->refcount > 0);
163 --frame->refcount;
167 * NAME: frame->field()
168 * DESCRIPTION: return a pointer to a field in a frame
170 union id3_field *id3_frame_field(struct id3_frame const *frame,
171 unsigned int index)
173 assert(frame);
175 return (index < frame->nfields) ? &frame->fields[index] : 0;
178 static
179 struct id3_frame *obsolete(char const *id, id3_byte_t const *data,
180 id3_length_t length)
182 struct id3_frame *frame;
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;
191 if (0) {
192 fail:
193 if (frame) {
194 id3_frame_delete(frame);
195 frame = 0;
199 return frame;
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)
208 struct id3_frame *frame = 0;
209 id3_byte_t *mem;
211 mem = malloc(length ? length : 1);
212 if (mem == 0)
213 goto fail;
215 frame = id3_frame_new(id);
216 if (frame == 0)
217 free(mem);
218 else {
219 memcpy(mem, *ptr, length);
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;
229 if (0) {
230 fail:
234 *ptr += length;
236 return frame;
239 static
240 int parse_data(struct id3_frame *frame,
241 id3_byte_t const *data, id3_length_t length)
243 enum id3_field_textencoding encoding;
244 id3_byte_t const *end;
245 unsigned int i;
247 encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
249 end = data + length;
251 for (i = 0; i < frame->nfields; ++i) {
252 if (id3_field_parse(&frame->fields[i], &data, end - data, &encoding) == -1)
253 return -1;
256 return 0;
260 * NAME: frame->parse()
261 * DESCRIPTION: parse raw frame data according to the specified ID3 tag version
263 struct id3_frame *id3_frame_parse(id3_byte_t const **ptr, id3_length_t length,
264 unsigned int version)
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];
274 id = *ptr;
275 end = *ptr + length;
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;
283 compat = id3_compat_lookup(id, 3);
285 *ptr += 3;
286 size = id3_parse_uint(ptr, 3);
288 if (size > end - *ptr)
289 goto fail;
291 end = *ptr + size;
293 break;
295 case 3:
296 if (length < 10)
297 goto fail;
299 compat = id3_compat_lookup(id, 4);
301 *ptr += 4;
302 size = id3_parse_uint(ptr, 4);
303 flags = id3_parse_uint(ptr, 2);
305 if (size > end - *ptr)
306 goto fail;
308 end = *ptr + size;
310 if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~0x00e0)) {
311 frame = unparseable(id, ptr, end - *ptr, 0, 0, 0, 0);
312 goto done;
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);
321 if (flags & ID3_FRAME_FLAG_COMPRESSION) {
322 if (end - *ptr < 4)
323 goto fail;
325 decoded_length = id3_parse_uint(ptr, 4);
328 if (flags & ID3_FRAME_FLAG_ENCRYPTION) {
329 if (end - *ptr < 1)
330 goto fail;
332 encryption_method = id3_parse_uint(ptr, 1);
335 if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) {
336 if (end - *ptr < 1)
337 goto fail;
339 group_id = id3_parse_uint(ptr, 1);
342 break;
344 default:
345 goto fail;
348 /* canonicalize frame ID for ID3v2.4 */
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];
358 id = xid;
360 flags |=
361 ID3_FRAME_FLAG_TAGALTERPRESERVATION |
362 ID3_FRAME_FLAG_FILEALTERPRESERVATION;
365 else { /* ID3v2.4 */
366 if (length < 10)
367 goto fail;
369 *ptr += 4;
370 size = id3_parse_syncsafe(ptr, 4);
371 flags = id3_parse_uint(ptr, 2);
373 if (size > end - *ptr)
374 goto fail;
376 end = *ptr + size;
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;
383 if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) {
384 if (end - *ptr < 1)
385 goto fail;
387 group_id = id3_parse_uint(ptr, 1);
390 if ((flags & ID3_FRAME_FLAG_COMPRESSION) &&
391 !(flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR))
392 goto fail;
394 if (flags & ID3_FRAME_FLAG_ENCRYPTION) {
395 if (end - *ptr < 1)
396 goto fail;
398 encryption_method = id3_parse_uint(ptr, 1);
401 if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) {
402 if (end - *ptr < 4)
403 goto fail;
405 decoded_length = id3_parse_syncsafe(ptr, 4);
409 data = *ptr;
410 *ptr = end;
412 /* undo frame encodings */
414 if ((flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) && end - data > 0) {
415 mem = malloc(end - data);
416 if (mem == 0)
417 goto fail;
419 memcpy(mem, data, end - data);
421 end = mem + id3_util_deunsynchronise(mem, end - data);
422 data = mem;
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;
431 if (flags & ID3_FRAME_FLAG_COMPRESSION) {
432 id3_byte_t *decomp;
434 decomp = id3_util_decompress(data, end - data, decoded_length);
435 if (decomp == 0)
436 goto fail;
438 if (mem)
439 free(mem);
441 data = mem = decomp;
442 end = data + decoded_length;
445 /* check for obsolescence */
447 if (compat && !compat->equiv) {
448 frame = obsolete(id, data, end - data);
449 goto done;
452 /* generate the internal frame structure */
454 frame = id3_frame_new(id);
455 if (frame) {
456 frame->flags = flags;
457 frame->group_id = group_id;
459 if (compat && compat->translate) {
460 if (compat->translate(frame, compat->id, data, end - data) == -1)
461 goto fail;
463 else {
464 if (parse_data(frame, data, end - data) == -1)
465 goto fail;
469 if (0) {
470 fail:
471 if (frame) {
472 id3_frame_delete(frame);
473 frame = 0;
477 done:
478 if (mem)
479 free(mem);
481 return frame;
484 static
485 id3_length_t render_data(id3_byte_t **ptr,
486 union id3_field *fields, unsigned int length)
488 id3_length_t size = 0;
489 enum id3_field_textencoding encoding;
490 unsigned int i;
492 encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
494 for (i = 0; i < length; ++i)
495 size += id3_field_render(&fields[i], ptr, &encoding, i < length - 1);
497 return size;
501 * NAME: frame->render()
502 * DESCRIPTION: render a single, complete frame
504 id3_length_t id3_frame_render(struct id3_frame const *frame,
505 id3_byte_t **ptr, int options)
507 id3_length_t size = 0, decoded_length, datalen;
508 id3_byte_t *size_ptr = 0, *flags_ptr = 0, *data = 0;
509 int flags;
511 assert(frame);
513 if ((frame->flags & ID3_FRAME_FLAG_TAGALTERPRESERVATION) ||
514 ((options & ID3_TAG_OPTION_FILEALTERED) &&
515 (frame->flags & ID3_FRAME_FLAG_FILEALTERPRESERVATION)))
516 return 0;
518 /* a frame must be at least 1 byte big, excluding the header */
520 decoded_length = render_data(0, frame->fields, frame->nfields);
521 if (decoded_length == 0 && frame->encoded == 0)
522 return 0;
524 /* header */
526 size += id3_render_immediate(ptr, frame->id, 4);
528 if (ptr)
529 size_ptr = *ptr;
531 size += id3_render_syncsafe(ptr, 0, 4);
533 if (ptr)
534 flags_ptr = *ptr;
536 flags = frame->flags;
538 size += id3_render_int(ptr, flags, 2);
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);
545 return size;
548 flags &= ID3_FRAME_FLAG_KNOWNFLAGS;
550 flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION;
551 if (options & ID3_TAG_OPTION_UNSYNCHRONISATION)
552 flags |= ID3_FRAME_FLAG_UNSYNCHRONISATION;
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;
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);
570 if (ptr)
571 data = *ptr;
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);
581 if (flags & ID3_FRAME_FLAG_COMPRESSION) {
582 id3_byte_t *comp;
583 id3_length_t complen;
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);
592 free(comp);
598 /* unsynchronisation */
600 if (flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) {
601 if (data == 0)
602 datalen *= 2;
603 else {
604 id3_length_t newlen;
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;
616 size += datalen;
618 /* patch size and flags */
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);
625 return size;