VirtualBox

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

Last change on this file since 93103 was 90794, checked in by vboxsync, 3 years ago

*: More VALID_PTR -> RT_VALID_PTR/AssertPtr.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette