]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/contrib/strutl.cc
* apt-pkg/contrib/strutl.cc:
[apt.git] / apt-pkg / contrib / strutl.cc
index 1683868c8a398c72fb9a0e61d97233d3ac0fa56c..2913fbf44e42f74bf8104cb5b97051816c0940d7 100644 (file)
@@ -43,9 +43,10 @@ bool UTF8ToCodeset(const char *codeset, const string &orig, string *dest)
 {
   iconv_t cd;
   const char *inbuf;
-  char *inptr, *outbuf, *outptr;
-  size_t insize, outsize;
-  
+  char *inptr, *outbuf;
+  size_t insize, bufsize;
+  dest->clear();
+
   cd = iconv_open(codeset, "UTF-8");
   if (cd == (iconv_t)(-1)) {
      // Something went wrong
@@ -55,22 +56,49 @@ bool UTF8ToCodeset(const char *codeset, const string &orig, string *dest)
      else
        perror("iconv_open");
      
-     // Clean the destination string
-     *dest = "";
-     
      return false;
   }
 
-  insize = outsize = orig.size();
+  insize = bufsize = orig.size();
   inbuf = orig.data();
   inptr = (char *)inbuf;
-  outbuf = new char[insize+1];
-  outptr = outbuf;
+  outbuf = new char[bufsize];
+  size_t lastError = -1;
 
-  iconv(cd, &inptr, &insize, &outptr, &outsize);
-  *outptr = '\0';
+  while (insize != 0)
+  {
+     char *outptr = outbuf;
+     size_t outsize = bufsize;
+     size_t const err = iconv(cd, &inptr, &insize, &outptr, &outsize);
+     dest->append(outbuf, outptr - outbuf);
+     if (err == (size_t)(-1))
+     {
+       switch (errno)
+       {
+       case EILSEQ:
+          insize--;
+          inptr++;
+          // replace a series of unknown multibytes with a single "?"
+          if (lastError != insize) {
+             lastError = insize - 1;
+             dest->append("?");
+          }
+          break;
+       case EINVAL:
+          insize = 0;
+          break;
+       case E2BIG:
+          if (outptr == outbuf)
+          {
+             bufsize *= 2;
+             delete[] outbuf;
+             outbuf = new char[bufsize];
+          }
+          break;
+       }
+     }
+  }
 
-  *dest = outbuf;
   delete[] outbuf;
   
   iconv_close(cd);