Mercurial > hg > sv-dependency-builds
comparison src/libid3tag-0.15.1b/frame.c @ 85:545efbb81310
Import initial set of sources
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Mon, 18 Mar 2013 14:12:14 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 85:545efbb81310 |
---|---|
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 } |