On Tuesday, October 1, 2002, at 01:45 PM, Mark Malson wrote:
I wrote this function (in Objective-C) to update the contents of a tag for writing out later. Am I on the right track? Do I need to update both the UTF8 and the latin strings?
bool libid3tag_SetString (struct id3_tag const *tag, char const *id, NSString *newStr) { bool retVal = NO; struct id3_frame const *frame; id3_latin1_t *latin1; id3_utf8_t *utf8;
/* text information */
union id3_field const *field; unsigned int nstrings, j; extern id3_ucs4_t *id3_utf8_deserialize(id3_byte_t const **ptr,
id3_length_t length);
if ((frame = id3_tag_findframe(tag, id, 0)) == nil) return NO; field = &frame->fields[1]; nstrings = id3_field_getnstrings(field); for (j = 0; j < nstrings; ++j) { id3_byte_t *ptr; id3_ucs4_t *ucs4; switch (field->type) { case ID3_FIELD_TYPE_STRINGLIST: ptr = [ newStr UTF8String ]; ucs4 = id3_utf8_deserialize (&ptr, [ newStr length ]); id3_field_setstrings (field, 1, &ucs4); free (ucs4); break; case ID3_FIELD_TYPE_LATIN1LIST: ptr = [ newStr cString ]; ucs4 = id3_latin1_deserialize (&ptr, [ newStr length
]);
id3_field_setstrings (field, 1, &ucs4); free (ucs4); break; } } return YES;
}
Be careful which types of frames you are willing to modify. Different frames have different field structures, so you probably want to restrict yourself to text and comment frames (Txxx and COMM). Text frames have an ID3_FIELD_TYPE_STRINGLIST as their second field, while comment frames have three fields needing population, an ID3_FIELD_TYPE_LANGUAGE, an ID3_FIELD_TYPE_STRING "short content description," and an ID3_FIELD_TYPE_STRINGFULL with the actual comment text.
The only frame type that uses a field of type ID3_FIELD_TYPE_LATIN1LIST is "LINK", so you probably will not need to bother setting such fields.
For the common case of text frames and ID3_FIELD_TYPE_STRINGLIST fields, your code is close but not perfect. Since you can get the number of Unicode characters directly from NSString, I would do something like this instead:
id3_utf8_t const *utf8; id3_ucs4_t *ucs4;
utf8 = [newStr UTF8String]; ucs4 = malloc(([newStr length] + 1) * sizeof(*ucs4)); if (ucs4) { id3_utf8_decode(utf8, ucs4); id3_field_setstrings(field, 1, &ucs4); free(ucs4); }
The id3_utf8_deserialize() routine is more low-level and expects the number of encoded bytes as argument, not the number of decoded UCS-4 characters.