1/* 2 * libid3tag - ID3 tag manipulation library 3 * Copyright (C) 2000-2003 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.14 2003/04/19 00:14:33 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 44static 45int 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 */ 54int 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 */ 67struct 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 127void 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 */ 148void 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 */ 159void 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 */ 170union 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 178static 179struct 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 202static 203struct 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 239static 240int 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 */ 263struct 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 484static 485id3_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 */ 504id3_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