1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
#include "charset.h"
#include <errno.h>
#include <iconv.h>
#include <langinfo.h>
#include <locale.h>
#include <stdlib.h>
#include <id3/misc_support.h>
#include <id3/utils.h>
char *GetID3EncText (const ID3_Frame *frame, ID3_FieldID fldName)
{
return GetID3EncText (frame, fldName, (size_t) -1);
}
char *GetID3EncText (const ID3_Frame *frame, ID3_FieldID fldName, size_t idx)
{
ID3_Field *fld = frame->GetField (fldName);
ID3_TextEnc enc = fld->GetEncoding();
size_t len = fld->Size(), inl;
char *enc_text;
const char *iconv_enc;
if (ID3TE_IS_DOUBLE_BYTE_ENC (enc)) {
enc_text = new char [(len + 1) * sizeof (unicode_t)];
if (idx == (size_t) -1)
len = fld->Get ((unicode_t *) enc_text, len);
else
len = fld->Get ((unicode_t *) enc_text, len, idx);
iconv_enc = "UTF-16BE";
// Seems that fld->Size() returns number of bytes afterall,
// contrary to docs. Can't find any way to avoid it, so we have to
// count on that it remains bug compatible. :(
len >>= 1;
inl = len * sizeof (unicode_t);
}
else {
enc_text = new char [len + 1];
if (idx == (size_t) -1)
len = fld->Get (enc_text, len);
else
len = fld->Get (enc_text, len, idx);
iconv_enc = "ISO-8859-1";
inl = len;
}
iconv_t cd = iconv_open (nl_langinfo (CODESET), iconv_enc);
if (cd != (iconv_t) -1) {
size_t outl = (len + 1) * MB_CUR_MAX;
char *mbs_text = new char [outl];
char *inp = enc_text, *outp = mbs_text;
while (1) {
if (iconv (cd, &inp, &inl, &outp, &outl) != (size_t) -1) {
*outp++ = 0;
if (outl > len) {
char *realloced = new char [outp - mbs_text];
memcpy ((void *) realloced, (void *) mbs_text, outp - mbs_text);
delete[] mbs_text;
mbs_text = realloced;
}
iconv_close (cd);
delete[] enc_text;
return mbs_text;
}
if (errno == EILSEQ) {
inp++;
if (ID3TE_IS_DOUBLE_BYTE_ENC (enc)) inp++;
inl--;
*outp++ = '?';
outl--;
}
else break;
}
iconv_close (cd);
}
delete[] enc_text;
// Lame fallback but no worse than earlier versions.
return ID3_GetString (frame, fldName);
}
void SetID3EncText (ID3_Frame *frame, ID3_FieldID fldName, char *text)
{
// Try iso-8859-1 first.
iconv_t cd = iconv_open ("ISO-8859-1", nl_langinfo (CODESET));
if (cd != (iconv_t) -1) {
size_t inl = strlen (text);
size_t latin1_len = inl + 1;
char *latin1_text = new char [latin1_len];
char *inp = text, *outp = latin1_text;
if (iconv (cd, &inp, &inl, &outp, &latin1_len) != (size_t) -1) {
*outp = 0;
frame->Field (ID3FN_TEXTENC) = ID3TE_ASCII;
frame->Field (fldName) = latin1_text;
delete[] latin1_text;
iconv_close (cd);
return;
}
delete[] latin1_text;
iconv_close (cd);
}
// Then utf-16.
cd = iconv_open ("UTF-16BE", nl_langinfo (CODESET));
if (cd != (iconv_t) -1) {
size_t inl = strlen (text);
size_t utf16_len = inl + 1;
unicode_t *utf16_text = new unicode_t [utf16_len];
char *inp = text, *outp = (char *) utf16_text;
utf16_len *= sizeof (unicode_t);
if (iconv (cd, &inp, &inl, &outp, &utf16_len) != (size_t) -1) {
*outp = 0;
*(outp + 1) = 0;
frame->Field (ID3FN_TEXTENC) = ID3TE_UTF16;
frame->Field (fldName).SetEncoding (ID3TE_UTF16);
frame->Field (fldName) = utf16_text;
delete[] utf16_text;
iconv_close (cd);
return;
}
delete[] utf16_text;
iconv_close (cd);
}
// Lame fallback but no worse than earlier versions.
frame->Field (ID3FN_TEXTENC) = ID3TE_ASCII;
frame->Field (ID3FN_TEXT) = text;
}
|