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