qt: Handle encoding for diagnostics
authorAndre Heinecke <aheinecke@intevation.de>
Wed, 18 Jul 2018 09:27:46 +0000 (11:27 +0200)
committerAndre Heinecke <aheinecke@intevation.de>
Wed, 18 Jul 2018 09:27:46 +0000 (11:27 +0200)
* lang/qt/src/threadedjobmixin.cpp (fromEncoding)
(stringFromGpgOutput): New helpers.
(markupDiagnostics): Use it.

--
The Problem is that on my western windows system GnuPG
gets CP 437 as GetConsoleOutputCP and prints in that codepage.
In a W32 GUI Application we get 0 as GetConsoleOutputCP and 1252
with GetACP.

The only thing that seemed to somehow match was GetOEMCP but
that might just be luck and it might still be broken in
other windows languages.

This code is also used in Kleopatra so it might make sense
to make it public once it is demonstrated that it works on
most systems.

lang/qt/src/threadedjobmixin.cpp

index 8fed77c..cd7c494 100644 (file)
 using namespace QGpgME;
 using namespace GpgME;
 
+#ifdef Q_OS_WIN
+#include <windows.h>
+
+static QString fromEncoding (unsigned int src_encoding, const char *data)
+{
+    int n = MultiByteToWideChar(src_encoding, 0, data, -1, NULL, 0);
+    if (n < 0) {
+        return QString();
+    }
+
+    wchar_t *result = (wchar_t *) malloc ((n+1) * sizeof *result);
+
+    n = MultiByteToWideChar(src_encoding, 0, data, -1, result, n);
+    if (n < 0) {
+        free(result);
+        return QString();
+    }
+    const auto ret = QString::fromWCharArray(result, n);
+    free(result);
+    return ret;
+}
+#endif
+
+static QString stringFromGpgOutput(const QByteArray &ba)
+{
+#ifdef Q_OS_WIN
+    /* Qt on Windows uses GetACP while GnuPG prefers
+     * GetConsoleOutputCP.
+     *
+     * As we are not a console application GetConsoleOutputCP
+     * usually returns 0.
+     * From experience the closest thing that let's us guess
+     * what GetConsoleOutputCP returns for a console application
+     * it appears to be the OEMCP.
+     */
+    unsigned int cpno = GetConsoleOutputCP ();
+    if (!cpno) {
+        cpno = GetOEMCP();
+    }
+    if (!cpno) {
+        cpno = GetACP();
+    }
+    if (!cpno) {
+        return QString();
+    }
+
+    return fromEncoding(cpno, ba.constData());
+#else
+    return QString::fromLocal8Bit(ba);
+#endif
+}
+
 static QString markupDiagnostics(const QString &data)
 {
     // First ensure that we don't have html in the diag.
@@ -76,7 +128,7 @@ QString _detail::audit_log_as_html(Context *ctx, GpgME::Error &err)
             return QString::fromLocal8Bit(err.asString());
         }
         const QByteArray ba = dp.data();
-        return markupDiagnostics(QString::fromUtf8(ba.data(), ba.size()));
+        return markupDiagnostics(stringFromGpgOutput(ba));
     }
 
     if (ctx->protocol() == CMS) {