Re: Handling ID3 tags with non-latin1 encoding

Rob Leslie <[email protected]> Tue, 6 Jun 2006 18:38:04 -0700
Newsgroups gmane.comp.audio.mad.devel
Message-ID <[email protected]>
On Jun 6, 2006, at 4:46 PM, Kurt Roeckx wrote:
> On Mon, Jun 05, 2006 at 09:06:00AM +0000, Stefan Huelswitt wrote:
>> I have a question regarding handling of ID3 tags which are non- 
>> latin1 encoded e.g. iso-8859-5.
>>
>> I think I can get ucs4 strings from libid3tag and convert them  
>> with iconv to whatever codeset originaly was used.
>
> What you really should do is convert things to wchar_t, and then  
> use functions that work with them (like wprintf()) to output  
> things.  This should be much more portable.
>
> I find it unfortute libid3tag does everything with ucs4 instead of  
> wchar_t's.

Unfortunately wchar_t is not a very portable way of supporting  
Unicode. Its size is compiler-dependent, and may not be large enough  
to represent all of the ISO/IEC 10646 code points. For example, ISO/ 
IEC 9899:1999 (C99) allows wchar_t to be as small as 8 bits; even 16  
bits is not large enough. The type is also locale-dependent.

> I'm not sure what's the best way to convert it from ucs4 to wchar_t  
> though, and can't think of a portable way, and I'd love if someone  
> could point me out how to do it.
>
> (On Linux (glibc), casting it from a id3_ucs4_t to a wchar_t seems  
> to work, but it's not portable.)

There's nothing wrong with this per se as long as wchar_t is at least  
21 bits wide (for example, when __STDC_ISO_10646__ is defined) or you  
are sure the UCS-4 code point in question can otherwise be  
represented by a wchar_t -- and the relevant locale is compatible.  
Note that casting id3_ucs4_t to wchar_t is not the same as casting  
(id3_ucs4_t *) to (wchar_t *); the latter is definitely not portable  
though it may work if the underlying types happen to have the same size.

A simple way to translate a UCS-4 string to wchar_t might be (untested):

wchar_t *ucs4_to_wchar(id3_ucs4_t const *ucs4)
{
   wchar_t *wchar;

   wchar = malloc(id3_ucs4_size(ucs4) * sizeof(wchar_t));
   if (wchar) {
     wchar_t *ptr = wchar;
     while ((*ptr++ = (wchar_t) *ucs4++))
       ;
   }

   return wchar;
}

This assumes __STDC_ISO_10646__ is defined, or wchar_t is otherwise  
compatible with ISO/IEC 10646 character codes.

-- 
Rob Leslie
[email protected]