static int translate_TCON(struct id3_frame *frame, char const *oldid, id3_byte_t const *data, id3_length_t length) { id3_byte_t const *end; enum id3_field_textencoding encoding; id3_ucs4_t *string = 0, *ptr, *endptr; int result = 0; (void)oldid; /* translate old TCON syntax into multiple strings */ assert(frame->nfields == 2); encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1; end = data + length; if(id3_field_parse(&frame->fields[0], &data, end - data, &encoding) == -1) goto fail; string = id3_parse_string(&data, end - data, encoding, 0); if(string == 0) goto fail; ptr = string; while(*ptr == '(') { if(*++ptr == '(') break; endptr = ptr; while(*endptr && *endptr != ')') ++endptr; if(*endptr) *endptr++ = 0; if(id3_field_addstring(&frame->fields[1], ptr) == -1) goto fail; ptr = endptr; } if(*ptr && id3_field_addstring(&frame->fields[1], ptr) == -1) goto fail; if(0) { fail: result = -1; } if(string) free(string); return result; }
/* * NAME: field->parse() * DESCRIPTION: parse a field value */ int id3_field_parse(union id3_field *field, id3_byte_t const **ptr, id3_length_t length, enum id3_field_textencoding *encoding) { assert(field); id3_field_finish(field); switch (field->type) { case ID3_FIELD_TYPE_INT32: if (length < 4) goto fail; field->number.value = id3_parse_uint(ptr, 4); break; case ID3_FIELD_TYPE_INT24: if (length < 3) goto fail; field->number.value = id3_parse_uint(ptr, 3); break; case ID3_FIELD_TYPE_INT16: if (length < 2) goto fail; field->number.value = id3_parse_uint(ptr, 2); break; case ID3_FIELD_TYPE_INT8: case ID3_FIELD_TYPE_TEXTENCODING: if (length < 1) goto fail; field->number.value = id3_parse_uint(ptr, 1); if (field->type == ID3_FIELD_TYPE_TEXTENCODING) *encoding = field->number.value; break; case ID3_FIELD_TYPE_LANGUAGE: if (length < 3) goto fail; id3_parse_immediate(ptr, 3, field->immediate.value); break; case ID3_FIELD_TYPE_FRAMEID: if (length < 4) goto fail; id3_parse_immediate(ptr, 4, field->immediate.value); break; case ID3_FIELD_TYPE_DATE: if (length < 8) goto fail; id3_parse_immediate(ptr, 8, field->immediate.value); break; case ID3_FIELD_TYPE_LATIN1: case ID3_FIELD_TYPE_LATIN1FULL: { id3_latin1_t *latin1; latin1 = id3_parse_latin1(ptr, length, field->type == ID3_FIELD_TYPE_LATIN1FULL); if (latin1 == 0) goto fail; field->latin1.ptr = latin1; } break; case ID3_FIELD_TYPE_LATIN1LIST: { id3_byte_t const *end; id3_latin1_t *latin1, **strings; end = *ptr + length; while (end - *ptr > 0) { latin1 = id3_parse_latin1(ptr, end - *ptr, 0); if (latin1 == 0) goto fail; strings = realloc(field->latin1list.strings, (field->latin1list.nstrings + 1) * sizeof(*strings)); if (strings == 0) { free(latin1); goto fail; } field->latin1list.strings = strings; field->latin1list.strings[field->latin1list.nstrings++] = latin1; } } break; case ID3_FIELD_TYPE_STRING: case ID3_FIELD_TYPE_STRINGFULL: { id3_ucs4_t *ucs4; ucs4 = id3_parse_string(ptr, length, *encoding, field->type == ID3_FIELD_TYPE_STRINGFULL); if (ucs4 == 0) goto fail; field->string.ptr = ucs4; } break; case ID3_FIELD_TYPE_STRINGLIST: { id3_byte_t const *end; id3_ucs4_t *ucs4, **strings; end = *ptr + length; while (end - *ptr > 0) { ucs4 = id3_parse_string(ptr, end - *ptr, *encoding, 0); if (ucs4 == 0) goto fail; strings = realloc(field->stringlist.strings, (field->stringlist.nstrings + 1) * sizeof(*strings)); if (strings == 0) { free(ucs4); goto fail; } field->stringlist.strings = strings; field->stringlist.strings[field->stringlist.nstrings++] = ucs4; } } break; case ID3_FIELD_TYPE_INT32PLUS: case ID3_FIELD_TYPE_BINARYDATA: { id3_byte_t *data; data = id3_parse_binary(ptr, length); if (data == 0) goto fail; field->binary.data = data; field->binary.length = length; } break; } return 0; fail: return -1; }
/* * NAME: compat->fixup() * DESCRIPTION: finish compatibility translations */ int id3_compat_fixup(struct id3_tag *tag) { struct id3_frame *frame; unsigned int index; id3_ucs4_t timestamp[17] = { 0 }; int result = 0; /* create a TDRC frame from obsolete TYER/TDAT/TIME frames */ /* * TYE/TYER: YYYY * TDA/TDAT: DDMM * TIM/TIME: HHMM * * TDRC: yyyy-MM-ddTHH:mm */ index = 0; while((frame = id3_tag_findframe(tag, ID3_FRAME_OBSOLETE, index++))) { char const *id; id3_byte_t const *data, *end; id3_length_t length; enum id3_field_textencoding encoding; id3_ucs4_t *string; id = id3_field_getframeid(&frame->fields[0]); assert(id); if(strcmp(id, "TYER") != 0 && strcmp(id, "YTYE") != 0 && strcmp(id, "TDAT") != 0 && strcmp(id, "YTDA") != 0 && strcmp(id, "TIME") != 0 && strcmp(id, "YTIM") != 0) continue; data = id3_field_getbinarydata(&frame->fields[1], &length); assert(data); if(length < 1) continue; end = data + length; encoding = (enum id3_field_textencoding)id3_parse_uint(&data, 1); string = id3_parse_string(&data, end - data, encoding, 0); if(id3_ucs4_length(string) < 4) { free(string); continue; } if(strcmp(id, "TYER") == 0 || strcmp(id, "YTYE") == 0) { timestamp[0] = string[0]; timestamp[1] = string[1]; timestamp[2] = string[2]; timestamp[3] = string[3]; } else if(strcmp(id, "TDAT") == 0 || strcmp(id, "YTDA") == 0) { timestamp[4] = '-'; timestamp[5] = string[2]; timestamp[6] = string[3]; timestamp[7] = '-'; timestamp[8] = string[0]; timestamp[9] = string[1]; } else /* TIME or YTIM */ { timestamp[10] = 'T'; timestamp[11] = string[0]; timestamp[12] = string[1]; timestamp[13] = ':'; timestamp[14] = string[2]; timestamp[15] = string[3]; } free(string); } if(timestamp[0]) { id3_ucs4_t *strings; frame = id3_frame_new("TDRC"); if(frame == 0) goto fail; strings = timestamp; if(id3_field_settextencoding(&frame->fields[0], ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1 || id3_field_setstrings(&frame->fields[1], 1, &strings) == -1 || id3_tag_attachframe(tag, frame) == -1) { id3_frame_delete(frame); goto fail; } } if(0) { fail: result = -1; } return result; }