strdup -> xstrdup
[gpgol.git] / src / mlang-charset.cpp
1 /* @file mlang-charset.cpp
2  * @brief Convert between charsets using Mlang
3  *
4  * Copyright (C) 2015 by Bundesamt für Sicherheit in der Informationstechnik
5  * Software engineering by Intevation GmbH
6  *
7  * This file is part of GpgOL.
8  *
9  * GpgOL is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * GpgOL is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include "config.h"
24 #include "common.h"
25 #define INITGUID
26 #include <initguid.h>
27 DEFINE_GUID (IID_IMultiLanguage, 0x275c23e1,0x3747,0x11d0,0x9f,
28                                  0xea,0x00,0xaa,0x00,0x3f,0x86,0x46);
29 #include <mlang.h>
30 #undef INITGUID
31
32 #include "mlang-charset.h"
33
34 char *ansi_charset_to_utf8 (const char *charset, const char *input,
35                             size_t inlen, int codepage)
36 {
37   LPMULTILANGUAGE multilang = NULL;
38   MIMECSETINFO mime_info;
39   HRESULT err;
40   DWORD enc;
41   DWORD mode = 0;
42   unsigned int wlen = 0,
43                uinlen = 0;
44   wchar_t *buf;
45   char *ret;
46
47   if ((!charset || !strlen (charset)) && !codepage)
48     {
49       log_debug ("%s:%s: No charset / codepage returning plain.",
50                  SRCNAME, __func__);
51       return xstrdup (input);
52     }
53
54   CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
55                    IID_IMultiLanguage, (void**)&multilang);
56   memdbg_addRef (multilang);
57
58   if (!multilang)
59     {
60       log_error ("%s:%s: Failed to get multilang obj.",
61                  SRCNAME, __func__);
62       return NULL;
63     }
64
65   if (inlen > UINT_MAX)
66     {
67       log_error ("%s:%s: Inlen too long. Bug.",
68                  SRCNAME, __func__);
69       gpgol_release (multilang);
70       return NULL;
71     }
72
73   uinlen = (unsigned int) inlen;
74
75   if (!codepage)
76     {
77       mime_info.uiCodePage = 0;
78       mime_info.uiInternetEncoding = 0;
79       BSTR w_charset = utf8_to_wchar (charset);
80       err = multilang->GetCharsetInfo (w_charset, &mime_info);
81       xfree (w_charset);
82       if (err != S_OK)
83         {
84           log_error ("%s:%s: Failed to find charset for: %s",
85                      SRCNAME, __func__, charset);
86           gpgol_release (multilang);
87           return xstrdup (input);
88         }
89       enc = (mime_info.uiInternetEncoding == 0) ? mime_info.uiCodePage :
90                                                   mime_info.uiInternetEncoding;
91     }
92   else
93     {
94       enc = codepage;
95     }
96
97   /** Get the size of the result */
98   err = multilang->ConvertStringToUnicode(&mode, enc, const_cast<char*>(input),
99                                           &uinlen, NULL, &wlen);
100   if (FAILED (err))
101     {
102       log_error ("%s:%s: Failed conversion.",
103                  SRCNAME, __func__);
104       gpgol_release (multilang);
105       return NULL;
106   }
107   buf = (wchar_t*) xmalloc(sizeof(wchar_t) * (wlen + 1));
108
109   err = multilang->ConvertStringToUnicode(&mode, enc, const_cast<char*>(input),
110                                           &uinlen, buf, &wlen);
111   gpgol_release (multilang);
112   if (FAILED (err))
113     {
114       log_error ("%s:%s: Failed conversion 2.",
115                  SRCNAME, __func__);
116       xfree (buf);
117       return NULL;
118     }
119   /* Doc is not clear if this is terminated. */
120   buf[wlen] = L'\0';
121
122   ret = wchar_to_utf8 (buf);
123   xfree (buf);
124   return ret;
125 }