Coverage Report

Created: 2023-09-25 06:56

/src/FreeRDP/winpr/libwinpr/crt/unicode_icu.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Unicode Conversion (CRT)
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2022 Armin Novak <anovak@thincast.com>
7
 * Copyright 2022 Thincast Technologies GmbH
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
22
#include <winpr/config.h>
23
#include <winpr/assert.h>
24
25
#include <errno.h>
26
#include <wctype.h>
27
28
#include <winpr/crt.h>
29
#include <winpr/error.h>
30
#include <winpr/print.h>
31
32
#ifndef MIN
33
#define MIN(a, b) (a) < (b) ? (a) : (b)
34
#endif
35
36
#include <unicode/ucnv.h>
37
#include <unicode/ustring.h>
38
39
#include "unicode.h"
40
41
#include "../log.h"
42
#define TAG WINPR_TAG("unicode")
43
44
int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
45
                            LPWSTR lpWideCharStr, int cchWideChar)
46
0
{
47
0
  const BOOL isNullTerminated = cbMultiByte < 0;
48
0
  LPWSTR targetStart = NULL;
49
50
0
  WINPR_UNUSED(dwFlags);
51
52
  /* If cbMultiByte is 0, the function fails */
53
54
0
  if ((cbMultiByte == 0) || (cbMultiByte < -1))
55
0
  {
56
0
    SetLastError(ERROR_INVALID_PARAMETER);
57
0
    return 0;
58
0
  }
59
60
0
  size_t len = 0;
61
0
  if (isNullTerminated)
62
0
    len = strlen(lpMultiByteStr) + 1;
63
0
  else
64
0
    len = cbMultiByte;
65
66
0
  if (len >= INT_MAX)
67
0
  {
68
0
    SetLastError(ERROR_INVALID_PARAMETER);
69
0
    return 0;
70
0
  }
71
0
  cbMultiByte = (int)len;
72
73
  /*
74
   * if cchWideChar is 0, the function returns the required buffer size
75
   * in characters for lpWideCharStr and makes no use of the output parameter itself.
76
   */
77
0
  {
78
0
    UErrorCode error = U_ZERO_ERROR;
79
0
    int32_t targetLength = -1;
80
0
    int32_t targetCapacity = -1;
81
82
0
    switch (CodePage)
83
0
    {
84
0
      case CP_ACP:
85
0
      case CP_UTF8:
86
0
        break;
87
88
0
      default:
89
0
        WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
90
0
        SetLastError(ERROR_INVALID_PARAMETER);
91
0
        return 0;
92
0
    }
93
94
0
    targetStart = lpWideCharStr;
95
0
    targetCapacity = cchWideChar;
96
97
0
    u_strFromUTF8(targetStart, targetCapacity, &targetLength, lpMultiByteStr, cbMultiByte,
98
0
                  &error);
99
100
0
    switch (error)
101
0
    {
102
0
      case U_BUFFER_OVERFLOW_ERROR:
103
0
        if (targetCapacity > 0)
104
0
        {
105
0
          cchWideChar = 0;
106
0
          WLog_ERR(TAG, "insufficient buffer supplied, got %d, required %d",
107
0
                   targetCapacity, targetLength);
108
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
109
0
        }
110
0
        else
111
0
          cchWideChar = targetLength;
112
0
        break;
113
0
      case U_STRING_NOT_TERMINATED_WARNING:
114
0
        cchWideChar = targetLength;
115
0
        break;
116
0
      case U_ZERO_ERROR:
117
0
        cchWideChar = targetLength;
118
0
        break;
119
0
      default:
120
0
        WLog_WARN(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "]", u_errorName(error),
121
0
                  error);
122
0
        if (U_FAILURE(error))
123
0
        {
124
0
          WLog_ERR(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "] is fatal",
125
0
                   u_errorName(error), error);
126
0
          cchWideChar = 0;
127
0
          SetLastError(ERROR_NO_UNICODE_TRANSLATION);
128
0
        }
129
0
        else
130
0
          cchWideChar = targetLength;
131
0
        break;
132
0
    }
133
0
  }
134
135
0
  return cchWideChar;
136
0
}
137
138
int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
139
                            LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
140
                            LPBOOL lpUsedDefaultChar)
141
0
{
142
0
  char* targetStart = NULL;
143
144
  /* If cchWideChar is 0, the function fails */
145
146
0
  if ((cchWideChar == 0) || (cchWideChar < -1))
147
0
  {
148
0
    SetLastError(ERROR_INVALID_PARAMETER);
149
0
    return 0;
150
0
  }
151
152
  /* If cchWideChar is -1, the string is null-terminated */
153
154
0
  size_t len = 0;
155
0
  if (cchWideChar == -1)
156
0
    len = _wcslen(lpWideCharStr) + 1;
157
0
  else
158
0
    len = cchWideChar;
159
160
0
  if (len >= INT32_MAX)
161
0
  {
162
0
    SetLastError(ERROR_INVALID_PARAMETER);
163
0
    return 0;
164
0
  }
165
0
  cchWideChar = (int)len;
166
167
  /*
168
   * if cbMultiByte is 0, the function returns the required buffer size
169
   * in bytes for lpMultiByteStr and makes no use of the output parameter itself.
170
   */
171
0
  {
172
0
    UErrorCode error = U_ZERO_ERROR;
173
0
    int32_t targetLength = -1;
174
0
    int32_t targetCapacity = -1;
175
176
0
    switch (CodePage)
177
0
    {
178
0
      case CP_ACP:
179
0
      case CP_UTF8:
180
0
        break;
181
182
0
      default:
183
0
        WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
184
0
        SetLastError(ERROR_INVALID_PARAMETER);
185
0
        return 0;
186
0
    }
187
188
0
    targetStart = lpMultiByteStr;
189
0
    targetCapacity = cbMultiByte;
190
191
0
    u_strToUTF8(targetStart, targetCapacity, &targetLength, lpWideCharStr, cchWideChar, &error);
192
0
    switch (error)
193
0
    {
194
0
      case U_BUFFER_OVERFLOW_ERROR:
195
0
        if (targetCapacity > 0)
196
0
        {
197
0
          WLog_ERR(TAG, "insufficient buffer supplied, got %d, required %d",
198
0
                   targetCapacity, targetLength);
199
0
          cbMultiByte = 0;
200
0
          SetLastError(ERROR_INSUFFICIENT_BUFFER);
201
0
        }
202
0
        else
203
0
          cbMultiByte = targetLength;
204
0
        break;
205
0
      case U_STRING_NOT_TERMINATED_WARNING:
206
0
        cbMultiByte = targetLength;
207
0
        break;
208
0
      case U_ZERO_ERROR:
209
0
        cbMultiByte = targetLength;
210
0
        break;
211
0
      default:
212
0
        WLog_WARN(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "]", u_errorName(error),
213
0
                  error);
214
0
        if (U_FAILURE(error))
215
0
        {
216
0
          WLog_ERR(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "] is fatal",
217
0
                   u_errorName(error), error);
218
0
          cbMultiByte = 0;
219
0
          SetLastError(ERROR_NO_UNICODE_TRANSLATION);
220
0
        }
221
0
        else
222
0
          cbMultiByte = targetLength;
223
0
        break;
224
0
    }
225
0
  }
226
0
  return cbMultiByte;
227
0
}