Package: libid3-3.8.3
Version: 3.8.3-4.2
Severity: important
Tags: patch l10n


The attached patch fixes a few issues with id3lib.
It works for me, but is untested on bigendian machines.
Issues fixed:

1)
I tried my best to fix the unicode borkage

2)
The reader/writer was doing unconditional byte swapping for
unicode strings.  Since iconv already does that I removed those parts.

3)
The reader/writer always prepended a Byte Order Mark for unicode
strings, which it only should do for type 1 (UTF16) and never do for
type 2 (UTF16BE) or type 3 (UTF8), so I changed the defaults to
disabled, since iconv already takes care of the BOM for UTF16.

4)
If a program like id3v2 is used in a locale _not using the iso-8859-1
charset_ (e.g. en_US.UTF-8 or ja_JP) libid3 would put invalid encoding
into a iso-8859-1 field.  The patch changes the default to 'native'
(locale) encoding and unconvertible characters will be converted to
question marks, for both reading and writing.  With minimal changes
a program like id3v2 can be converted to support writing proper unicode
tags (see http://bugs.debian.org/232307).

Test files in different encodings are available at
http://ranmachan.dyndns.org/~ranma/mp3test/

-- System Information:
Debian Release: testing/unstable
  APT prefers unstable
  APT policy: (990, 'unstable'), (500, 'hoary')
Architecture: i386 (i686)
Shell:  /bin/sh linked to /bin/bash
Kernel: Linux 2.6.11.12-ac7-vs1.9.5-htbatm-imq
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)

Versions of packages libid3-3.8.3 depends on:
ii  libc6                       2.3.2.ds1-22 GNU C Library: Shared libraries an
ii  libgcc1                     1:4.0.0-9    GCC support library
ii  libstdc++5                  1:3.3.6-6    The GNU Standard C++ Library v3
ii  zlib1g                      1:1.2.2-4    compression library - runtime

libid3-3.8.3 recommends no packages.

-- no debconf information
diff -Naru -x Makefile.in -x Makefile -x libtool -x control -x config.h -x configure -x config.log -x config.status id3lib3.8.3-3.8.3/include/id3/globals.h id3lib3.8.3-3.8.3.patched/include/id3/globals.h
--- id3lib3.8.3-3.8.3/include/id3/globals.h	2003-03-02 01:23:00.000000000 +0100
+++ id3lib3.8.3-3.8.3.patched/include/id3/globals.h	2005-07-08 23:36:05.000000000 +0200
@@ -141,12 +141,13 @@
   ID3TE_UTF16,
   ID3TE_UTF16BE,
   ID3TE_UTF8,
+  ID3TE_NATIVE,
   ID3TE_NUMENCODINGS,
   ID3TE_ASCII = ID3TE_ISO8859_1, // do not use this -> use ID3TE_IS_SINGLE_BYTE_ENC(enc) instead
   ID3TE_UNICODE = ID3TE_UTF16    // do not use this -> use ID3TE_IS_DOUBLE_BYTE_ENC(enc) instead
 };
 
-#define ID3TE_IS_SINGLE_BYTE_ENC(enc)    ((enc) == ID3TE_ISO8859_1 || (enc) == ID3TE_UTF8)
+#define ID3TE_IS_SINGLE_BYTE_ENC(enc)    ((enc) == ID3TE_ISO8859_1 || (enc) == ID3TE_UTF8 || (enc) == ID3TE_NATIVE)
 #define ID3TE_IS_DOUBLE_BYTE_ENC(enc)    ((enc) == ID3TE_UTF16 || (enc) == ID3TE_UTF16BE)
 
 /** Enumeration of the various id3 specifications
diff -Naru -x Makefile.in -x Makefile -x libtool -x control -x config.h -x configure -x config.log -x config.status id3lib3.8.3-3.8.3/include/id3/io_helpers.h id3lib3.8.3-3.8.3.patched/include/id3/io_helpers.h
--- id3lib3.8.3-3.8.3/include/id3/io_helpers.h	2003-03-02 01:23:00.000000000 +0100
+++ id3lib3.8.3-3.8.3.patched/include/id3/io_helpers.h	2005-07-07 21:19:49.000000000 +0200
@@ -70,8 +70,8 @@
 
     ID3_C_EXPORT size_t      writeString(ID3_Writer&, String);
     ID3_C_EXPORT size_t      writeText(ID3_Writer&, String);
-    ID3_C_EXPORT size_t      writeUnicodeString(ID3_Writer&, String, bool = true);
-    ID3_C_EXPORT size_t      writeUnicodeText(ID3_Writer&, String, bool = true);
+    ID3_C_EXPORT size_t      writeUnicodeString(ID3_Writer&, String, bool = false);
+    ID3_C_EXPORT size_t      writeUnicodeText(ID3_Writer&, String, bool = false);
     ID3_C_EXPORT size_t      writeBENumber(ID3_Writer&, uint32 val, size_t);
     ID3_C_EXPORT size_t      writeTrailingSpaces(ID3_Writer&, String, size_t);
     ID3_C_EXPORT size_t      writeUInt28(ID3_Writer&, uint32);
diff -Naru -x Makefile.in -x Makefile -x libtool -x control -x config.h -x configure -x config.log -x config.status id3lib3.8.3-3.8.3/src/field.cpp id3lib3.8.3-3.8.3.patched/src/field.cpp
--- id3lib3.8.3-3.8.3/src/field.cpp	2003-03-02 01:23:00.000000000 +0100
+++ id3lib3.8.3-3.8.3.patched/src/field.cpp	2005-07-09 00:01:13.000000000 +0200
@@ -906,7 +906,7 @@
     _changed(false),
     _fixed_size(def._fixed_size),
     _num_items(0),
-    _enc((_type == ID3FTY_TEXTSTRING) ? ID3TE_ASCII : ID3TE_NONE)
+    _enc((_type == ID3FTY_TEXTSTRING) ? ID3TE_NATIVE : ID3TE_NONE)
 {
   this->Clear();
 }
@@ -943,11 +943,11 @@
       _text.erase();
       if (_fixed_size > 0)
       {
-        if (this->GetEncoding() == ID3TE_UNICODE)
+        if (ID3TE_IS_DOUBLE_BYTE_ENC(this->GetEncoding()))
         {
           _text.assign(_fixed_size * 2, '\0');
         }
-        else if (this->GetEncoding() == ID3TE_ASCII)
+        else if (ID3TE_IS_SINGLE_BYTE_ENC(this->GetEncoding()))
         {
           _text.assign(_fixed_size, '\0');
         }
diff -Naru -x Makefile.in -x Makefile -x libtool -x control -x config.h -x configure -x config.log -x config.status id3lib3.8.3-3.8.3/src/field_string_ascii.cpp id3lib3.8.3-3.8.3.patched/src/field_string_ascii.cpp
--- id3lib3.8.3-3.8.3/src/field_string_ascii.cpp	2003-03-02 01:23:00.000000000 +0100
+++ id3lib3.8.3-3.8.3.patched/src/field_string_ascii.cpp	2005-07-09 00:41:13.000000000 +0200
@@ -48,6 +48,7 @@
   if ((this->GetType() == ID3FTY_TEXTSTRING) && data)
   {
     String str(data);
+    this->SetEncoding(ID3TE_NATIVE);
     len = this->SetText_i(str);
   }
   return len;
@@ -86,38 +87,45 @@
  **/
 size_t ID3_FieldImpl::Get(char* buffer, size_t maxLength) const
 {
+  ID3_TextEnc enc = this->GetEncoding();
   size_t size = 0;
-  if (this->GetType() == ID3FTY_TEXTSTRING &&
-      this->GetEncoding() == ID3TE_ASCII &&
-      buffer != NULL && maxLength > 0)
+  if (this->GetType() != ID3FTY_TEXTSTRING ||
+      buffer == NULL || maxLength <= 0)
   {
-    String data = this->GetText();
-    size = dami::min(maxLength, data.size());
-    ::memcpy(buffer, data.data(), size);
-    if (size < maxLength)
-    {
-      buffer[size] = '\0';
-    }
+    return 0;
   }
+  String data = dami::convert(this->GetText(), enc, ID3TE_NATIVE);
+  /*
+   * maxLenght-1 is used to leave room for the terminating \0.
+   * Safe by default is good.
+   * http://www.courtesan.com/todd/papers/strlcpy.html
+   */
+  size = dami::min(maxLength-1, data.size());
+  data.copy(buffer, size);
+  buffer[size] = '\0';
 
   return size;
 }
 
 size_t ID3_FieldImpl::Get(char* buf, size_t maxLen, size_t index) const
 {
+  ID3_TextEnc enc = this->GetEncoding();
   size_t size = 0;
-  if (this->GetType() == ID3FTY_TEXTSTRING &&
-      this->GetEncoding() == ID3TE_ASCII &&
-      buf != NULL && maxLen > 0)
+  if (this->GetType() != ID3FTY_TEXTSTRING ||
+      buf == NULL || maxLen <= 0)
   {
-    String data = this->GetTextItem(index);
-    size = dami::min(maxLen, data.size());
-    ::memcpy(buf, data.data(), size);
-    if (size < maxLen)
-    {
-      buf[size] = '\0';
-    }
+    return 0;
   }
+  String data = dami::convert(this->GetTextItem(index), enc, ID3TE_NATIVE);
+  /*
+   * maxLen-1 is used to leave room for the terminating \0.
+   * Safe by default is good.
+   * http://www.courtesan.com/todd/papers/strlcpy.html
+   */
+  size = dami::min(maxLen-1, data.size());
+  data.copy(buf, size);
+  buf[size] = '\0';
+
   return size;
 }
 
@@ -135,7 +143,7 @@
 {
   String data;
   if (this->GetType() == ID3FTY_TEXTSTRING &&
-      this->GetEncoding() == ID3TE_ASCII)
+      ID3TE_IS_SINGLE_BYTE_ENC(this->GetEncoding()))
   {
     const char* raw = this->GetRawTextItem(index);
     if (raw != NULL)
@@ -225,7 +233,7 @@
 
     // ASSERT(_fixed_size == 0)
     _text += '\0';
-    if (this->GetEncoding() == ID3TE_UNICODE)
+    if (ID3TE_IS_DOUBLE_BYTE_ENC(this->GetEncoding()))
     {
       _text += '\0';
     }
@@ -261,8 +269,7 @@
 const char* ID3_FieldImpl::GetRawText() const
 {
   const char* text = NULL;
-  if (this->GetType() == ID3FTY_TEXTSTRING &&
-      this->GetEncoding() == ID3TE_ASCII)
+  if (this->GetType() == ID3FTY_TEXTSTRING)
   {
     text = _text.c_str();
   }
@@ -271,16 +278,21 @@
 
 const char* ID3_FieldImpl::GetRawTextItem(size_t index) const
 {
+  ID3_TextEnc enc = this->GetEncoding();
   const char* text = NULL;
-  if (this->GetType() == ID3FTY_TEXTSTRING &&
-      this->GetEncoding() == ID3TE_ASCII &&
-      index < this->GetNumTextItems())
+  if (this->GetType() != ID3FTY_TEXTSTRING ||
+      index >= this->GetNumTextItems())
   {
-    text = _text.c_str();
-    for (size_t i = 0; i < index; ++i)
-    {
-      text += strlen(text) + 1;
-    }
+    return NULL;
+  }
+  if (ID3TE_IS_DOUBLE_BYTE_ENC(enc))
+  {
+    return (char *) this->GetRawUnicodeTextItem(index);
+  }
+  text = _text.c_str();
+  for (size_t i = 0; i < index; ++i)
+  {
+    text += strlen(text) + 1;
   }
   return text;
 }
@@ -289,7 +301,7 @@
 {
   String readEncodedText(ID3_Reader& reader, size_t len, ID3_TextEnc enc)
   {
-    if (enc == ID3TE_ASCII)
+    if (ID3TE_IS_SINGLE_BYTE_ENC(enc))
     {
       return io::readText(reader, len);
     }
@@ -298,7 +310,7 @@
 
   String readEncodedString(ID3_Reader& reader, ID3_TextEnc enc)
   {
-    if (enc == ID3TE_ASCII)
+    if (ID3TE_IS_SINGLE_BYTE_ENC(enc))
     {
       return io::readString(reader);
     }
@@ -307,20 +319,20 @@
 
   size_t writeEncodedText(ID3_Writer& writer, String data, ID3_TextEnc enc)
   {
-    if (enc == ID3TE_ASCII)
+    if (ID3TE_IS_SINGLE_BYTE_ENC(enc))
     {
       return io::writeText(writer, data);
     }
-    return io::writeUnicodeText(writer, data);
+    return io::writeUnicodeText(writer, data, false);
   }
 
   size_t writeEncodedString(ID3_Writer& writer, String data, ID3_TextEnc enc)
   {
-    if (enc == ID3TE_ASCII)
+    if (ID3TE_IS_SINGLE_BYTE_ENC(enc))
     {
       return io::writeString(writer, data);
     }
-    return io::writeUnicodeString(writer, data);
+    return io::writeUnicodeString(writer, data, false);
   }
 }
 
diff -Naru -x Makefile.in -x Makefile -x libtool -x control -x config.h -x configure -x config.log -x config.status id3lib3.8.3-3.8.3/src/field_string_unicode.cpp id3lib3.8.3-3.8.3.patched/src/field_string_unicode.cpp
--- id3lib3.8.3-3.8.3/src/field_string_unicode.cpp	2003-03-02 01:23:00.000000000 +0100
+++ id3lib3.8.3-3.8.3.patched/src/field_string_unicode.cpp	2005-07-09 00:00:08.000000000 +0200
@@ -49,10 +49,10 @@
 size_t ID3_FieldImpl::Set(const unicode_t* data)
 {
   size_t size = 0;
-  if (this->GetType() == ID3FTY_TEXTSTRING &&
-      this->GetEncoding() == ID3TE_UNICODE && data)
+  if (this->GetType() == ID3FTY_TEXTSTRING && data)
   {
     String text((const char*) data, ucslen(data) * 2);
+    this->SetEncoding(ID3TE_UTF16);
     size = this->SetText_i(text);
   }
   return size;
@@ -62,7 +62,7 @@
 {
   size_t size = 0;
   if (this->GetType() == ID3FTY_TEXTSTRING &&
-      this->GetEncoding() == ID3TE_UNICODE)
+      ID3TE_IS_DOUBLE_BYTE_ENC(this->GetEncoding()))
   {
     String text((const char*) data, ucslen(data) * 2);
     size = this->AddText_i(text);
@@ -93,26 +93,27 @@
 size_t ID3_FieldImpl::Get(unicode_t *buffer, size_t maxLength) const
 {
   size_t length = 0;
-  if (this->GetType() == ID3FTY_TEXTSTRING &&
-      this->GetEncoding() == ID3TE_UNICODE &&
-      buffer != NULL && maxLength > 0)
+  if (this->GetType() != ID3FTY_TEXTSTRING ||
+      buffer == NULL || maxLength <= 0)
   {
-    size_t size = this->Size();
-    length = dami::min(maxLength, size);
-    ::memcpy((void *)buffer, (void *)_text.data(), length * 2);
-    if (length < maxLength)
-    {
-      buffer[length] = NULL_UNICODE;
-    }
+    return 0;
   }
+  String utf = dami::convert(_text, this->GetEncoding(), ID3TE_UTF16);
+  /*
+   * maxLenght-1 is used to leave room for the terminating \0.
+   * Safe by default is good.
+   * http://www.courtesan.com/todd/papers/strlcpy.html
+   */
+  length = dami::min(maxLength-1, utf.size()/2);
+  utf.copy((char*)buffer, length * 2);
+  buffer[length] = NULL_UNICODE;
   return length;
 }
 
 const unicode_t* ID3_FieldImpl::GetRawUnicodeText() const
 {
   const unicode_t* text = NULL;
-  if (this->GetType() == ID3FTY_TEXTSTRING &&
-      this->GetEncoding() == ID3TE_UNICODE)
+  if (this->GetType() == ID3FTY_TEXTSTRING)
   {
     text = (unicode_t *)_text.data();
   }
@@ -123,7 +124,7 @@
 {
   const unicode_t* text = NULL;
   if (this->GetType() == ID3FTY_TEXTSTRING &&
-      this->GetEncoding() == ID3TE_UNICODE &&
+      ID3TE_IS_DOUBLE_BYTE_ENC(this->GetEncoding()) &&
       index < this->GetNumTextItems())
   {
     String unicode = _text + '\0' + '\0';
@@ -140,23 +141,28 @@
 {
   size_t length = 0;
   size_t total_items = this->GetNumTextItems();
-  if (this->GetType() == ID3FTY_TEXTSTRING &&
-      this->GetEncoding() == ID3TE_UNICODE &&
-      buffer != NULL && maxLength > 0 && itemNum < total_items)
+  if (this->GetType() != ID3FTY_TEXTSTRING ||
+      buffer == NULL || maxLength <= 0 || itemNum >= total_items)
   {
-    const unicode_t* text = this->GetRawUnicodeTextItem(itemNum);
-    if (NULL != text)
-    {
-      size_t length = dami::min(maxLength, ucslen(text));
-      ::memcpy(buffer, text, length * 2);
-      if (length < maxLength)
-      {
-        buffer[length] = NULL_UNICODE;
-      }
-    }
+    return 0;
   }
 
+  const unicode_t *raw = this->GetRawUnicodeTextItem(itemNum);
+  if (raw == NULL)
+  {
+    return 0;
+  }
+  String s;
+  s.append((char*) raw, ucslen(raw)*2);
+  String data = dami::convert(s, this->GetEncoding(), ID3TE_UTF16);
+  /*
+   * maxLenght-1 is used to leave room for the terminating \0.
+   * Safe by default is good.
+   * http://www.courtesan.com/todd/papers/strlcpy.html
+   */
+  length = dami::min(maxLength-1, data.size()/2);
+  data.copy((char*)buffer, length * 2);
+  buffer[length] = NULL_UNICODE;
+
   return length;
 }
-
-
diff -Naru -x Makefile.in -x Makefile -x libtool -x control -x config.h -x configure -x config.log -x config.status id3lib3.8.3-3.8.3/src/helpers.cpp id3lib3.8.3-3.8.3.patched/src/helpers.cpp
--- id3lib3.8.3-3.8.3/src/helpers.cpp	2003-03-02 01:23:00.000000000 +0100
+++ id3lib3.8.3-3.8.3.patched/src/helpers.cpp	2005-07-09 00:23:16.000000000 +0200
@@ -51,13 +51,19 @@
   {
     return "";
   }
-  ID3_TextEnc enc = fp->GetEncoding();
-  fp->SetEncoding(ID3TE_ASCII);
+  
+  const char *rawtext = fp->GetRawText();
+  if (rawtext == NULL)
+  {
+    return "";
+  }
+  String raw;
+  raw.append(rawtext, fp->Size());
+  raw.append("\0\0", 2); /* make sure we have enough terminating zeroes */
 
-  String text(fp->GetRawText(), fp->Size());
+  String res = convert(raw, fp->GetEncoding(), ID3TE_NATIVE);
 
-  fp->SetEncoding(enc);
-  return text;
+  return res;
 }
 
 String id3::v2::getStringAtIndex(const ID3_Frame* frame, ID3_FieldID fldName,
@@ -69,16 +75,32 @@
   }
   String text;
   ID3_Field* fp = frame->GetField(fldName);
-  if (fp && fp->GetNumTextItems() < nIndex)
+  if (fp && fp->GetNumTextItems() >= nIndex)
+  {
+    return "";
+  }
+  const char *rawtext = fp->GetRawTextItem(nIndex);
+  if (rawtext == NULL)
+  {
+    return "";
+  }
+  size_t rawlen = 0;
+  ID3_TextEnc enc = fp->GetEncoding();
+  if (ID3TE_IS_DOUBLE_BYTE_ENC(enc))
+  {
+    rawlen = ucslen((unicode_t *)rawtext)*2;
+  }
+  else
   {
-    ID3_TextEnc enc = fp->GetEncoding();
-    fp->SetEncoding(ID3TE_ASCII);
+    rawlen = strlen(rawtext);
+  }
+  String raw;
+  raw.append(rawtext, rawlen);
+  raw.append("\0\0", 2); /* make sure we have enough terminating zeroes */
 
-    text = fp->GetRawTextItem(nIndex);
+  String res = convert(raw, enc, ID3TE_NATIVE);
 
-    fp->SetEncoding(enc);
-  }
-  return text;
+  return res;
 }
 
 size_t id3::v2::removeFrames(ID3_TagImpl& tag, ID3_FrameID id)
diff -Naru -x Makefile.in -x Makefile -x libtool -x control -x config.h -x configure -x config.log -x config.status id3lib3.8.3-3.8.3/src/io_helpers.cpp id3lib3.8.3-3.8.3.patched/src/io_helpers.cpp
--- id3lib3.8.3-3.8.3/src/io_helpers.cpp	2003-03-02 01:23:00.000000000 +0100
+++ id3lib3.8.3-3.8.3.patched/src/io_helpers.cpp	2005-07-09 00:44:21.000000000 +0200
@@ -142,16 +142,8 @@
     {
       break;
     }
-    if (bom == -1)
-    {
-      unicode += static_cast<char>(ch2);
-      unicode += static_cast<char>(ch1);
-    }
-    else
-    {
-      unicode += static_cast<char>(ch1);
-      unicode += static_cast<char>(ch2);
-    }
+    unicode += static_cast<char>(ch1);
+    unicode += static_cast<char>(ch2);
   }
   return unicode;
 }
@@ -170,24 +162,8 @@
   {
     unicode += ch1;
     unicode += ch2;
-    unicode += readText(reader, len);
-  }
-  else if (bom == 1)
-  {
-    unicode = readText(reader, len);
-  }
-  else
-  {
-    for (size_t i = 0; i < len; i += 2)
-    {
-      if (!readTwoChars(reader, ch1, ch2))
-      {
-        break;
-      }
-      unicode += ch2;
-      unicode += ch1;
-    }
   }
+  unicode += readText(reader, len);
   return unicode;
 }
 
@@ -363,12 +339,8 @@
     // Write the BOM: 0xFEFF
     unicode_t BOM = 0xFEFF;
     writer.writeChars((const unsigned char*) &BOM, 2);
-    for (size_t i = 0; i < size; i += 2)
-    {
-      unicode_t ch = (data[i] << 8) | data[i+1];
-      writer.writeChars((const unsigned char*) &ch, 2);
-    }
   }
+  writer.writeChars(&data[0], size);
   return writer.getCur() - beg;
 }
 
diff -Naru -x Makefile.in -x Makefile -x libtool -x control -x config.h -x configure -x config.log -x config.status id3lib3.8.3-3.8.3/src/misc_support.cpp id3lib3.8.3-3.8.3.patched/src/misc_support.cpp
--- id3lib3.8.3-3.8.3/src/misc_support.cpp	2005-07-08 00:52:31.000000000 +0200
+++ id3lib3.8.3-3.8.3.patched/src/misc_support.cpp	2005-07-09 00:15:52.000000000 +0200
@@ -31,8 +31,9 @@
 #include "misc_support.h"
 //#include "field.h"
 #include "id3/utils.h" // has <config.h> "id3/id3lib_streams.h" "id3/globals.h" "id3/id3lib_strings.h"
+#include "id3/helpers.h"
 
-//using namespace dami;
+using namespace dami;
 
 char *ID3_GetString(const ID3_Frame *frame, ID3_FieldID fldName)
 {
@@ -41,13 +42,10 @@
   ID3_Field* fld;
   if (NULL != frame && NULL != (fld = frame->GetField(fldName)))
   {
-//    ID3_Field* fld = frame->GetField(fldName);
-    ID3_TextEnc enc = fld->GetEncoding();
-    fld->SetEncoding(ID3TE_ISO8869_1);
-    size_t nText = fld->Size();
+    String str = id3::v2::getString(frame, fldName);
+    size_t nText = str.size();
     text = new char[nText + 1];
-    fld->Get(text, nText + 1);
-    fld->SetEncoding(enc);
+    str.copy(text, nText);
   }
   return text;
 }
@@ -57,9 +55,10 @@
   char *text = NULL;
   if (NULL != frame)
   {
-    size_t nText = frame->GetField(fldName)->Size();
+    String str = id3::v2::getStringAtIndex(frame, fldName, nIndex);
+    size_t nText = str.size();
     text = new char[nText + 1];
-    frame->GetField(fldName)->Get(text, nText + 1, nIndex);
+    str.copy(text, nText);
   }
   return text;
 }
diff -Naru -x Makefile.in -x Makefile -x libtool -x control -x config.h -x configure -x config.log -x config.status id3lib3.8.3-3.8.3/src/utils.cpp id3lib3.8.3-3.8.3.patched/src/utils.cpp
--- id3lib3.8.3-3.8.3/src/utils.cpp	2003-03-02 01:23:00.000000000 +0100
+++ id3lib3.8.3-3.8.3.patched/src/utils.cpp	2005-07-08 23:48:42.000000000 +0200
@@ -41,6 +41,8 @@
 // check if we have all unicodes
 #if (defined(ID3_ICONV_FORMAT_UTF16BE) && defined(ID3_ICONV_FORMAT_UTF16) && defined(ID3_ICONV_FORMAT_UTF8) && defined(ID3_ICONV_FORMAT_ASCII))
 # include <iconv.h>
+# include <locale.h>
+# include <langinfo.h>
 # include <errno.h>
 #else
 # undef HAVE_ICONV_H
@@ -54,7 +56,15 @@
   dami::String unicode(size * 2, '\0');
   for (size_t i = 0; i < size; ++i)
   {
-    unicode[i*2+1] = toascii(data[i]);
+    unsigned char c = data[i];
+    if ((c & 0x80) == 0)
+    {
+      unicode[i*2+1] = c;
+    }
+    else
+    {
+      unicode[i*2+1] = '?';
+    }
   }
   return unicode;
 }
@@ -66,7 +76,15 @@
   dami::String ascii(size, '\0');
   for (size_t i = 0; i < size; ++i)
   {
-    ascii[i] = toascii(data[i*2+1]);
+    static unicode_t *c = (unicode_t *)&data[i*2];
+    if ((*c & 0xff80) == 0)
+    {
+      ascii[i] = *c;
+    }
+    else
+    {
+      ascii[i] = '?';
+    }
   }
   return ascii;
 }
@@ -74,13 +92,13 @@
 dami::String oldconvert(dami::String data, ID3_TextEnc sourceEnc, ID3_TextEnc targetEnc)
 {
   dami::String target;
-#define ID3_IS_ASCII(enc)      ((enc) == ID3TE_ASCII || (enc) == ID3TE_ISO8859_1 || (enc) == ID3TE_UTF8)
-#define ID3_IS_UNICODE(enc)    ((enc) == ID3TE_UNICODE || (enc) == ID3TE_UTF16 || (enc) == ID3TE_UTF16BE)
-  if (ID3_IS_ASCII(sourceEnc) && ID3_IS_UNICODE(targetEnc))
+  if (ID3TE_IS_SINGLE_BYTE_ENC(sourceEnc) &&
+      ID3TE_IS_DOUBLE_BYTE_ENC(targetEnc))
   {
     target = mbstoucs(data);
   }
-  else if (ID3_IS_UNICODE(sourceEnc) && ID3_IS_ASCII(targetEnc))
+  else if (ID3TE_IS_DOUBLE_BYTE_ENC(sourceEnc) &&
+           ID3TE_IS_SINGLE_BYTE_ENC(targetEnc))
   {
     target = ucstombs(data);
   }
@@ -117,7 +135,7 @@
 
 namespace 
 {
-  String convert_i(iconv_t cd, String source)
+  String convert_i(iconv_t cd, String source, bool dbcs, bool bigendian)
   {
     String target;
     size_t source_size = source.size();
@@ -140,19 +158,52 @@
       size_t nconv = iconv(cd, 
                            &source_str, &source_size, 
                            &target_str, &target_size);
-      if (nconv == (size_t) -1 && errno != EINVAL && errno != E2BIG)
-      {
-// errno is probably EILSEQ here, which means either an invalid byte sequence or a valid but unconvertible byte sequence 
-        return target;
-      }
       target.append(buf, ID3LIB_BUFSIZ - target_size);
       target_str = buf;
       target_size = ID3LIB_BUFSIZ;
+      if (nconv == (size_t)-1 && (errno == EILSEQ || errno == EINVAL))
+      {
+        if (dbcs)
+        {
+          if (bigendian)
+          {
+            source_str[0] = '\0';
+            source_str[1] = '?';
+          }
+          else
+          {
+            source_str[0] = '?';
+            source_str[1] = '\0';
+          }
+        }
+        else
+        {
+          source_str[0] = '?';
+        }
+      }
+      else if (nconv == (size_t)-1 && errno != E2BIG) /* unexpected error */
+      {
+        return target;
+      }
     }
     while (source_size > 0);
     return target;
   }
 
+  const char* getNativeCharset(void)
+  {
+    static char *charset = NULL;
+    char *oldlocale = NULL;
+
+    if (charset == NULL) {
+      oldlocale = setlocale(LC_CTYPE, "");
+      charset = nl_langinfo(CODESET);
+      setlocale(LC_CTYPE, oldlocale);
+    }
+
+    return charset;
+  }
+
   const char* getFormat(ID3_TextEnc enc)
   {
     const char* format = NULL;
@@ -173,7 +224,11 @@
       case ID3TE_UTF8:
         format = ID3_ICONV_FORMAT_UTF8;
         break;
-        
+
+      case ID3TE_NATIVE:
+        format = getNativeCharset();
+        break;
+
       default:
         break;
     }
@@ -196,7 +251,9 @@
     iconv_t cd = iconv_open (targetFormat, sourceFormat);
     if (cd != (iconv_t) -1)
     {
-      target = convert_i(cd, data);
+      target = convert_i(cd, data,
+                         ID3TE_IS_DOUBLE_BYTE_ENC(sourceEnc),
+                         sourceEnc == ID3TE_UTF16BE);
       if (target.size() == 0)
       {
         //try it without iconv

Reply via email to