VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/string/utf-16-latin-1.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.9 KB
Line 
1/* $Id: utf-16-latin-1.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Latin-1 and UTF-16.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/latin1.h>
42#include "internal/iprt.h"
43
44#include <iprt/assert.h>
45#include <iprt/err.h>
46#include <iprt/mem.h>
47#include <iprt/string.h>
48#include <iprt/utf16.h>
49#include <iprt/uni.h>
50#include "internal/string.h"
51
52
53/**
54 * Validate the UTF-16 encoding and calculates the length of a Latin1 encoding.
55 *
56 * @returns iprt status code.
57 * @param pwsz The UTF-16 string.
58 * @param cwc The max length of the UTF-16 string to consider.
59 * @param pcch Where to store the length (excluding '\\0') of the Latin1 string. (cch == cb, btw)
60 */
61static int rtUtf16CalcLatin1Length(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)
62{
63 int rc = VINF_SUCCESS;
64 size_t cch = 0;
65 while (cwc > 0)
66 {
67 RTUTF16 wc = *pwsz++; cwc--;
68 if (!wc)
69 break;
70 else if (RT_LIKELY(wc < 0x100))
71 ++cch;
72 else
73 {
74 if (wc < 0xd800 || wc > 0xdfff)
75 {
76 if (wc >= 0xfffe)
77 {
78 RTStrAssertMsgFailed(("endian indicator! wc=%#x\n", wc));
79 rc = VERR_CODE_POINT_ENDIAN_INDICATOR;
80 break;
81 }
82 }
83 else
84 {
85 if (wc >= 0xdc00)
86 {
87 RTStrAssertMsgFailed(("Wrong 1st char in surrogate! wc=%#x\n", wc));
88 rc = VERR_INVALID_UTF16_ENCODING;
89 break;
90 }
91 if (cwc <= 0)
92 {
93 RTStrAssertMsgFailed(("Invalid length! wc=%#x\n", wc));
94 rc = VERR_INVALID_UTF16_ENCODING;
95 break;
96 }
97 wc = *pwsz++; cwc--;
98 if (wc < 0xdc00 || wc > 0xdfff)
99 {
100 RTStrAssertMsgFailed(("Wrong 2nd char in surrogate! wc=%#x\n", wc));
101 rc = VERR_INVALID_UTF16_ENCODING;
102 break;
103 }
104 }
105
106 rc = VERR_NO_TRANSLATION;
107 break;
108 }
109 }
110
111 /* done */
112 *pcch = cch;
113 return rc;
114}
115
116
117/**
118 * Recodes an valid UTF-16 string as Latin1.
119 *
120 * @returns iprt status code.
121 * @param pwsz The UTF-16 string.
122 * @param cwc The number of RTUTF16 characters to process from pwsz. The recoding
123 * will stop when cwc or '\\0' is reached.
124 * @param psz Where to store the Latin1 string.
125 * @param cch The size of the Latin1 buffer, excluding the terminator.
126 */
127static int rtUtf16RecodeAsLatin1(PCRTUTF16 pwsz, size_t cwc, char *psz, size_t cch)
128{
129 unsigned char *pch = (unsigned char *)psz;
130 int rc = VINF_SUCCESS;
131 while (cwc > 0)
132 {
133 RTUTF16 wc = *pwsz++; cwc--;
134 if (!wc)
135 break;
136 if (RT_LIKELY(wc < 0x100))
137 {
138 if (RT_UNLIKELY(cch < 1))
139 {
140 RTStrAssertMsgFailed(("Buffer overflow! 1\n"));
141 rc = VERR_BUFFER_OVERFLOW;
142 break;
143 }
144 cch--;
145 *pch++ = (unsigned char)wc;
146 }
147 else
148 {
149 if (wc < 0xd800 || wc > 0xdfff)
150 {
151 if (wc >= 0xfffe)
152 {
153 RTStrAssertMsgFailed(("endian indicator! wc=%#x\n", wc));
154 rc = VERR_CODE_POINT_ENDIAN_INDICATOR;
155 break;
156 }
157 }
158 else
159 {
160 if (wc >= 0xdc00)
161 {
162 RTStrAssertMsgFailed(("Wrong 1st char in surrogate! wc=%#x\n", wc));
163 rc = VERR_INVALID_UTF16_ENCODING;
164 break;
165 }
166 if (cwc <= 0)
167 {
168 RTStrAssertMsgFailed(("Invalid length! wc=%#x\n", wc));
169 rc = VERR_INVALID_UTF16_ENCODING;
170 break;
171 }
172 RTUTF16 wc2 = *pwsz++; cwc--;
173 if (wc2 < 0xdc00 || wc2 > 0xdfff)
174 {
175 RTStrAssertMsgFailed(("Wrong 2nd char in surrogate! wc=%#x\n", wc));
176 rc = VERR_INVALID_UTF16_ENCODING;
177 break;
178 }
179 }
180
181 rc = VERR_NO_TRANSLATION;
182 break;
183 }
184 }
185
186 /* done */
187 *pch = '\0';
188 return rc;
189}
190
191
192RTDECL(int) RTUtf16ToLatin1Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag)
193{
194 /*
195 * Validate input.
196 */
197 AssertPtr(ppszString);
198 AssertPtr(pwszString);
199 *ppszString = NULL;
200
201 /*
202 * Validate the UTF-16 string and calculate the length of the UTF-8 encoding of it.
203 */
204 size_t cch;
205 int rc = rtUtf16CalcLatin1Length(pwszString, RTSTR_MAX, &cch);
206 if (RT_SUCCESS(rc))
207 {
208 /*
209 * Allocate buffer and recode it.
210 */
211 char *pszResult = (char *)RTMemAllocTag(cch + 1, pszTag);
212 if (pszResult)
213 {
214 rc = rtUtf16RecodeAsLatin1(pwszString, RTSTR_MAX, pszResult, cch);
215 if (RT_SUCCESS(rc))
216 {
217 *ppszString = pszResult;
218 return rc;
219 }
220
221 RTMemFree(pszResult);
222 }
223 else
224 rc = VERR_NO_STR_MEMORY;
225 }
226 return rc;
227}
228RT_EXPORT_SYMBOL(RTUtf16ToLatin1Tag);
229
230
231RTDECL(int) RTUtf16ToLatin1ExTag(PCRTUTF16 pwszString, size_t cwcString, char **ppsz, size_t cch, size_t *pcch, const char *pszTag)
232{
233 /*
234 * Validate input.
235 */
236 AssertPtr(pwszString);
237 AssertPtr(ppsz);
238 AssertPtrNull(pcch);
239
240 /*
241 * Validate the UTF-16 string and calculate the length of the Latin1 encoding of it.
242 */
243 size_t cchResult;
244 int rc = rtUtf16CalcLatin1Length(pwszString, cwcString, &cchResult);
245 if (RT_SUCCESS(rc))
246 {
247 if (pcch)
248 *pcch = cchResult;
249
250 /*
251 * Check buffer size / Allocate buffer and recode it.
252 */
253 bool fShouldFree;
254 char *pszResult;
255 if (cch > 0 && *ppsz)
256 {
257 fShouldFree = false;
258 if (cch <= cchResult)
259 return VERR_BUFFER_OVERFLOW;
260 pszResult = *ppsz;
261 }
262 else
263 {
264 *ppsz = NULL;
265 fShouldFree = true;
266 cch = RT_MAX(cch, cchResult + 1);
267 pszResult = (char *)RTMemAllocTag(cch, pszTag);
268 }
269 if (pszResult)
270 {
271 rc = rtUtf16RecodeAsLatin1(pwszString, cwcString, pszResult, cch - 1);
272 if (RT_SUCCESS(rc))
273 {
274 *ppsz = pszResult;
275 return rc;
276 }
277
278 if (fShouldFree)
279 RTMemFree(pszResult);
280 }
281 else
282 rc = VERR_NO_STR_MEMORY;
283 }
284 return rc;
285}
286RT_EXPORT_SYMBOL(RTUtf16ToLatin1ExTag);
287
288
289RTDECL(size_t) RTUtf16CalcLatin1Len(PCRTUTF16 pwsz)
290{
291 size_t cch;
292 int rc = rtUtf16CalcLatin1Length(pwsz, RTSTR_MAX, &cch);
293 return RT_SUCCESS(rc) ? cch : 0;
294}
295RT_EXPORT_SYMBOL(RTUtf16CalcLatin1Len);
296
297
298RTDECL(int) RTUtf16CalcLatin1LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)
299{
300 size_t cch;
301 int rc = rtUtf16CalcLatin1Length(pwsz, cwc, &cch);
302 if (pcch)
303 *pcch = RT_SUCCESS(rc) ? cch : ~(size_t)0;
304 return rc;
305}
306RT_EXPORT_SYMBOL(RTUtf16CalcLatin1LenEx);
307
308
309/**
310 * Calculates the UTF-16 length of a Latin1 string. In fact this is just the
311 * original length, but the function saves us nasty comments to that effect
312 * all over the place.
313 *
314 * @returns IPRT status code.
315 * @param psz Pointer to the Latin1 string.
316 * @param cch The max length of the string. (btw cch = cb)
317 * Use RTSTR_MAX if all of the string is to be examined.s
318 * @param pcwc Where to store the length of the UTF-16 string as a number of RTUTF16 characters.
319 */
320static int rtLatin1CalcUtf16Length(const char *psz, size_t cch, size_t *pcwc)
321{
322 *pcwc = RTStrNLen(psz, cch);
323 return VINF_SUCCESS;
324}
325
326
327/**
328 * Recodes a Latin1 string as UTF-16. This is just a case of expanding it to
329 * sixteen bits, as Unicode is a superset of Latin1.
330 *
331 * Since we know the input is valid, we do *not* perform length checks.
332 *
333 * @returns iprt status code.
334 * @param psz The Latin1 string to recode.
335 * @param cch The number of chars (the type char, so bytes if you like) to process of the Latin1 string.
336 * The recoding will stop when cch or '\\0' is reached. Pass RTSTR_MAX to process up to '\\0'.
337 * @param pwsz Where to store the UTF-16 string.
338 * @param cwc The number of RTUTF16 items the pwsz buffer can hold, excluding the terminator ('\\0').
339 */
340static int rtLatin1RecodeAsUtf16(const char *psz, size_t cch, PRTUTF16 pwsz, size_t cwc)
341{
342 int rc = VINF_SUCCESS;
343 const unsigned char *puch = (const unsigned char *)psz;
344 PRTUTF16 pwc = pwsz;
345 while (cch-- > 0)
346 {
347 /* read the next char and check for terminator. */
348 const unsigned char uch = *puch;
349 if (!uch)
350 break;
351
352 /* check for output overflow */
353 if (RT_UNLIKELY(cwc < 1))
354 {
355 rc = VERR_BUFFER_OVERFLOW;
356 break;
357 }
358
359 /* expand the code point */
360 *pwc++ = uch;
361 cwc--;
362 puch++;
363 }
364
365 /* done */
366 *pwc = '\0';
367 return rc;
368}
369
370
371RTDECL(int) RTLatin1ToUtf16Tag(const char *pszString, PRTUTF16 *ppwszString, const char *pszTag)
372{
373 /*
374 * Validate input.
375 */
376 AssertPtr(ppwszString);
377 AssertPtr(pszString);
378 *ppwszString = NULL;
379
380 /*
381 * Validate the input and calculate the length of the UTF-16 string.
382 */
383 size_t cwc;
384 int rc = rtLatin1CalcUtf16Length(pszString, RTSTR_MAX, &cwc);
385 if (RT_SUCCESS(rc))
386 {
387 /*
388 * Allocate buffer.
389 */
390 PRTUTF16 pwsz = (PRTUTF16)RTMemAllocTag((cwc + 1) * sizeof(RTUTF16), pszTag);
391 if (pwsz)
392 {
393 /*
394 * Encode the UTF-16 string.
395 */
396 rc = rtLatin1RecodeAsUtf16(pszString, RTSTR_MAX, pwsz, cwc);
397 if (RT_SUCCESS(rc))
398 {
399 *ppwszString = pwsz;
400 return rc;
401 }
402 RTMemFree(pwsz);
403 }
404 else
405 rc = VERR_NO_UTF16_MEMORY;
406 }
407 return rc;
408}
409RT_EXPORT_SYMBOL(RTLatin1ToUtf16Tag);
410
411
412RTDECL(int) RTLatin1ToUtf16ExTag(const char *pszString, size_t cchString,
413 PRTUTF16 *ppwsz, size_t cwc, size_t *pcwc, const char *pszTag)
414{
415 /*
416 * Validate input.
417 */
418 AssertPtr(pszString);
419 AssertPtr(ppwsz);
420 AssertPtrNull(pcwc);
421
422 /*
423 * Validate the input and calculate the length of the UTF-16 string.
424 */
425 size_t cwcResult;
426 int rc = rtLatin1CalcUtf16Length(pszString, cchString, &cwcResult);
427 if (RT_SUCCESS(rc))
428 {
429 if (pcwc)
430 *pcwc = cwcResult;
431
432 /*
433 * Check buffer size / Allocate buffer.
434 */
435 bool fShouldFree;
436 PRTUTF16 pwszResult;
437 if (cwc > 0 && *ppwsz)
438 {
439 fShouldFree = false;
440 if (cwc <= cwcResult)
441 return VERR_BUFFER_OVERFLOW;
442 pwszResult = *ppwsz;
443 }
444 else
445 {
446 *ppwsz = NULL;
447 fShouldFree = true;
448 cwc = RT_MAX(cwcResult + 1, cwc);
449 pwszResult = (PRTUTF16)RTMemAllocTag(cwc * sizeof(RTUTF16), pszTag);
450 }
451 if (pwszResult)
452 {
453 /*
454 * Encode the UTF-16 string.
455 */
456 rc = rtLatin1RecodeAsUtf16(pszString, cchString, pwszResult, cwc - 1);
457 if (RT_SUCCESS(rc))
458 {
459 *ppwsz = pwszResult;
460 return rc;
461 }
462 if (fShouldFree)
463 RTMemFree(pwszResult);
464 }
465 else
466 rc = VERR_NO_UTF16_MEMORY;
467 }
468 return rc;
469}
470RT_EXPORT_SYMBOL(RTLatin1ToUtf16ExTag);
471
472
473RTDECL(size_t) RTLatin1CalcUtf16Len(const char *psz)
474{
475 size_t cwc;
476 int rc = rtLatin1CalcUtf16Length(psz, RTSTR_MAX, &cwc);
477 return RT_SUCCESS(rc) ? cwc : 0;
478}
479RT_EXPORT_SYMBOL(RTLatin1CalcUtf16Len);
480
481
482RTDECL(int) RTLatin1CalcUtf16LenEx(const char *psz, size_t cch, size_t *pcwc)
483{
484 size_t cwc;
485 int rc = rtLatin1CalcUtf16Length(psz, cch, &cwc);
486 if (pcwc)
487 *pcwc = RT_SUCCESS(rc) ? cwc : ~(size_t)0;
488 return rc;
489}
490RT_EXPORT_SYMBOL(RTLatin1CalcUtf16LenEx);
491
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use