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: field.c,v 1.16 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 "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 */
id3_field_init(union id3_field * field,enum id3_field_type type)47 void 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 */
id3_field_finish(union id3_field * field)103 void 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 */
id3_field_type(union id3_field const * field)162 enum 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 */
id3_field_parse(union id3_field * field,id3_byte_t const ** ptr,id3_length_t length,enum id3_field_textencoding * encoding)173 int 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 */
id3_field_render(union id3_field const * field,id3_byte_t ** ptr,enum id3_field_textencoding * encoding,int terminate)337 id3_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 */
id3_field_setint(union id3_field * field,signed long number)408 int 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 */
id3_field_settextencoding(union id3_field * field,enum id3_field_textencoding encoding)448 int 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
463 static
set_latin1(union id3_field * field,id3_latin1_t const * latin1)464 int 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 */
id3_field_setlatin1(union id3_field * field,id3_latin1_t const * latin1)485 int 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 */
id3_field_setfulllatin1(union id3_field * field,id3_latin1_t const * latin1)510 int 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
522 static
set_string(union id3_field * field,id3_ucs4_t const * string)523 int 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 */
id3_field_setstring(union id3_field * field,id3_ucs4_t const * string)544 int 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 */
id3_field_setfullstring(union id3_field * field,id3_ucs4_t const * string)569 int 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 */
id3_field_setstrings(union id3_field * field,unsigned int length,id3_ucs4_t ** ptrs)585 int 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 */
id3_field_addstring(union id3_field * field,id3_ucs4_t const * string)626 int 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 */
id3_field_setlanguage(union id3_field * field,char const * language)659 int 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 */
id3_field_setframeid(union id3_field * field,char const * id)682 int 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 */
id3_field_setbinarydata(union id3_field * field,id3_byte_t const * data,id3_length_t length)705 int 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 */
id3_field_getint(union id3_field const * field)739 signed 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->gettextencoding()
754 * DESCRIPTION: return the value of a text encoding field
755 */
756 enum id3_field_textencoding
id3_field_gettextencoding(union id3_field const * field)757 id3_field_gettextencoding(union id3_field const *field)
758 {
759 assert(field);
760
761 if (field->type != ID3_FIELD_TYPE_TEXTENCODING)
762 return -1;
763
764 return field->number.value;
765 }
766
767 /*
768 * NAME: field->getlatin1()
769 * DESCRIPTION: return the value of a latin1 field
770 */
id3_field_getlatin1(union id3_field const * field)771 id3_latin1_t const *id3_field_getlatin1(union id3_field const *field)
772 {
773 assert(field);
774
775 if (field->type != ID3_FIELD_TYPE_LATIN1)
776 return 0;
777
778 return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) "";
779 }
780
781 /*
782 * NAME: field->getfulllatin1()
783 * DESCRIPTION: return the value of a full latin1 field
784 */
id3_field_getfulllatin1(union id3_field const * field)785 id3_latin1_t const *id3_field_getfulllatin1(union id3_field const *field)
786 {
787 assert(field);
788
789 if (field->type != ID3_FIELD_TYPE_LATIN1FULL)
790 return 0;
791
792 return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) "";
793 }
794
795 /*
796 * NAME: field->getstring()
797 * DESCRIPTION: return the value of a string field
798 */
id3_field_getstring(union id3_field const * field)799 id3_ucs4_t const *id3_field_getstring(union id3_field const *field)
800 {
801 assert(field);
802
803 if (field->type != ID3_FIELD_TYPE_STRING)
804 return 0;
805
806 return field->string.ptr ? field->string.ptr : id3_ucs4_empty;
807 }
808
809 /*
810 * NAME: field->getfullstring()
811 * DESCRIPTION: return the value of a fullstring field
812 */
id3_field_getfullstring(union id3_field const * field)813 id3_ucs4_t const *id3_field_getfullstring(union id3_field const *field)
814 {
815 assert(field);
816
817 if (field->type != ID3_FIELD_TYPE_STRINGFULL)
818 return 0;
819
820 return field->string.ptr ? field->string.ptr : id3_ucs4_empty;
821 }
822
823 /*
824 * NAME: field->getnstrings()
825 * DESCRIPTION: return the number of strings in a stringlist field
826 */
id3_field_getnstrings(union id3_field const * field)827 unsigned int id3_field_getnstrings(union id3_field const *field)
828 {
829 assert(field);
830
831 if (field->type != ID3_FIELD_TYPE_STRINGLIST)
832 return 0;
833
834 return field->stringlist.nstrings;
835 }
836
837 /*
838 * NAME: field->getstrings()
839 * DESCRIPTION: return one value of a stringlist field
840 */
id3_field_getstrings(union id3_field const * field,unsigned int index)841 id3_ucs4_t const *id3_field_getstrings(union id3_field const *field,
842 unsigned int index)
843 {
844 id3_ucs4_t const *string;
845
846 assert(field);
847
848 if (field->type != ID3_FIELD_TYPE_STRINGLIST ||
849 index >= field->stringlist.nstrings)
850 return 0;
851
852 string = field->stringlist.strings[index];
853
854 return string ? string : id3_ucs4_empty;
855 }
856
857 /*
858 * NAME: field->getframeid()
859 * DESCRIPTION: return the value of a frameid field
860 */
id3_field_getframeid(union id3_field const * field)861 char const *id3_field_getframeid(union id3_field const *field)
862 {
863 assert(field);
864
865 if (field->type != ID3_FIELD_TYPE_FRAMEID)
866 return 0;
867
868 return field->immediate.value;
869 }
870
871 /*
872 * NAME: field->getbinarydata()
873 * DESCRIPTION: return the value of a binarydata field
874 */
id3_field_getbinarydata(union id3_field const * field,id3_length_t * length)875 id3_byte_t const *id3_field_getbinarydata(union id3_field const *field,
876 id3_length_t *length)
877 {
878 static id3_byte_t const empty;
879
880 assert(field && length);
881
882 if (field->type != ID3_FIELD_TYPE_BINARYDATA)
883 return 0;
884
885 assert(field->binary.length == 0 || field->binary.data);
886
887 *length = field->binary.length;
888
889 return field->binary.data ? field->binary.data : ∅
890 }
891