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 $
37 # include "frametype.h"
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
)
57 valid_idchar(id
[0]) &&
58 valid_idchar(id
[1]) &&
59 valid_idchar(id
[2]) &&
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
;
73 if (!id3_frame_validid(id
))
76 frametype
= id3_frametype_lookup(id
, 4);
80 frametype
= &id3_frametype_text
;
84 frametype
= &id3_frametype_url
;
90 frametype
= &id3_frametype_experimental
;
94 frametype
= &id3_frametype_unknown
;
95 if (id3_compat_lookup(id
, 4))
96 frametype
= &id3_frametype_obsolete
;
101 frame
= malloc(sizeof(*frame
) + frametype
->nfields
* sizeof(*frame
->fields
));
103 frame
->id
[0] = id
[0];
104 frame
->id
[1] = id
[1];
105 frame
->id
[2] = id
[2];
106 frame
->id
[3] = id
[3];
109 frame
->description
= frametype
->description
;
111 frame
->flags
= frametype
->defaultflags
;
113 frame
->encryption_method
= 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
]);
127 void id3_frame_delete(struct id3_frame
*frame
)
131 if (frame
->refcount
== 0) {
134 for (i
= 0; i
< frame
->nfields
; ++i
)
135 id3_field_finish(&frame
->fields
[i
]);
138 free(frame
->encoded
);
145 * NAME: frame->addref()
146 * DESCRIPTION: add an external reference to a frame
148 void id3_frame_addref(struct id3_frame
*frame
)
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);
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
,
175 return (index
< frame
->nfields
) ? &frame
->fields
[index
] : 0;
179 struct id3_frame
*obsolete(char const *id
, id3_byte_t
const *data
,
182 struct id3_frame
*frame
;
184 frame
= id3_frame_new(ID3_FRAME_OBSOLETE
);
186 if (id3_field_setframeid(&frame
->fields
[0], id
) == -1 ||
187 id3_field_setbinarydata(&frame
->fields
[1], data
, length
) == -1)
194 id3_frame_delete(frame
);
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;
211 mem
= malloc(length
? length
: 1);
215 frame
= id3_frame_new(id
);
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
;
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
;
247 encoding
= ID3_FIELD_TEXTENCODING_ISO_8859_1
;
251 for (i
= 0; i
< frame
->nfields
; ++i
) {
252 if (id3_field_parse(&frame
->fields
[i
], &data
, end
- data
, &encoding
) == -1)
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;
277 if (ID3_TAG_VERSION_MAJOR(version
) < 4) {
278 switch (ID3_TAG_VERSION_MAJOR(version
)) {
283 compat
= id3_compat_lookup(id
, 3);
286 size
= id3_parse_uint(ptr
, 3);
288 if (size
> end
- *ptr
)
299 compat
= id3_compat_lookup(id
, 4);
302 size
= id3_parse_uint(ptr
, 4);
303 flags
= id3_parse_uint(ptr
, 2);
305 if (size
> end
- *ptr
)
310 if (flags
& (ID3_FRAME_FLAG_FORMATFLAGS
& ~0x00e0)) {
311 frame
= unparseable(id
, ptr
, end
- *ptr
, 0, 0, 0, 0);
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
) {
325 decoded_length
= id3_parse_uint(ptr
, 4);
328 if (flags
& ID3_FRAME_FLAG_ENCRYPTION
) {
332 encryption_method
= id3_parse_uint(ptr
, 1);
335 if (flags
& ID3_FRAME_FLAG_GROUPINGIDENTITY
) {
339 group_id
= id3_parse_uint(ptr
, 1);
348 /* canonicalize frame ID for ID3v2.4 */
350 if (compat
&& compat
->equiv
)
352 else if (ID3_TAG_VERSION_MAJOR(version
) == 2) {
361 ID3_FRAME_FLAG_TAGALTERPRESERVATION
|
362 ID3_FRAME_FLAG_FILEALTERPRESERVATION
;
370 size
= id3_parse_syncsafe(ptr
, 4);
371 flags
= id3_parse_uint(ptr
, 2);
373 if (size
> end
- *ptr
)
378 if (flags
& (ID3_FRAME_FLAG_FORMATFLAGS
& ~ID3_FRAME_FLAG_KNOWNFLAGS
)) {
379 frame
= unparseable(id
, ptr
, end
- *ptr
, flags
, 0, 0, 0);
383 if (flags
& ID3_FRAME_FLAG_GROUPINGIDENTITY
) {
387 group_id
= id3_parse_uint(ptr
, 1);
390 if ((flags
& ID3_FRAME_FLAG_COMPRESSION
) &&
391 !(flags
& ID3_FRAME_FLAG_DATALENGTHINDICATOR
))
394 if (flags
& ID3_FRAME_FLAG_ENCRYPTION
) {
398 encryption_method
= id3_parse_uint(ptr
, 1);
401 if (flags
& ID3_FRAME_FLAG_DATALENGTHINDICATOR
) {
405 decoded_length
= id3_parse_syncsafe(ptr
, 4);
412 /* undo frame encodings */
414 if ((flags
& ID3_FRAME_FLAG_UNSYNCHRONISATION
) && end
- data
> 0) {
415 mem
= malloc(end
- data
);
419 memcpy(mem
, data
, end
- data
);
421 end
= mem
+ id3_util_deunsynchronise(mem
, end
- data
);
425 if (flags
& ID3_FRAME_FLAG_ENCRYPTION
) {
426 frame
= unparseable(id
, &data
, end
- data
, flags
,
427 group_id
, encryption_method
, decoded_length
);
431 if (flags
& ID3_FRAME_FLAG_COMPRESSION
) {
434 decomp
= id3_util_decompress(data
, end
- data
, decoded_length
);
442 end
= data
+ decoded_length
;
445 /* check for obsolescence */
447 if (compat
&& !compat
->equiv
) {
448 frame
= obsolete(id
, data
, end
- data
);
452 /* generate the internal frame structure */
454 frame
= id3_frame_new(id
);
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)
464 if (parse_data(frame
, data
, end
- data
) == -1)
472 id3_frame_delete(frame
);
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
;
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);
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;
513 if ((frame
->flags
& ID3_FRAME_FLAG_TAGALTERPRESERVATION
) ||
514 ((options
& ID3_TAG_OPTION_FILEALTERED
) &&
515 (frame
->flags
& ID3_FRAME_FLAG_FILEALTERPRESERVATION
)))
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)
526 size
+= id3_render_immediate(ptr
, frame
->id
, 4);
531 size
+= id3_render_syncsafe(ptr
, 0, 4);
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
);
543 id3_render_syncsafe(&size_ptr
, size
- 10, 4);
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);
573 if (flags
& ID3_FRAME_FLAG_ENCRYPTION
)
574 datalen
= id3_render_binary(ptr
, frame
->encoded
, frame
->encoded_length
);
577 datalen
= decoded_length
;
579 datalen
= render_data(ptr
, frame
->fields
, frame
->nfields
);
581 if (flags
& ID3_FRAME_FLAG_COMPRESSION
) {
583 id3_length_t complen
;
585 comp
= id3_util_compress(data
, datalen
, &complen
);
587 flags
&= ~ID3_FRAME_FLAG_COMPRESSION
;
590 datalen
= id3_render_binary(ptr
, comp
, complen
);
598 /* unsynchronisation */
600 if (flags
& ID3_FRAME_FLAG_UNSYNCHRONISATION
) {
606 newlen
= id3_util_unsynchronise(data
, datalen
);
607 if (newlen
== datalen
)
608 flags
&= ~ID3_FRAME_FLAG_UNSYNCHRONISATION
;
610 *ptr
+= newlen
- datalen
;
618 /* patch size and flags */
621 id3_render_syncsafe(&size_ptr
, size
- 10, 4);
623 id3_render_int(&flags_ptr
, flags
, 2);