Chris@0: /* Chris@0: * libid3tag - ID3 tag manipulation library Chris@0: * Copyright (C) 2000-2004 Underbit Technologies, Inc. Chris@0: * Chris@0: * This program is free software; you can redistribute it and/or modify Chris@0: * it under the terms of the GNU General Public License as published by Chris@0: * the Free Software Foundation; either version 2 of the License, or Chris@0: * (at your option) any later version. Chris@0: * Chris@0: * This program is distributed in the hope that it will be useful, Chris@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@0: * GNU General Public License for more details. Chris@0: * Chris@0: * You should have received a copy of the GNU General Public License Chris@0: * along with this program; if not, write to the Free Software Chris@0: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Chris@0: * Chris@0: * $Id: field.c,v 1.16 2004/01/23 09:41:32 rob Exp $ Chris@0: */ Chris@0: Chris@0: # ifdef HAVE_CONFIG_H Chris@0: # include "config.h" Chris@0: # endif Chris@0: Chris@0: # include "global.h" Chris@0: Chris@0: # include Chris@0: # include Chris@0: Chris@0: # ifdef HAVE_ASSERT_H Chris@0: # include Chris@0: # endif Chris@0: Chris@0: # include "id3tag.h" Chris@0: # include "field.h" Chris@0: # include "frame.h" Chris@0: # include "render.h" Chris@0: # include "ucs4.h" Chris@0: # include "latin1.h" Chris@0: # include "parse.h" Chris@0: Chris@0: /* Chris@0: * NAME: field->init() Chris@0: * DESCRIPTION: initialize a field to a default value for the given type Chris@0: */ Chris@0: void id3_field_init(union id3_field *field, enum id3_field_type type) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: switch (field->type = type) { Chris@0: case ID3_FIELD_TYPE_TEXTENCODING: Chris@0: case ID3_FIELD_TYPE_INT8: Chris@0: case ID3_FIELD_TYPE_INT16: Chris@0: case ID3_FIELD_TYPE_INT24: Chris@0: case ID3_FIELD_TYPE_INT32: Chris@0: field->number.value = 0; Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_LATIN1: Chris@0: case ID3_FIELD_TYPE_LATIN1FULL: Chris@0: field->latin1.ptr = 0; Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_LATIN1LIST: Chris@0: field->latin1list.nstrings = 0; Chris@0: field->latin1list.strings = 0; Chris@0: Chris@0: case ID3_FIELD_TYPE_STRING: Chris@0: case ID3_FIELD_TYPE_STRINGFULL: Chris@0: field->string.ptr = 0; Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_STRINGLIST: Chris@0: field->stringlist.nstrings = 0; Chris@0: field->stringlist.strings = 0; Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_LANGUAGE: Chris@0: strcpy(field->immediate.value, "XXX"); Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_FRAMEID: Chris@0: strcpy(field->immediate.value, "XXXX"); Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_DATE: Chris@0: memset(field->immediate.value, 0, sizeof(field->immediate.value)); Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_INT32PLUS: Chris@0: case ID3_FIELD_TYPE_BINARYDATA: Chris@0: field->binary.data = 0; Chris@0: field->binary.length = 0; Chris@0: break; Chris@0: } Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->finish() Chris@0: * DESCRIPTION: reset a field, deallocating memory if necessary Chris@0: */ Chris@0: void id3_field_finish(union id3_field *field) Chris@0: { Chris@0: unsigned int i; Chris@0: Chris@0: assert(field); Chris@0: Chris@0: switch (field->type) { Chris@0: case ID3_FIELD_TYPE_TEXTENCODING: Chris@0: case ID3_FIELD_TYPE_INT8: Chris@0: case ID3_FIELD_TYPE_INT16: Chris@0: case ID3_FIELD_TYPE_INT24: Chris@0: case ID3_FIELD_TYPE_INT32: Chris@0: case ID3_FIELD_TYPE_LANGUAGE: Chris@0: case ID3_FIELD_TYPE_FRAMEID: Chris@0: case ID3_FIELD_TYPE_DATE: Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_LATIN1: Chris@0: case ID3_FIELD_TYPE_LATIN1FULL: Chris@0: if (field->latin1.ptr) Chris@0: free(field->latin1.ptr); Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_LATIN1LIST: Chris@0: for (i = 0; i < field->latin1list.nstrings; ++i) Chris@0: free(field->latin1list.strings[i]); Chris@0: Chris@0: if (field->latin1list.strings) Chris@0: free(field->latin1list.strings); Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_STRING: Chris@0: case ID3_FIELD_TYPE_STRINGFULL: Chris@0: if (field->string.ptr) Chris@0: free(field->string.ptr); Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_STRINGLIST: Chris@0: for (i = 0; i < field->stringlist.nstrings; ++i) Chris@0: free(field->stringlist.strings[i]); Chris@0: Chris@0: if (field->stringlist.strings) Chris@0: free(field->stringlist.strings); Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_INT32PLUS: Chris@0: case ID3_FIELD_TYPE_BINARYDATA: Chris@0: if (field->binary.data) Chris@0: free(field->binary.data); Chris@0: break; Chris@0: } Chris@0: Chris@0: id3_field_init(field, field->type); Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->type() Chris@0: * DESCRIPTION: return the value type of a field Chris@0: */ Chris@0: enum id3_field_type id3_field_type(union id3_field const *field) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: return field->type; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->parse() Chris@0: * DESCRIPTION: parse a field value Chris@0: */ Chris@0: int id3_field_parse(union id3_field *field, id3_byte_t const **ptr, Chris@0: id3_length_t length, enum id3_field_textencoding *encoding) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: id3_field_finish(field); Chris@0: Chris@0: switch (field->type) { Chris@0: case ID3_FIELD_TYPE_INT32: Chris@0: if (length < 4) Chris@0: goto fail; Chris@0: Chris@0: field->number.value = id3_parse_uint(ptr, 4); Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_INT24: Chris@0: if (length < 3) Chris@0: goto fail; Chris@0: Chris@0: field->number.value = id3_parse_uint(ptr, 3); Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_INT16: Chris@0: if (length < 2) Chris@0: goto fail; Chris@0: Chris@0: field->number.value = id3_parse_uint(ptr, 2); Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_INT8: Chris@0: case ID3_FIELD_TYPE_TEXTENCODING: Chris@0: if (length < 1) Chris@0: goto fail; Chris@0: Chris@0: field->number.value = id3_parse_uint(ptr, 1); Chris@0: Chris@0: if (field->type == ID3_FIELD_TYPE_TEXTENCODING) Chris@0: *encoding = field->number.value; Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_LANGUAGE: Chris@0: if (length < 3) Chris@0: goto fail; Chris@0: Chris@0: id3_parse_immediate(ptr, 3, field->immediate.value); Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_FRAMEID: Chris@0: if (length < 4) Chris@0: goto fail; Chris@0: Chris@0: id3_parse_immediate(ptr, 4, field->immediate.value); Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_DATE: Chris@0: if (length < 8) Chris@0: goto fail; Chris@0: Chris@0: id3_parse_immediate(ptr, 8, field->immediate.value); Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_LATIN1: Chris@0: case ID3_FIELD_TYPE_LATIN1FULL: Chris@0: { Chris@0: id3_latin1_t *latin1; Chris@0: Chris@0: latin1 = id3_parse_latin1(ptr, length, Chris@0: field->type == ID3_FIELD_TYPE_LATIN1FULL); Chris@0: if (latin1 == 0) Chris@0: goto fail; Chris@0: Chris@0: field->latin1.ptr = latin1; Chris@0: } Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_LATIN1LIST: Chris@0: { Chris@0: id3_byte_t const *end; Chris@0: id3_latin1_t *latin1, **strings; Chris@0: Chris@0: end = *ptr + length; Chris@0: Chris@0: while (end - *ptr > 0) { Chris@0: latin1 = id3_parse_latin1(ptr, end - *ptr, 0); Chris@0: if (latin1 == 0) Chris@0: goto fail; Chris@0: Chris@0: strings = realloc(field->latin1list.strings, Chris@0: (field->latin1list.nstrings + 1) * sizeof(*strings)); Chris@0: if (strings == 0) { Chris@0: free(latin1); Chris@0: goto fail; Chris@0: } Chris@0: Chris@0: field->latin1list.strings = strings; Chris@0: field->latin1list.strings[field->latin1list.nstrings++] = latin1; Chris@0: } Chris@0: } Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_STRING: Chris@0: case ID3_FIELD_TYPE_STRINGFULL: Chris@0: { Chris@0: id3_ucs4_t *ucs4; Chris@0: Chris@0: ucs4 = id3_parse_string(ptr, length, *encoding, Chris@0: field->type == ID3_FIELD_TYPE_STRINGFULL); Chris@0: if (ucs4 == 0) Chris@0: goto fail; Chris@0: Chris@0: field->string.ptr = ucs4; Chris@0: } Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_STRINGLIST: Chris@0: { Chris@0: id3_byte_t const *end; Chris@0: id3_ucs4_t *ucs4, **strings; Chris@0: Chris@0: end = *ptr + length; Chris@0: Chris@0: while (end - *ptr > 0) { Chris@0: ucs4 = id3_parse_string(ptr, end - *ptr, *encoding, 0); Chris@0: if (ucs4 == 0) Chris@0: goto fail; Chris@0: Chris@0: strings = realloc(field->stringlist.strings, Chris@0: (field->stringlist.nstrings + 1) * sizeof(*strings)); Chris@0: if (strings == 0) { Chris@0: free(ucs4); Chris@0: goto fail; Chris@0: } Chris@0: Chris@0: field->stringlist.strings = strings; Chris@0: field->stringlist.strings[field->stringlist.nstrings++] = ucs4; Chris@0: } Chris@0: } Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_INT32PLUS: Chris@0: case ID3_FIELD_TYPE_BINARYDATA: Chris@0: { Chris@0: id3_byte_t *data; Chris@0: Chris@0: data = id3_parse_binary(ptr, length); Chris@0: if (data == 0) Chris@0: goto fail; Chris@0: Chris@0: field->binary.data = data; Chris@0: field->binary.length = length; Chris@0: } Chris@0: break; Chris@0: } Chris@0: Chris@0: return 0; Chris@0: Chris@0: fail: Chris@0: return -1; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->render() Chris@0: * DESCRIPTION: render a field value Chris@0: */ Chris@0: id3_length_t id3_field_render(union id3_field const *field, id3_byte_t **ptr, Chris@0: enum id3_field_textencoding *encoding, Chris@0: int terminate) Chris@0: { Chris@0: id3_length_t size; Chris@0: unsigned int i; Chris@0: Chris@0: assert(field && encoding); Chris@0: Chris@0: switch (field->type) { Chris@0: case ID3_FIELD_TYPE_INT32: Chris@0: return id3_render_int(ptr, field->number.value, 4); Chris@0: Chris@0: case ID3_FIELD_TYPE_INT24: Chris@0: return id3_render_int(ptr, field->number.value, 3); Chris@0: Chris@0: case ID3_FIELD_TYPE_INT16: Chris@0: return id3_render_int(ptr, field->number.value, 2); Chris@0: Chris@0: case ID3_FIELD_TYPE_TEXTENCODING: Chris@0: *encoding = field->number.value; Chris@0: case ID3_FIELD_TYPE_INT8: Chris@0: return id3_render_int(ptr, field->number.value, 1); Chris@0: Chris@0: case ID3_FIELD_TYPE_LATIN1: Chris@0: case ID3_FIELD_TYPE_LATIN1FULL: Chris@0: return id3_render_latin1(ptr, field->latin1.ptr, terminate); Chris@0: Chris@0: case ID3_FIELD_TYPE_LATIN1LIST: Chris@0: size = 0; Chris@0: for (i = 0; i < field->latin1list.nstrings; ++i) { Chris@0: size += id3_render_latin1(ptr, field->latin1list.strings[i], Chris@0: (i < field->latin1list.nstrings - 1) || Chris@0: terminate); Chris@0: } Chris@0: return size; Chris@0: Chris@0: case ID3_FIELD_TYPE_STRING: Chris@0: case ID3_FIELD_TYPE_STRINGFULL: Chris@0: return id3_render_string(ptr, field->string.ptr, *encoding, terminate); Chris@0: Chris@0: case ID3_FIELD_TYPE_STRINGLIST: Chris@0: size = 0; Chris@0: for (i = 0; i < field->stringlist.nstrings; ++i) { Chris@0: size += id3_render_string(ptr, field->stringlist.strings[i], *encoding, Chris@0: (i < field->stringlist.nstrings - 1) || Chris@0: terminate); Chris@0: } Chris@0: return size; Chris@0: Chris@0: case ID3_FIELD_TYPE_LANGUAGE: Chris@0: return id3_render_immediate(ptr, field->immediate.value, 3); Chris@0: Chris@0: case ID3_FIELD_TYPE_FRAMEID: Chris@0: return id3_render_immediate(ptr, field->immediate.value, 4); Chris@0: Chris@0: case ID3_FIELD_TYPE_DATE: Chris@0: return id3_render_immediate(ptr, field->immediate.value, 8); Chris@0: Chris@0: case ID3_FIELD_TYPE_INT32PLUS: Chris@0: case ID3_FIELD_TYPE_BINARYDATA: Chris@0: return id3_render_binary(ptr, field->binary.data, field->binary.length); Chris@0: } Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->setint() Chris@0: * DESCRIPTION: set the value of an int field Chris@0: */ Chris@0: int id3_field_setint(union id3_field *field, signed long number) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: switch (field->type) { Chris@0: case ID3_FIELD_TYPE_INT8: Chris@0: if (number > 0x7f || number < -0x80) Chris@0: return -1; Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_INT16: Chris@0: if (number > 0x7fff || number < -0x8000) Chris@0: return -1; Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_INT24: Chris@0: if (number > 0x7fffffL || number < -0x800000L) Chris@0: return -1; Chris@0: break; Chris@0: Chris@0: case ID3_FIELD_TYPE_INT32: Chris@0: if (number > 0x7fffffffL || number < -0x80000000L) Chris@0: return -1; Chris@0: break; Chris@0: Chris@0: default: Chris@0: return -1; Chris@0: } Chris@0: Chris@0: id3_field_finish(field); Chris@0: Chris@0: field->number.value = number; Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->settextencoding() Chris@0: * DESCRIPTION: set the value of a textencoding field Chris@0: */ Chris@0: int id3_field_settextencoding(union id3_field *field, Chris@0: enum id3_field_textencoding encoding) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_TEXTENCODING) Chris@0: return -1; Chris@0: Chris@0: id3_field_finish(field); Chris@0: Chris@0: field->number.value = encoding; Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: static Chris@0: int set_latin1(union id3_field *field, id3_latin1_t const *latin1) Chris@0: { Chris@0: id3_latin1_t *data; Chris@0: Chris@0: if (latin1 == 0 || *latin1 == 0) Chris@0: data = 0; Chris@0: else { Chris@0: data = id3_latin1_duplicate(latin1); Chris@0: if (data == 0) Chris@0: return -1; Chris@0: } Chris@0: Chris@0: field->latin1.ptr = data; Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->setlatin1() Chris@0: * DESCRIPTION: set the value of a latin1 field Chris@0: */ Chris@0: int id3_field_setlatin1(union id3_field *field, id3_latin1_t const *latin1) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_LATIN1) Chris@0: return -1; Chris@0: Chris@0: id3_field_finish(field); Chris@0: Chris@0: if (latin1) { Chris@0: id3_latin1_t const *ptr; Chris@0: Chris@0: for (ptr = latin1; *ptr; ++ptr) { Chris@0: if (*ptr == '\n') Chris@0: return -1; Chris@0: } Chris@0: } Chris@0: Chris@0: return set_latin1(field, latin1); Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->setfulllatin1() Chris@0: * DESCRIPTION: set the value of a full latin1 field Chris@0: */ Chris@0: int id3_field_setfulllatin1(union id3_field *field, id3_latin1_t const *latin1) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_LATIN1FULL) Chris@0: return -1; Chris@0: Chris@0: id3_field_finish(field); Chris@0: Chris@0: return set_latin1(field, latin1); Chris@0: } Chris@0: Chris@0: static Chris@0: int set_string(union id3_field *field, id3_ucs4_t const *string) Chris@0: { Chris@0: id3_ucs4_t *data; Chris@0: Chris@0: if (string == 0 || *string == 0) Chris@0: data = 0; Chris@0: else { Chris@0: data = id3_ucs4_duplicate(string); Chris@0: if (data == 0) Chris@0: return -1; Chris@0: } Chris@0: Chris@0: field->string.ptr = data; Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->setstring() Chris@0: * DESCRIPTION: set the value of a string field Chris@0: */ Chris@0: int id3_field_setstring(union id3_field *field, id3_ucs4_t const *string) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_STRING) Chris@0: return -1; Chris@0: Chris@0: id3_field_finish(field); Chris@0: Chris@0: if (string) { Chris@0: id3_ucs4_t const *ptr; Chris@0: Chris@0: for (ptr = string; *ptr; ++ptr) { Chris@0: if (*ptr == '\n') Chris@0: return -1; Chris@0: } Chris@0: } Chris@0: Chris@0: return set_string(field, string); Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->setfullstring() Chris@0: * DESCRIPTION: set the value of a full string field Chris@0: */ Chris@0: int id3_field_setfullstring(union id3_field *field, id3_ucs4_t const *string) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_STRINGFULL) Chris@0: return -1; Chris@0: Chris@0: id3_field_finish(field); Chris@0: Chris@0: return set_string(field, string); Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->setstrings() Chris@0: * DESCRIPTION: set the value of a stringlist field Chris@0: */ Chris@0: int id3_field_setstrings(union id3_field *field, Chris@0: unsigned int length, id3_ucs4_t **ptrs) Chris@0: { Chris@0: id3_ucs4_t **strings; Chris@0: unsigned int i; Chris@0: Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_STRINGLIST) Chris@0: return -1; Chris@0: Chris@0: id3_field_finish(field); Chris@0: Chris@0: if (length == 0) Chris@0: return 0; Chris@0: Chris@0: strings = malloc(length * sizeof(*strings)); Chris@0: if (strings == 0) Chris@0: return -1; Chris@0: Chris@0: for (i = 0; i < length; ++i) { Chris@0: strings[i] = id3_ucs4_duplicate(ptrs[i]); Chris@0: if (strings[i] == 0) { Chris@0: while (i--) Chris@0: free(strings[i]); Chris@0: Chris@0: free(strings); Chris@0: return -1; Chris@0: } Chris@0: } Chris@0: Chris@0: field->stringlist.strings = strings; Chris@0: field->stringlist.nstrings = length; Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->addstring() Chris@0: * DESCRIPTION: add a string to a stringlist field Chris@0: */ Chris@0: int id3_field_addstring(union id3_field *field, id3_ucs4_t const *string) Chris@0: { Chris@0: id3_ucs4_t *new, **strings; Chris@0: Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_STRINGLIST) Chris@0: return -1; Chris@0: Chris@0: if (string == 0) Chris@0: string = id3_ucs4_empty; Chris@0: Chris@0: new = id3_ucs4_duplicate(string); Chris@0: if (new == 0) Chris@0: return -1; Chris@0: Chris@0: strings = realloc(field->stringlist.strings, Chris@0: (field->stringlist.nstrings + 1) * sizeof(*strings)); Chris@0: if (strings == 0) { Chris@0: free(new); Chris@0: return -1; Chris@0: } Chris@0: Chris@0: field->stringlist.strings = strings; Chris@0: field->stringlist.strings[field->stringlist.nstrings++] = new; Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->setlanguage() Chris@0: * DESCRIPTION: set the value of a language field Chris@0: */ Chris@0: int id3_field_setlanguage(union id3_field *field, char const *language) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_LANGUAGE) Chris@0: return -1; Chris@0: Chris@0: id3_field_finish(field); Chris@0: Chris@0: if (language) { Chris@0: if (strlen(language) != 3) Chris@0: return -1; Chris@0: Chris@0: strcpy(field->immediate.value, language); Chris@0: } Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->setframeid() Chris@0: * DESCRIPTION: set the value of a frameid field Chris@0: */ Chris@0: int id3_field_setframeid(union id3_field *field, char const *id) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_FRAMEID || Chris@0: !id3_frame_validid(id)) Chris@0: return -1; Chris@0: Chris@0: id3_field_finish(field); Chris@0: Chris@0: field->immediate.value[0] = id[0]; Chris@0: field->immediate.value[1] = id[1]; Chris@0: field->immediate.value[2] = id[2]; Chris@0: field->immediate.value[3] = id[3]; Chris@0: field->immediate.value[4] = 0; Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->setbinarydata() Chris@0: * DESCRIPTION: set the value of a binarydata field Chris@0: */ Chris@0: int id3_field_setbinarydata(union id3_field *field, Chris@0: id3_byte_t const *data, id3_length_t length) Chris@0: { Chris@0: id3_byte_t *mem; Chris@0: Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_BINARYDATA) Chris@0: return -1; Chris@0: Chris@0: id3_field_finish(field); Chris@0: Chris@0: if (length == 0) Chris@0: mem = 0; Chris@0: else { Chris@0: mem = malloc(length); Chris@0: if (mem == 0) Chris@0: return -1; Chris@0: Chris@0: assert(data); Chris@0: Chris@0: memcpy(mem, data, length); Chris@0: } Chris@0: Chris@0: field->binary.data = mem; Chris@0: field->binary.length = length; Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->getint() Chris@0: * DESCRIPTION: return the value of an integer field Chris@0: */ Chris@0: signed long id3_field_getint(union id3_field const *field) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_INT8 && Chris@0: field->type != ID3_FIELD_TYPE_INT16 && Chris@0: field->type != ID3_FIELD_TYPE_INT24 && Chris@0: field->type != ID3_FIELD_TYPE_INT32) Chris@0: return -1; Chris@0: Chris@0: return field->number.value; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->gettextencoding() Chris@0: * DESCRIPTION: return the value of a text encoding field Chris@0: */ Chris@0: enum id3_field_textencoding Chris@0: id3_field_gettextencoding(union id3_field const *field) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_TEXTENCODING) Chris@0: return -1; Chris@0: Chris@0: return field->number.value; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->getlatin1() Chris@0: * DESCRIPTION: return the value of a latin1 field Chris@0: */ Chris@0: id3_latin1_t const *id3_field_getlatin1(union id3_field const *field) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_LATIN1) Chris@0: return 0; Chris@0: Chris@0: return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) ""; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->getfulllatin1() Chris@0: * DESCRIPTION: return the value of a full latin1 field Chris@0: */ Chris@0: id3_latin1_t const *id3_field_getfulllatin1(union id3_field const *field) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_LATIN1FULL) Chris@0: return 0; Chris@0: Chris@0: return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) ""; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->getstring() Chris@0: * DESCRIPTION: return the value of a string field Chris@0: */ Chris@0: id3_ucs4_t const *id3_field_getstring(union id3_field const *field) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_STRING) Chris@0: return 0; Chris@0: Chris@0: return field->string.ptr ? field->string.ptr : id3_ucs4_empty; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->getfullstring() Chris@0: * DESCRIPTION: return the value of a fullstring field Chris@0: */ Chris@0: id3_ucs4_t const *id3_field_getfullstring(union id3_field const *field) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_STRINGFULL) Chris@0: return 0; Chris@0: Chris@0: return field->string.ptr ? field->string.ptr : id3_ucs4_empty; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->getnstrings() Chris@0: * DESCRIPTION: return the number of strings in a stringlist field Chris@0: */ Chris@0: unsigned int id3_field_getnstrings(union id3_field const *field) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_STRINGLIST) Chris@0: return 0; Chris@0: Chris@0: return field->stringlist.nstrings; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->getstrings() Chris@0: * DESCRIPTION: return one value of a stringlist field Chris@0: */ Chris@0: id3_ucs4_t const *id3_field_getstrings(union id3_field const *field, Chris@0: unsigned int index) Chris@0: { Chris@0: id3_ucs4_t const *string; Chris@0: Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_STRINGLIST || Chris@0: index >= field->stringlist.nstrings) Chris@0: return 0; Chris@0: Chris@0: string = field->stringlist.strings[index]; Chris@0: Chris@0: return string ? string : id3_ucs4_empty; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->getframeid() Chris@0: * DESCRIPTION: return the value of a frameid field Chris@0: */ Chris@0: char const *id3_field_getframeid(union id3_field const *field) Chris@0: { Chris@0: assert(field); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_FRAMEID) Chris@0: return 0; Chris@0: Chris@0: return field->immediate.value; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: field->getbinarydata() Chris@0: * DESCRIPTION: return the value of a binarydata field Chris@0: */ Chris@0: id3_byte_t const *id3_field_getbinarydata(union id3_field const *field, Chris@0: id3_length_t *length) Chris@0: { Chris@0: static id3_byte_t const empty; Chris@0: Chris@0: assert(field && length); Chris@0: Chris@0: if (field->type != ID3_FIELD_TYPE_BINARYDATA) Chris@0: return 0; Chris@0: Chris@0: assert(field->binary.length == 0 || field->binary.data); Chris@0: Chris@0: *length = field->binary.length; Chris@0: Chris@0: return field->binary.data ? field->binary.data : ∅ Chris@0: }