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: field.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 "field.h" 37# include "frame.h" 38# include "render.h" 39# include "ucs4.h" 40# include "latin1.h" 41# include "parse.h" 42 43/* 44 * NAME: field->init() 45 * DESCRIPTION: initialize a field to a default value for the given type 46 */ 47void id3_field_init(union id3_field *field, enum id3_field_type type) 48{ 49 assert(field); 50 51 switch (field->type = type) { 52 case ID3_FIELD_TYPE_TEXTENCODING: 53 case ID3_FIELD_TYPE_INT8: 54 case ID3_FIELD_TYPE_INT16: 55 case ID3_FIELD_TYPE_INT24: 56 case ID3_FIELD_TYPE_INT32: 57 field->number.value = 0; 58 break; 59 60 case ID3_FIELD_TYPE_LATIN1: 61 case ID3_FIELD_TYPE_LATIN1FULL: 62 field->latin1.ptr = 0; 63 break; 64 65 case ID3_FIELD_TYPE_LATIN1LIST: 66 field->latin1list.nstrings = 0; 67 field->latin1list.strings = 0; 68 69 case ID3_FIELD_TYPE_STRING: 70 case ID3_FIELD_TYPE_STRINGFULL: 71 field->string.ptr = 0; 72 break; 73 74 case ID3_FIELD_TYPE_STRINGLIST: 75 field->stringlist.nstrings = 0; 76 field->stringlist.strings = 0; 77 break; 78 79 case ID3_FIELD_TYPE_LANGUAGE: 80 strcpy(field->immediate.value, "XXX"); 81 break; 82 83 case ID3_FIELD_TYPE_FRAMEID: 84 strcpy(field->immediate.value, "XXXX"); 85 break; 86 87 case ID3_FIELD_TYPE_DATE: 88 memset(field->immediate.value, 0, sizeof(field->immediate.value)); 89 break; 90 91 case ID3_FIELD_TYPE_INT32PLUS: 92 case ID3_FIELD_TYPE_BINARYDATA: 93 field->binary.data = 0; 94 field->binary.length = 0; 95 break; 96 } 97} 98 99/* 100 * NAME: field->finish() 101 * DESCRIPTION: reset a field, deallocating memory if necessary 102 */ 103void id3_field_finish(union id3_field *field) 104{ 105 unsigned int i; 106 107 assert(field); 108 109 switch (field->type) { 110 case ID3_FIELD_TYPE_TEXTENCODING: 111 case ID3_FIELD_TYPE_INT8: 112 case ID3_FIELD_TYPE_INT16: 113 case ID3_FIELD_TYPE_INT24: 114 case ID3_FIELD_TYPE_INT32: 115 case ID3_FIELD_TYPE_LANGUAGE: 116 case ID3_FIELD_TYPE_FRAMEID: 117 case ID3_FIELD_TYPE_DATE: 118 break; 119 120 case ID3_FIELD_TYPE_LATIN1: 121 case ID3_FIELD_TYPE_LATIN1FULL: 122 if (field->latin1.ptr) 123 free(field->latin1.ptr); 124 break; 125 126 case ID3_FIELD_TYPE_LATIN1LIST: 127 for (i = 0; i < field->latin1list.nstrings; ++i) 128 free(field->latin1list.strings[i]); 129 130 if (field->latin1list.strings) 131 free(field->latin1list.strings); 132 break; 133 134 case ID3_FIELD_TYPE_STRING: 135 case ID3_FIELD_TYPE_STRINGFULL: 136 if (field->string.ptr) 137 free(field->string.ptr); 138 break; 139 140 case ID3_FIELD_TYPE_STRINGLIST: 141 for (i = 0; i < field->stringlist.nstrings; ++i) 142 free(field->stringlist.strings[i]); 143 144 if (field->stringlist.strings) 145 free(field->stringlist.strings); 146 break; 147 148 case ID3_FIELD_TYPE_INT32PLUS: 149 case ID3_FIELD_TYPE_BINARYDATA: 150 if (field->binary.data) 151 free(field->binary.data); 152 break; 153 } 154 155 id3_field_init(field, field->type); 156} 157 158/* 159 * NAME: field->type() 160 * DESCRIPTION: return the value type of a field 161 */ 162enum id3_field_type id3_field_type(union id3_field const *field) 163{ 164 assert(field); 165 166 return field->type; 167} 168 169/* 170 * NAME: field->parse() 171 * DESCRIPTION: parse a field value 172 */ 173int id3_field_parse(union id3_field *field, id3_byte_t const **ptr, 174 id3_length_t length, enum id3_field_textencoding *encoding) 175{ 176 assert(field); 177 178 id3_field_finish(field); 179 180 switch (field->type) { 181 case ID3_FIELD_TYPE_INT32: 182 if (length < 4) 183 goto fail; 184 185 field->number.value = id3_parse_uint(ptr, 4); 186 break; 187 188 case ID3_FIELD_TYPE_INT24: 189 if (length < 3) 190 goto fail; 191 192 field->number.value = id3_parse_uint(ptr, 3); 193 break; 194 195 case ID3_FIELD_TYPE_INT16: 196 if (length < 2) 197 goto fail; 198 199 field->number.value = id3_parse_uint(ptr, 2); 200 break; 201 202 case ID3_FIELD_TYPE_INT8: 203 case ID3_FIELD_TYPE_TEXTENCODING: 204 if (length < 1) 205 goto fail; 206 207 field->number.value = id3_parse_uint(ptr, 1); 208 209 if (field->type == ID3_FIELD_TYPE_TEXTENCODING) 210 *encoding = field->number.value; 211 break; 212 213 case ID3_FIELD_TYPE_LANGUAGE: 214 if (length < 3) 215 goto fail; 216 217 id3_parse_immediate(ptr, 3, field->immediate.value); 218 break; 219 220 case ID3_FIELD_TYPE_FRAMEID: 221 if (length < 4) 222 goto fail; 223 224 id3_parse_immediate(ptr, 4, field->immediate.value); 225 break; 226 227 case ID3_FIELD_TYPE_DATE: 228 if (length < 8) 229 goto fail; 230 231 id3_parse_immediate(ptr, 8, field->immediate.value); 232 break; 233 234 case ID3_FIELD_TYPE_LATIN1: 235 case ID3_FIELD_TYPE_LATIN1FULL: 236 { 237 id3_latin1_t *latin1; 238 239 latin1 = id3_parse_latin1(ptr, length, 240 field->type == ID3_FIELD_TYPE_LATIN1FULL); 241 if (latin1 == 0) 242 goto fail; 243 244 field->latin1.ptr = latin1; 245 } 246 break; 247 248 case ID3_FIELD_TYPE_LATIN1LIST: 249 { 250 id3_byte_t const *end; 251 id3_latin1_t *latin1, **strings; 252 253 end = *ptr + length; 254 255 while (end - *ptr > 0) { 256 latin1 = id3_parse_latin1(ptr, end - *ptr, 0); 257 if (latin1 == 0) 258 goto fail; 259 260 strings = realloc(field->latin1list.strings, 261 (field->latin1list.nstrings + 1) * sizeof(*strings)); 262 if (strings == 0) { 263 free(latin1); 264 goto fail; 265 } 266 267 field->latin1list.strings = strings; 268 field->latin1list.strings[field->latin1list.nstrings++] = latin1; 269 } 270 } 271 break; 272 273 case ID3_FIELD_TYPE_STRING: 274 case ID3_FIELD_TYPE_STRINGFULL: 275 { 276 id3_ucs4_t *ucs4; 277 278 ucs4 = id3_parse_string(ptr, length, *encoding, 279 field->type == ID3_FIELD_TYPE_STRINGFULL); 280 if (ucs4 == 0) 281 goto fail; 282 283 field->string.ptr = ucs4; 284 } 285 break; 286 287 case ID3_FIELD_TYPE_STRINGLIST: 288 { 289 id3_byte_t const *end; 290 id3_ucs4_t *ucs4, **strings; 291 292 end = *ptr + length; 293 294 while (end - *ptr > 0) { 295 ucs4 = id3_parse_string(ptr, end - *ptr, *encoding, 0); 296 if (ucs4 == 0) 297 goto fail; 298 299 strings = realloc(field->stringlist.strings, 300 (field->stringlist.nstrings + 1) * sizeof(*strings)); 301 if (strings == 0) { 302 free(ucs4); 303 goto fail; 304 } 305 306 field->stringlist.strings = strings; 307 field->stringlist.strings[field->stringlist.nstrings++] = ucs4; 308 } 309 } 310 break; 311 312 case ID3_FIELD_TYPE_INT32PLUS: 313 case ID3_FIELD_TYPE_BINARYDATA: 314 { 315 id3_byte_t *data; 316 317 data = id3_parse_binary(ptr, length); 318 if (data == 0) 319 goto fail; 320 321 field->binary.data = data; 322 field->binary.length = length; 323 } 324 break; 325 } 326 327 return 0; 328 329 fail: 330 return -1; 331} 332 333/* 334 * NAME: field->render() 335 * DESCRIPTION: render a field value 336 */ 337id3_length_t id3_field_render(union id3_field const *field, id3_byte_t **ptr, 338 enum id3_field_textencoding *encoding, 339 int terminate) 340{ 341 id3_length_t size; 342 unsigned int i; 343 344 assert(field && encoding); 345 346 switch (field->type) { 347 case ID3_FIELD_TYPE_INT32: 348 return id3_render_int(ptr, field->number.value, 4); 349 350 case ID3_FIELD_TYPE_INT24: 351 return id3_render_int(ptr, field->number.value, 3); 352 353 case ID3_FIELD_TYPE_INT16: 354 return id3_render_int(ptr, field->number.value, 2); 355 356 case ID3_FIELD_TYPE_TEXTENCODING: 357 *encoding = field->number.value; 358 case ID3_FIELD_TYPE_INT8: 359 return id3_render_int(ptr, field->number.value, 1); 360 361 case ID3_FIELD_TYPE_LATIN1: 362 case ID3_FIELD_TYPE_LATIN1FULL: 363 return id3_render_latin1(ptr, field->latin1.ptr, terminate); 364 365 case ID3_FIELD_TYPE_LATIN1LIST: 366 size = 0; 367 for (i = 0; i < field->latin1list.nstrings; ++i) { 368 size += id3_render_latin1(ptr, field->latin1list.strings[i], 369 (i < field->latin1list.nstrings - 1) || 370 terminate); 371 } 372 return size; 373 374 case ID3_FIELD_TYPE_STRING: 375 case ID3_FIELD_TYPE_STRINGFULL: 376 return id3_render_string(ptr, field->string.ptr, *encoding, terminate); 377 378 case ID3_FIELD_TYPE_STRINGLIST: 379 size = 0; 380 for (i = 0; i < field->stringlist.nstrings; ++i) { 381 size += id3_render_string(ptr, field->stringlist.strings[i], *encoding, 382 (i < field->stringlist.nstrings - 1) || 383 terminate); 384 } 385 return size; 386 387 case ID3_FIELD_TYPE_LANGUAGE: 388 return id3_render_immediate(ptr, field->immediate.value, 3); 389 390 case ID3_FIELD_TYPE_FRAMEID: 391 return id3_render_immediate(ptr, field->immediate.value, 4); 392 393 case ID3_FIELD_TYPE_DATE: 394 return id3_render_immediate(ptr, field->immediate.value, 8); 395 396 case ID3_FIELD_TYPE_INT32PLUS: 397 case ID3_FIELD_TYPE_BINARYDATA: 398 return id3_render_binary(ptr, field->binary.data, field->binary.length); 399 } 400 401 return 0; 402} 403 404/* 405 * NAME: field->setint() 406 * DESCRIPTION: set the value of an int field 407 */ 408int id3_field_setint(union id3_field *field, signed long number) 409{ 410 assert(field); 411 412 switch (field->type) { 413 case ID3_FIELD_TYPE_INT8: 414 if (number > 0x7f || number < -0x80) 415 return -1; 416 break; 417 418 case ID3_FIELD_TYPE_INT16: 419 if (number > 0x7fff || number < -0x8000) 420 return -1; 421 break; 422 423 case ID3_FIELD_TYPE_INT24: 424 if (number > 0x7fffffL || number < -0x800000L) 425 return -1; 426 break; 427 428 case ID3_FIELD_TYPE_INT32: 429 if (number > 0x7fffffffL || number < -0x80000000L) 430 return -1; 431 break; 432 433 default: 434 return -1; 435 } 436 437 id3_field_finish(field); 438 439 field->number.value = number; 440 441 return 0; 442} 443 444/* 445 * NAME: field->settextencoding() 446 * DESCRIPTION: set the value of a textencoding field 447 */ 448int id3_field_settextencoding(union id3_field *field, 449 enum id3_field_textencoding encoding) 450{ 451 assert(field); 452 453 if (field->type != ID3_FIELD_TYPE_TEXTENCODING) 454 return -1; 455 456 id3_field_finish(field); 457 458 field->number.value = encoding; 459 460 return 0; 461} 462 463static 464int set_latin1(union id3_field *field, id3_latin1_t const *latin1) 465{ 466 id3_latin1_t *data; 467 468 if (latin1 == 0 || *latin1 == 0) 469 data = 0; 470 else { 471 data = id3_latin1_duplicate(latin1); 472 if (data == 0) 473 return -1; 474 } 475 476 field->latin1.ptr = data; 477 478 return 0; 479} 480 481/* 482 * NAME: field->setlatin1() 483 * DESCRIPTION: set the value of a latin1 field 484 */ 485int id3_field_setlatin1(union id3_field *field, id3_latin1_t const *latin1) 486{ 487 assert(field); 488 489 if (field->type != ID3_FIELD_TYPE_LATIN1) 490 return -1; 491 492 id3_field_finish(field); 493 494 if (latin1) { 495 id3_latin1_t const *ptr; 496 497 for (ptr = latin1; *ptr; ++ptr) { 498 if (*ptr == '\n') 499 return -1; 500 } 501 } 502 503 return set_latin1(field, latin1); 504} 505 506/* 507 * NAME: field->setfulllatin1() 508 * DESCRIPTION: set the value of a full latin1 field 509 */ 510int id3_field_setfulllatin1(union id3_field *field, id3_latin1_t const *latin1) 511{ 512 assert(field); 513 514 if (field->type != ID3_FIELD_TYPE_LATIN1FULL) 515 return -1; 516 517 id3_field_finish(field); 518 519 return set_latin1(field, latin1); 520} 521 522static 523int set_string(union id3_field *field, id3_ucs4_t const *string) 524{ 525 id3_ucs4_t *data; 526 527 if (string == 0 || *string == 0) 528 data = 0; 529 else { 530 data = id3_ucs4_duplicate(string); 531 if (data == 0) 532 return -1; 533 } 534 535 field->string.ptr = data; 536 537 return 0; 538} 539 540/* 541 * NAME: field->setstring() 542 * DESCRIPTION: set the value of a string field 543 */ 544int id3_field_setstring(union id3_field *field, id3_ucs4_t const *string) 545{ 546 assert(field); 547 548 if (field->type != ID3_FIELD_TYPE_STRING) 549 return -1; 550 551 id3_field_finish(field); 552 553 if (string) { 554 id3_ucs4_t const *ptr; 555 556 for (ptr = string; *ptr; ++ptr) { 557 if (*ptr == '\n') 558 return -1; 559 } 560 } 561 562 return set_string(field, string); 563} 564 565/* 566 * NAME: field->setfullstring() 567 * DESCRIPTION: set the value of a full string field 568 */ 569int id3_field_setfullstring(union id3_field *field, id3_ucs4_t const *string) 570{ 571 assert(field); 572 573 if (field->type != ID3_FIELD_TYPE_STRINGFULL) 574 return -1; 575 576 id3_field_finish(field); 577 578 return set_string(field, string); 579} 580 581/* 582 * NAME: field->setstrings() 583 * DESCRIPTION: set the value of a stringlist field 584 */ 585int id3_field_setstrings(union id3_field *field, 586 unsigned int length, id3_ucs4_t **ptrs) 587{ 588 id3_ucs4_t **strings; 589 unsigned int i; 590 591 assert(field); 592 593 if (field->type != ID3_FIELD_TYPE_STRINGLIST) 594 return -1; 595 596 id3_field_finish(field); 597 598 if (length == 0) 599 return 0; 600 601 strings = malloc(length * sizeof(*strings)); 602 if (strings == 0) 603 return -1; 604 605 for (i = 0; i < length; ++i) { 606 strings[i] = id3_ucs4_duplicate(ptrs[i]); 607 if (strings[i] == 0) { 608 while (i--) 609 free(strings[i]); 610 611 free(strings); 612 return -1; 613 } 614 } 615 616 field->stringlist.strings = strings; 617 field->stringlist.nstrings = length; 618 619 return 0; 620} 621 622/* 623 * NAME: field->addstring() 624 * DESCRIPTION: add a string to a stringlist field 625 */ 626int id3_field_addstring(union id3_field *field, id3_ucs4_t const *string) 627{ 628 id3_ucs4_t *new, **strings; 629 630 assert(field); 631 632 if (field->type != ID3_FIELD_TYPE_STRINGLIST) 633 return -1; 634 635 if (string == 0) 636 string = id3_ucs4_empty; 637 638 new = id3_ucs4_duplicate(string); 639 if (new == 0) 640 return -1; 641 642 strings = realloc(field->stringlist.strings, 643 (field->stringlist.nstrings + 1) * sizeof(*strings)); 644 if (strings == 0) { 645 free(new); 646 return -1; 647 } 648 649 field->stringlist.strings = strings; 650 field->stringlist.strings[field->stringlist.nstrings++] = new; 651 652 return 0; 653} 654 655/* 656 * NAME: field->setlanguage() 657 * DESCRIPTION: set the value of a language field 658 */ 659int id3_field_setlanguage(union id3_field *field, char const *language) 660{ 661 assert(field); 662 663 if (field->type != ID3_FIELD_TYPE_LANGUAGE) 664 return -1; 665 666 id3_field_finish(field); 667 668 if (language) { 669 if (strlen(language) != 3) 670 return -1; 671 672 strcpy(field->immediate.value, language); 673 } 674 675 return 0; 676} 677 678/* 679 * NAME: field->setframeid() 680 * DESCRIPTION: set the value of a frameid field 681 */ 682int id3_field_setframeid(union id3_field *field, char const *id) 683{ 684 assert(field); 685 686 if (field->type != ID3_FIELD_TYPE_FRAMEID || 687 !id3_frame_validid(id)) 688 return -1; 689 690 id3_field_finish(field); 691 692 field->immediate.value[0] = id[0]; 693 field->immediate.value[1] = id[1]; 694 field->immediate.value[2] = id[2]; 695 field->immediate.value[3] = id[3]; 696 field->immediate.value[4] = 0; 697 698 return 0; 699} 700 701/* 702 * NAME: field->setbinarydata() 703 * DESCRIPTION: set the value of a binarydata field 704 */ 705int id3_field_setbinarydata(union id3_field *field, 706 id3_byte_t const *data, id3_length_t length) 707{ 708 id3_byte_t *mem; 709 710 assert(field); 711 712 if (field->type != ID3_FIELD_TYPE_BINARYDATA) 713 return -1; 714 715 id3_field_finish(field); 716 717 if (length == 0) 718 mem = 0; 719 else { 720 mem = malloc(length); 721 if (mem == 0) 722 return -1; 723 724 assert(data); 725 726 memcpy(mem, data, length); 727 } 728 729 field->binary.data = mem; 730 field->binary.length = length; 731 732 return 0; 733} 734 735/* 736 * NAME: field->getint() 737 * DESCRIPTION: return the value of an integer field 738 */ 739signed long id3_field_getint(union id3_field const *field) 740{ 741 assert(field); 742 743 if (field->type != ID3_FIELD_TYPE_INT8 && 744 field->type != ID3_FIELD_TYPE_INT16 && 745 field->type != ID3_FIELD_TYPE_INT24 && 746 field->type != ID3_FIELD_TYPE_INT32) 747 return -1; 748 749 return field->number.value; 750} 751 752/* 753 * NAME: field->getlatin1() 754 * DESCRIPTION: return the value of a latin1 field 755 */ 756id3_latin1_t const *id3_field_getlatin1(union id3_field const *field) 757{ 758 assert(field); 759 760 if (field->type != ID3_FIELD_TYPE_LATIN1) 761 return 0; 762 763 return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) ""; 764} 765 766/* 767 * NAME: field->getfulllatin1() 768 * DESCRIPTION: return the value of a full latin1 field 769 */ 770id3_latin1_t const *id3_field_getfulllatin1(union id3_field const *field) 771{ 772 assert(field); 773 774 if (field->type != ID3_FIELD_TYPE_LATIN1FULL) 775 return 0; 776 777 return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) ""; 778} 779 780/* 781 * NAME: field->getstring() 782 * DESCRIPTION: return the value of a string field 783 */ 784id3_ucs4_t const *id3_field_getstring(union id3_field const *field) 785{ 786 assert(field); 787 788 if (field->type != ID3_FIELD_TYPE_STRING) 789 return 0; 790 791 return field->string.ptr ? field->string.ptr : id3_ucs4_empty; 792} 793 794/* 795 * NAME: field->getfullstring() 796 * DESCRIPTION: return the value of a fullstring field 797 */ 798id3_ucs4_t const *id3_field_getfullstring(union id3_field const *field) 799{ 800 assert(field); 801 802 if (field->type != ID3_FIELD_TYPE_STRINGFULL) 803 return 0; 804 805 return field->string.ptr ? field->string.ptr : id3_ucs4_empty; 806} 807 808/* 809 * NAME: field->getnstrings() 810 * DESCRIPTION: return the number of strings in a stringlist field 811 */ 812unsigned int id3_field_getnstrings(union id3_field const *field) 813{ 814 assert(field); 815 816 if (field->type != ID3_FIELD_TYPE_STRINGLIST) 817 return 0; 818 819 return field->stringlist.nstrings; 820} 821 822/* 823 * NAME: field->getstrings() 824 * DESCRIPTION: return one value of a stringlist field 825 */ 826id3_ucs4_t const *id3_field_getstrings(union id3_field const *field, 827 unsigned int index) 828{ 829 id3_ucs4_t const *string; 830 831 assert(field); 832 833 if (field->type != ID3_FIELD_TYPE_STRINGLIST || 834 index >= field->stringlist.nstrings) 835 return 0; 836 837 string = field->stringlist.strings[index]; 838 839 return string ? string : id3_ucs4_empty; 840} 841 842/* 843 * NAME: field->getframeid() 844 * DESCRIPTION: return the value of a frameid field 845 */ 846char const *id3_field_getframeid(union id3_field const *field) 847{ 848 assert(field); 849 850 if (field->type != ID3_FIELD_TYPE_FRAMEID) 851 return 0; 852 853 return field->immediate.value; 854} 855 856/* 857 * NAME: field->getbinarydata() 858 * DESCRIPTION: return the value of a binarydata field 859 */ 860id3_byte_t const *id3_field_getbinarydata(union id3_field const *field, 861 id3_length_t *length) 862{ 863 static id3_byte_t const empty; 864 865 assert(field && length); 866 867 if (field->type != ID3_FIELD_TYPE_BINARYDATA) 868 return 0; 869 870 assert(field->binary.length == 0 || field->binary.data); 871 872 *length = field->binary.length; 873 874 return field->binary.data ? field->binary.data : ∅ 875} 876