Bug Summary

File:root/firefox-clang/intl/icu/source/common/ucnv.cpp
Warning:line 1943, column 21
Although the value stored to 's' is used in the enclosing expression, the value is never actually read from 's'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ucnv.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/config/external/icu/common -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/config/external/icu/common -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D U_COMMON_IMPLEMENTATION -D _LIBCPP_DISABLE_DEPRECATION_WARNINGS -D U_USING_ICU_NAMESPACE=0 -D U_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -D U_HIDE_OBSOLETE_UTF_OLD_H=1 -D UCONFIG_NO_LEGACY_CONVERSION -D UCONFIG_NO_TRANSLITERATION -D UCONFIG_NO_REGULAR_EXPRESSIONS -D UCONFIG_NO_BREAK_ITERATION -D UCONFIG_NO_IDNA -D UCONFIG_NO_MF2 -D UCONFIG_NO_NORMALIZATION -D UCONFIG_NO_COLLATION -D U_CHARSET_IS_UTF8 -D UNISTR_FROM_CHAR_EXPLICIT=explicit -D UNISTR_FROM_STRING_EXPLICIT=explicit -D U_ENABLE_DYLOAD=0 -D U_DEBUG=1 -I /root/firefox-clang/config/external/icu/common -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/config/external/icu/common -I /root/firefox-clang/intl/icu/source/i18n -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -Wno-comma -Wno-implicit-const-int-float-conversion -Wno-macro-redefined -Wno-microsoft-include -Wno-tautological-unsigned-enum-zero-compare -Wno-unreachable-code-loop-increment -Wno-unreachable-code-return -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ /root/firefox-clang/intl/icu/source/common/ucnv.cpp
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4******************************************************************************
5*
6* Copyright (C) 1998-2016, International Business Machines
7* Corporation and others. All Rights Reserved.
8*
9******************************************************************************
10*
11* ucnv.c:
12* Implements APIs for the ICU's codeset conversion library;
13* mostly calls through internal functions;
14* created by Bertrand A. Damiba
15*
16* Modification History:
17*
18* Date Name Description
19* 04/04/99 helena Fixed internal header inclusion.
20* 05/09/00 helena Added implementation to handle fallback mappings.
21* 06/20/2000 helena OS/400 port changes; mostly typecast.
22*/
23
24#include "unicode/utypes.h"
25
26#if !UCONFIG_NO_CONVERSION0
27
28#include <memory>
29
30#include "unicode/ustring.h"
31#include "unicode/ucnv.h"
32#include "unicode/ucnv_err.h"
33#include "unicode/uset.h"
34#include "unicode/utf.h"
35#include "unicode/utf16.h"
36#include "putilimp.h"
37#include "cmemory.h"
38#include "cstring.h"
39#include "uassert.h"
40#include "utracimp.h"
41#include "ustr_imp.h"
42#include "ucnv_imp.h"
43#include "ucnv_cnv.h"
44#include "ucnv_bld.h"
45
46/* size of intermediate and preflighting buffers in ucnv_convert() */
47#define CHUNK_SIZE1024 1024
48
49typedef struct UAmbiguousConverter {
50 const char *name;
51 const char16_t variant5c;
52} UAmbiguousConverter;
53
54static const UAmbiguousConverter ambiguousConverters[]={
55 { "ibm-897_P100-1995", 0xa5 },
56 { "ibm-942_P120-1999", 0xa5 },
57 { "ibm-943_P130-1999", 0xa5 },
58 { "ibm-946_P100-1995", 0xa5 },
59 { "ibm-33722_P120-1999", 0xa5 },
60 { "ibm-1041_P100-1995", 0xa5 },
61 /*{ "ibm-54191_P100-2006", 0xa5 },*/
62 /*{ "ibm-62383_P100-2007", 0xa5 },*/
63 /*{ "ibm-891_P100-1995", 0x20a9 },*/
64 { "ibm-944_P100-1995", 0x20a9 },
65 { "ibm-949_P110-1999", 0x20a9 },
66 { "ibm-1363_P110-1997", 0x20a9 },
67 { "ISO_2022,locale=ko,version=0", 0x20a9 },
68 { "ibm-1088_P100-1995", 0x20a9 }
69};
70
71/*Calls through createConverter */
72U_CAPIextern "C" UConverter* U_EXPORT2
73ucnv_open (const char *name,
74 UErrorCode * err)
75{
76 UConverter *r;
77
78 if (err == nullptr || U_FAILURE (*err)) {
79 return nullptr;
80 }
81
82 r = ucnv_createConverter(nullptr, name, err);
83 return r;
84}
85
86U_CAPIextern "C" UConverter* U_EXPORT2
87ucnv_openPackage (const char *packageName, const char *converterName, UErrorCode * err)
88{
89 return ucnv_createConverterFromPackage(packageName, converterName, err);
90}
91
92/*Extracts the char16_t* to a char* and calls through createConverter */
93U_CAPIextern "C" UConverter* U_EXPORT2
94ucnv_openU (const char16_t * name,
95 UErrorCode * err)
96{
97 char asciiName[UCNV_MAX_CONVERTER_NAME_LENGTH60];
98
99 if (err == nullptr || U_FAILURE(*err))
100 return nullptr;
101 if (name == nullptr)
102 return ucnv_open (nullptr, err);
103 if (u_strlen(name) >= UCNV_MAX_CONVERTER_NAME_LENGTH60)
104 {
105 *err = U_ILLEGAL_ARGUMENT_ERROR;
106 return nullptr;
107 }
108 return ucnv_open(u_austrcpy(asciiName, name), err);
109}
110
111/* Copy the string that is represented by the UConverterPlatform enum
112 * @param platformString An output buffer
113 * @param platform An enum representing a platform
114 * @return the length of the copied string.
115 */
116static int32_t
117ucnv_copyPlatformString(char *platformString, UConverterPlatform pltfrm)
118{
119 switch (pltfrm)
120 {
121 case UCNV_IBM:
122 uprv_strcpy(platformString, "ibm-"):: strcpy(platformString, "ibm-");
123 return 4;
124 case UCNV_UNKNOWN:
125 break;
126 }
127
128 /* default to empty string */
129 *platformString = 0;
130 return 0;
131}
132
133/*Assumes a $platform-#codepage.$CONVERTER_FILE_EXTENSION scheme and calls
134 *through createConverter*/
135U_CAPIextern "C" UConverter* U_EXPORT2
136ucnv_openCCSID (int32_t codepage,
137 UConverterPlatform platform,
138 UErrorCode * err)
139{
140 char myName[UCNV_MAX_CONVERTER_NAME_LENGTH60];
141 int32_t myNameLen;
142
143 if (err == nullptr || U_FAILURE (*err))
144 return nullptr;
145
146 /* ucnv_copyPlatformString could return "ibm-" or "cp" */
147 myNameLen = ucnv_copyPlatformString(myName, platform);
148 T_CString_integerToString(myName + myNameLen, codepage, 10);
149
150 return ucnv_createConverter(nullptr, myName, err);
151}
152
153/* Creating a temporary stack-based object that can be used in one thread,
154and created from a converter that is shared across threads.
155*/
156
157U_CAPIextern "C" UConverter* U_EXPORT2
158ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, UErrorCode *status)
159{
160 UConverter *localConverter, *allocatedConverter;
161 int32_t stackBufferSize;
162 int32_t bufferSizeNeeded;
163 UErrorCode cbErr;
164 UConverterToUnicodeArgs toUArgs = {
165 sizeof(UConverterToUnicodeArgs),
166 true,
167 nullptr,
168 nullptr,
169 nullptr,
170 nullptr,
171 nullptr,
172 nullptr
173 };
174 UConverterFromUnicodeArgs fromUArgs = {
175 sizeof(UConverterFromUnicodeArgs),
176 true,
177 nullptr,
178 nullptr,
179 nullptr,
180 nullptr,
181 nullptr,
182 nullptr
183 };
184
185 UTRACE_ENTRY_OC(UTRACE_UCNV_CLONE);
186
187 if (status == nullptr || U_FAILURE(*status)){
188 UTRACE_EXIT_STATUS(status? *status: U_ILLEGAL_ARGUMENT_ERROR);
189 return nullptr;
190 }
191
192 if (cnv == nullptr) {
193 *status = U_ILLEGAL_ARGUMENT_ERROR;
194 UTRACE_EXIT_STATUS(*status);
195 return nullptr;
196 }
197
198 UTRACE_DATA3(UTRACE_OPEN_CLOSE, "clone converter %s at %p into stackBuffer %p",
199 ucnv_getName(cnv, status), cnv, stackBuffer);
200
201 if (cnv->sharedData->impl->safeClone != nullptr) {
202 /* call the custom safeClone function for sizing */
203 bufferSizeNeeded = 0;
204 cnv->sharedData->impl->safeClone(cnv, nullptr, &bufferSizeNeeded, status);
205 if (U_FAILURE(*status)) {
206 UTRACE_EXIT_STATUS(*status);
207 return nullptr;
208 }
209 }
210 else
211 {
212 /* inherent sizing */
213 bufferSizeNeeded = sizeof(UConverter);
214 }
215
216 if (pBufferSize == nullptr) {
217 stackBufferSize = 1;
218 pBufferSize = &stackBufferSize;
219 } else {
220 stackBufferSize = *pBufferSize;
221 if (stackBufferSize <= 0){ /* 'preflighting' request - set needed size into *pBufferSize */
222 *pBufferSize = bufferSizeNeeded;
223 UTRACE_EXIT_VALUE(bufferSizeNeeded);
224 return nullptr;
225 }
226 }
227
228 /* Adjust (if necessary) the stackBuffer pointer to be aligned correctly for a UConverter.
229 * TODO(Jira ICU-20736) Redo this using std::align() once g++4.9 compatibility is no longer needed.
230 */
231 if (stackBuffer) {
232 uintptr_t p = reinterpret_cast<uintptr_t>(stackBuffer);
233 uintptr_t aligned_p = (p + alignof(UConverter) - 1) & ~(alignof(UConverter) - 1);
234 ptrdiff_t pointerAdjustment = aligned_p - p;
235 if (bufferSizeNeeded + pointerAdjustment <= stackBufferSize) {
236 stackBuffer = reinterpret_cast<void *>(aligned_p);
237 stackBufferSize -= static_cast<int32_t>(pointerAdjustment);
238 } else {
239 /* prevent using the stack buffer but keep the size > 0 so that we do not just preflight */
240 stackBufferSize = 1;
241 }
242 }
243
244 /* Now, see if we must allocate any memory */
245 if (stackBufferSize < bufferSizeNeeded || stackBuffer == nullptr)
246 {
247 /* allocate one here...*/
248 localConverter = allocatedConverter = (UConverter *) uprv_malloc (bufferSizeNeeded);
249
250 if(localConverter == nullptr) {
251 *status = U_MEMORY_ALLOCATION_ERROR;
252 UTRACE_EXIT_STATUS(*status);
253 return nullptr;
254 }
255 // If pBufferSize was nullptr as the input, pBufferSize is set to &stackBufferSize in this function.
256 if (pBufferSize != &stackBufferSize) {
257 *status = U_SAFECLONE_ALLOCATED_WARNING;
258 }
259
260 /* record the fact that memory was allocated */
261 *pBufferSize = bufferSizeNeeded;
262 } else {
263 /* just use the stack buffer */
264 localConverter = (UConverter*) stackBuffer;
265 allocatedConverter = nullptr;
266 }
267
268 uprv_memset(localConverter, 0, bufferSizeNeeded):: memset(localConverter, 0, bufferSizeNeeded);
269
270 /* Copy initial state */
271 uprv_memcpy(localConverter, cnv, sizeof(UConverter))do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (localConverter != __null) ? void
(0) : __assert_fail ("localConverter != __null", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); (
static_cast <bool> (cnv != __null) ? void (0) : __assert_fail
("cnv != __null", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__)); clang diagnostic pop :: memcpy(localConverter
, cnv, sizeof(UConverter)); } while (false)
;
272 localConverter->isCopyLocal = localConverter->isExtraLocal = false;
273
274 /* copy the substitution string */
275 if (cnv->subChars == (uint8_t *)cnv->subUChars) {
276 localConverter->subChars = (uint8_t *)localConverter->subUChars;
277 } else {
278 localConverter->subChars = (uint8_t *)uprv_malloc(UCNV_ERROR_BUFFER_LENGTH32 * U_SIZEOF_UCHAR2);
279 if (localConverter->subChars == nullptr) {
280 uprv_free(allocatedConverter);
281 UTRACE_EXIT_STATUS(*status);
282 return nullptr;
283 }
284 uprv_memcpy(localConverter->subChars, cnv->subChars, UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (localConverter->subChars != __null
) ? void (0) : __assert_fail ("localConverter->subChars != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); (static_cast <bool> (cnv->subChars != __null) ? void
(0) : __assert_fail ("cnv->subChars != __null", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); clang
diagnostic pop :: memcpy(localConverter->subChars, cnv->
subChars, 32 * 2); } while (false)
;
285 }
286
287 /* now either call the safeclone fcn or not */
288 if (cnv->sharedData->impl->safeClone != nullptr) {
289 /* call the custom safeClone function */
290 localConverter = cnv->sharedData->impl->safeClone(cnv, localConverter, pBufferSize, status);
291 }
292
293 if(localConverter==nullptr || U_FAILURE(*status)) {
294 if (allocatedConverter != nullptr && allocatedConverter->subChars != (uint8_t *)allocatedConverter->subUChars) {
295 uprv_free(allocatedConverter->subChars);
296 }
297 uprv_free(allocatedConverter);
298 UTRACE_EXIT_STATUS(*status);
299 return nullptr;
300 }
301
302 /* increment refcount of shared data if needed */
303 if (cnv->sharedData->isReferenceCounted) {
304 ucnv_incrementRefCount(cnv->sharedData);
305 }
306
307 if(localConverter == (UConverter*)stackBuffer) {
308 /* we're using user provided data - set to not destroy */
309 localConverter->isCopyLocal = true;
310 }
311
312 /* allow callback functions to handle any memory allocation */
313 toUArgs.converter = fromUArgs.converter = localConverter;
314 cbErr = U_ZERO_ERROR;
315 cnv->fromCharErrorBehaviour(cnv->toUContext, &toUArgs, nullptr, 0, UCNV_CLONE, &cbErr);
316 cbErr = U_ZERO_ERROR;
317 cnv->fromUCharErrorBehaviour(cnv->fromUContext, &fromUArgs, nullptr, 0, 0, UCNV_CLONE, &cbErr);
318
319 UTRACE_EXIT_PTR_STATUS(localConverter, *status);
320 return localConverter;
321}
322
323U_CAPIextern "C" UConverter* U_EXPORT2
324ucnv_clone(const UConverter* cnv, UErrorCode *status)
325{
326 return ucnv_safeClone(cnv, nullptr, nullptr, status);
327}
328
329/*Decreases the reference counter in the shared immutable section of the object
330 *and frees the mutable part*/
331
332U_CAPIextern "C" void U_EXPORT2
333ucnv_close (UConverter * converter)
334{
335 UErrorCode errorCode = U_ZERO_ERROR;
336
337 UTRACE_ENTRY_OC(UTRACE_UCNV_CLOSE);
338
339 if (converter == nullptr)
340 {
341 UTRACE_EXIT();
342 return;
343 }
344
345 UTRACE_DATA3(UTRACE_OPEN_CLOSE, "close converter %s at %p, isCopyLocal=%b",
346 ucnv_getName(converter, &errorCode), converter, converter->isCopyLocal);
347
348 /* In order to speed up the close, only call the callbacks when they have been changed.
349 This performance check will only work when the callbacks are set within a shared library
350 or from user code that statically links this code. */
351 /* first, notify the callback functions that the converter is closed */
352 if (converter->fromCharErrorBehaviour != UCNV_TO_U_DEFAULT_CALLBACK((UConverterToUCallback) UCNV_TO_U_CALLBACK_SUBSTITUTE)) {
353 UConverterToUnicodeArgs toUArgs = {
354 sizeof(UConverterToUnicodeArgs),
355 true,
356 nullptr,
357 nullptr,
358 nullptr,
359 nullptr,
360 nullptr,
361 nullptr
362 };
363
364 toUArgs.converter = converter;
365 errorCode = U_ZERO_ERROR;
366 converter->fromCharErrorBehaviour(converter->toUContext, &toUArgs, nullptr, 0, UCNV_CLOSE, &errorCode);
367 }
368 if (converter->fromUCharErrorBehaviour != UCNV_FROM_U_DEFAULT_CALLBACK((UConverterFromUCallback) UCNV_FROM_U_CALLBACK_SUBSTITUTE)) {
369 UConverterFromUnicodeArgs fromUArgs = {
370 sizeof(UConverterFromUnicodeArgs),
371 true,
372 nullptr,
373 nullptr,
374 nullptr,
375 nullptr,
376 nullptr,
377 nullptr
378 };
379 fromUArgs.converter = converter;
380 errorCode = U_ZERO_ERROR;
381 converter->fromUCharErrorBehaviour(converter->fromUContext, &fromUArgs, nullptr, 0, 0, UCNV_CLOSE, &errorCode);
382 }
383
384 if (converter->sharedData->impl->close != nullptr) {
385 converter->sharedData->impl->close(converter);
386 }
387
388 if (converter->subChars != (uint8_t *)converter->subUChars) {
389 uprv_free(converter->subChars);
390 }
391
392 if (converter->sharedData->isReferenceCounted) {
393 ucnv_unloadSharedDataIfReady(converter->sharedData);
394 }
395
396 if(!converter->isCopyLocal){
397 uprv_free(converter);
398 }
399
400 UTRACE_EXIT();
401}
402
403/*returns a single Name from the list, will return nullptr if out of bounds
404 */
405U_CAPIextern "C" const char* U_EXPORT2
406ucnv_getAvailableName (int32_t n)
407{
408 if (0 <= n && n <= 0xffff) {
409 UErrorCode err = U_ZERO_ERROR;
410 const char *name = ucnv_bld_getAvailableConverter((uint16_t)n, &err);
411 if (U_SUCCESS(err)) {
412 return name;
413 }
414 }
415 return nullptr;
416}
417
418U_CAPIextern "C" int32_t U_EXPORT2
419ucnv_countAvailable ()
420{
421 UErrorCode err = U_ZERO_ERROR;
422 return ucnv_bld_countAvailableConverters(&err);
423}
424
425U_CAPIextern "C" void U_EXPORT2
426ucnv_getSubstChars (const UConverter * converter,
427 char *mySubChar,
428 int8_t * len,
429 UErrorCode * err)
430{
431 if (U_FAILURE (*err))
432 return;
433
434 if (converter->subCharLen <= 0) {
435 /* Unicode string or empty string from ucnv_setSubstString(). */
436 *len = 0;
437 return;
438 }
439
440 if (*len < converter->subCharLen) /*not enough space in subChars */
441 {
442 *err = U_INDEX_OUTOFBOUNDS_ERROR;
443 return;
444 }
445
446 uprv_memcpy (mySubChar, converter->subChars, converter->subCharLen)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (mySubChar != __null) ? void (0) :
__assert_fail ("mySubChar != __null", __builtin_FILE (), __builtin_LINE
(), __extension__ __PRETTY_FUNCTION__)); (static_cast <bool
> (converter->subChars != __null) ? void (0) : __assert_fail
("converter->subChars != __null", __builtin_FILE (), __builtin_LINE
(), __extension__ __PRETTY_FUNCTION__)); clang diagnostic pop
:: memcpy(mySubChar, converter->subChars, converter->
subCharLen); } while (false)
; /*fills in the subchars */
447 *len = converter->subCharLen; /*store # of bytes copied to buffer */
448}
449
450U_CAPIextern "C" void U_EXPORT2
451ucnv_setSubstChars (UConverter * converter,
452 const char *mySubChar,
453 int8_t len,
454 UErrorCode * err)
455{
456 if (U_FAILURE (*err))
457 return;
458
459 /*Makes sure that the subChar is within the codepages char length boundaries */
460 if ((len > converter->sharedData->staticData->maxBytesPerChar)
461 || (len < converter->sharedData->staticData->minBytesPerChar))
462 {
463 *err = U_ILLEGAL_ARGUMENT_ERROR;
464 return;
465 }
466
467 uprv_memcpy (converter->subChars, mySubChar, len)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (converter->subChars != __null
) ? void (0) : __assert_fail ("converter->subChars != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); (static_cast <bool> (mySubChar != __null) ? void (0
) : __assert_fail ("mySubChar != __null", __builtin_FILE (), __builtin_LINE
(), __extension__ __PRETTY_FUNCTION__)); clang diagnostic pop
:: memcpy(converter->subChars, mySubChar, len); } while (
false)
; /*copies the subchars */
468 converter->subCharLen = len; /*sets the new len */
469
470 /*
471 * There is currently (2001Feb) no separate API to set/get subChar1.
472 * In order to always have subChar written after it is explicitly set,
473 * we set subChar1 to 0.
474 */
475 converter->subChar1 = 0;
476}
477
478U_CAPIextern "C" void U_EXPORT2
479ucnv_setSubstString(UConverter *cnv,
480 const char16_t *s,
481 int32_t length,
482 UErrorCode *err) {
483 alignas(UConverter) char cloneBuffer[U_CNV_SAFECLONE_BUFFERSIZE1024];
484 char chars[UCNV_ERROR_BUFFER_LENGTH32];
485
486 UConverter *clone;
487 uint8_t *subChars;
488 int32_t cloneSize, length8;
489
490 /* Let the following functions check all arguments. */
491 cloneSize = sizeof(cloneBuffer);
492 clone = ucnv_safeClone(cnv, cloneBuffer, &cloneSize, err);
493 ucnv_setFromUCallBack(clone, UCNV_FROM_U_CALLBACK_STOP, nullptr, nullptr, nullptr, err);
494 length8 = ucnv_fromUChars(clone, chars, (int32_t)sizeof(chars), s, length, err);
495 ucnv_close(clone);
496 if (U_FAILURE(*err)) {
497 return;
498 }
499
500 if (cnv->sharedData->impl->writeSub == nullptr
501#if !UCONFIG_NO_LEGACY_CONVERSION1
502 || (cnv->sharedData->staticData->conversionType == UCNV_MBCS &&
503 ucnv_MBCSGetType(cnv) != UCNV_EBCDIC_STATEFUL)
504#endif
505 ) {
506 /* The converter is not stateful. Store the charset bytes as a fixed string. */
507 subChars = (uint8_t *)chars;
508 } else {
509 /*
510 * The converter has a non-default writeSub() function, indicating
511 * that it is stateful.
512 * Store the Unicode string for on-the-fly conversion for correct
513 * state handling.
514 */
515 if (length > UCNV_ERROR_BUFFER_LENGTH32) {
516 /*
517 * Should not occur. The converter should output at least one byte
518 * per char16_t, which means that ucnv_fromUChars() should catch all
519 * overflows.
520 */
521 *err = U_BUFFER_OVERFLOW_ERROR;
522 return;
523 }
524 subChars = (uint8_t *)s;
525 if (length < 0) {
526 length = u_strlen(s);
527 }
528 length8 = length * U_SIZEOF_UCHAR2;
529 }
530
531 /*
532 * For storing the substitution string, select either the small buffer inside
533 * UConverter or allocate a subChars buffer.
534 */
535 if (length8 > UCNV_MAX_SUBCHAR_LEN4) {
536 /* Use a separate buffer for the string. Outside UConverter to not make it too large. */
537 if (cnv->subChars == (uint8_t *)cnv->subUChars) {
538 /* Allocate a new buffer for the string. */
539 cnv->subChars = (uint8_t *)uprv_malloc(UCNV_ERROR_BUFFER_LENGTH32 * U_SIZEOF_UCHAR2);
540 if (cnv->subChars == nullptr) {
541 cnv->subChars = (uint8_t *)cnv->subUChars;
542 *err = U_MEMORY_ALLOCATION_ERROR;
543 return;
544 }
545 uprv_memset(cnv->subChars, 0, UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR):: memset(cnv->subChars, 0, 32 * 2);
546 }
547 }
548
549 /* Copy the substitution string into the UConverter or its subChars buffer. */
550 if (length8 == 0) {
551 cnv->subCharLen = 0;
552 } else {
553 uprv_memcpy(cnv->subChars, subChars, length8)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (cnv->subChars != __null) ? void
(0) : __assert_fail ("cnv->subChars != __null", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); (
static_cast <bool> (subChars != __null) ? void (0) : __assert_fail
("subChars != __null", __builtin_FILE (), __builtin_LINE (),
__extension__ __PRETTY_FUNCTION__)); clang diagnostic pop ::
memcpy(cnv->subChars, subChars, length8); } while (false)
;
554 if (subChars == (uint8_t *)chars) {
555 cnv->subCharLen = (int8_t)length8;
556 } else /* subChars == s */ {
557 cnv->subCharLen = (int8_t)-length;
558 }
559 }
560
561 /* See comment in ucnv_setSubstChars(). */
562 cnv->subChar1 = 0;
563}
564
565/*resets the internal states of a converter
566 *goal : have the same behaviour than a freshly created converter
567 */
568static void _reset(UConverter *converter, UConverterResetChoice choice,
569 UBool callCallback) {
570 if(converter == nullptr) {
571 return;
572 }
573
574 if(callCallback) {
575 /* first, notify the callback functions that the converter is reset */
576 UErrorCode errorCode;
577
578 if(choice<=UCNV_RESET_TO_UNICODE && converter->fromCharErrorBehaviour != UCNV_TO_U_DEFAULT_CALLBACK((UConverterToUCallback) UCNV_TO_U_CALLBACK_SUBSTITUTE)) {
579 UConverterToUnicodeArgs toUArgs = {
580 sizeof(UConverterToUnicodeArgs),
581 true,
582 nullptr,
583 nullptr,
584 nullptr,
585 nullptr,
586 nullptr,
587 nullptr
588 };
589 toUArgs.converter = converter;
590 errorCode = U_ZERO_ERROR;
591 converter->fromCharErrorBehaviour(converter->toUContext, &toUArgs, nullptr, 0, UCNV_RESET, &errorCode);
592 }
593 if(choice!=UCNV_RESET_TO_UNICODE && converter->fromUCharErrorBehaviour != UCNV_FROM_U_DEFAULT_CALLBACK((UConverterFromUCallback) UCNV_FROM_U_CALLBACK_SUBSTITUTE)) {
594 UConverterFromUnicodeArgs fromUArgs = {
595 sizeof(UConverterFromUnicodeArgs),
596 true,
597 nullptr,
598 nullptr,
599 nullptr,
600 nullptr,
601 nullptr,
602 nullptr
603 };
604 fromUArgs.converter = converter;
605 errorCode = U_ZERO_ERROR;
606 converter->fromUCharErrorBehaviour(converter->fromUContext, &fromUArgs, nullptr, 0, 0, UCNV_RESET, &errorCode);
607 }
608 }
609
610 /* now reset the converter itself */
611 if(choice<=UCNV_RESET_TO_UNICODE) {
612 converter->toUnicodeStatus = converter->sharedData->toUnicodeStatus;
613 converter->mode = 0;
614 converter->toULength = 0;
615 converter->invalidCharLength = converter->UCharErrorBufferLength = 0;
616 converter->preToULength = 0;
617 }
618 if(choice!=UCNV_RESET_TO_UNICODE) {
619 converter->fromUnicodeStatus = 0;
620 converter->fromUChar32 = 0;
621 converter->invalidUCharLength = converter->charErrorBufferLength = 0;
622 converter->preFromUFirstCP = U_SENTINEL(-1);
623 converter->preFromULength = 0;
624 }
625
626 if (converter->sharedData->impl->reset != nullptr) {
627 /* call the custom reset function */
628 converter->sharedData->impl->reset(converter, choice);
629 }
630}
631
632U_CAPIextern "C" void U_EXPORT2
633ucnv_reset(UConverter *converter)
634{
635 _reset(converter, UCNV_RESET_BOTH, true);
636}
637
638U_CAPIextern "C" void U_EXPORT2
639ucnv_resetToUnicode(UConverter *converter)
640{
641 _reset(converter, UCNV_RESET_TO_UNICODE, true);
642}
643
644U_CAPIextern "C" void U_EXPORT2
645ucnv_resetFromUnicode(UConverter *converter)
646{
647 _reset(converter, UCNV_RESET_FROM_UNICODE, true);
648}
649
650U_CAPIextern "C" int8_t U_EXPORT2
651ucnv_getMaxCharSize (const UConverter * converter)
652{
653 return converter->maxBytesPerUChar;
654}
655
656
657U_CAPIextern "C" int8_t U_EXPORT2
658ucnv_getMinCharSize (const UConverter * converter)
659{
660 return converter->sharedData->staticData->minBytesPerChar;
661}
662
663U_CAPIextern "C" const char* U_EXPORT2
664ucnv_getName (const UConverter * converter, UErrorCode * err)
665
666{
667 if (U_FAILURE (*err))
668 return nullptr;
669 if(converter->sharedData->impl->getName){
670 const char* temp= converter->sharedData->impl->getName(converter);
671 if(temp)
672 return temp;
673 }
674 return converter->sharedData->staticData->name;
675}
676
677U_CAPIextern "C" int32_t U_EXPORT2
678ucnv_getCCSID(const UConverter * converter,
679 UErrorCode * err)
680{
681 int32_t ccsid;
682 if (U_FAILURE (*err))
683 return -1;
684
685 ccsid = converter->sharedData->staticData->codepage;
686 if (ccsid == 0) {
687 /* Rare case. This is for cases like gb18030,
688 which doesn't have an IBM canonical name, but does have an IBM alias. */
689 const char *standardName = ucnv_getStandardName(ucnv_getName(converter, err), "IBM", err);
690 if (U_SUCCESS(*err) && standardName) {
691 const char *ccsidStr = uprv_strchr(standardName, '-'):: strchr(standardName, '-');
692 if (ccsidStr) {
693 ccsid = (int32_t)atol(ccsidStr+1); /* +1 to skip '-' */
694 }
695 }
696 }
697 return ccsid;
698}
699
700
701U_CAPIextern "C" UConverterPlatform U_EXPORT2
702ucnv_getPlatform (const UConverter * converter,
703 UErrorCode * err)
704{
705 if (U_FAILURE (*err))
706 return UCNV_UNKNOWN;
707
708 return (UConverterPlatform)converter->sharedData->staticData->platform;
709}
710
711U_CAPIextern "C" void U_EXPORT2
712 ucnv_getToUCallBack (const UConverter * converter,
713 UConverterToUCallback *action,
714 const void **context)
715{
716 *action = converter->fromCharErrorBehaviour;
717 *context = converter->toUContext;
718}
719
720U_CAPIextern "C" void U_EXPORT2
721 ucnv_getFromUCallBack (const UConverter * converter,
722 UConverterFromUCallback *action,
723 const void **context)
724{
725 *action = converter->fromUCharErrorBehaviour;
726 *context = converter->fromUContext;
727}
728
729U_CAPIextern "C" void U_EXPORT2
730ucnv_setToUCallBack (UConverter * converter,
731 UConverterToUCallback newAction,
732 const void* newContext,
733 UConverterToUCallback *oldAction,
734 const void** oldContext,
735 UErrorCode * err)
736{
737 if (U_FAILURE (*err))
738 return;
739 if (oldAction) *oldAction = converter->fromCharErrorBehaviour;
740 converter->fromCharErrorBehaviour = newAction;
741 if (oldContext) *oldContext = converter->toUContext;
742 converter->toUContext = newContext;
743}
744
745U_CAPIextern "C" void U_EXPORT2
746ucnv_setFromUCallBack (UConverter * converter,
747 UConverterFromUCallback newAction,
748 const void* newContext,
749 UConverterFromUCallback *oldAction,
750 const void** oldContext,
751 UErrorCode * err)
752{
753 if (U_FAILURE (*err))
754 return;
755 if (oldAction) *oldAction = converter->fromUCharErrorBehaviour;
756 converter->fromUCharErrorBehaviour = newAction;
757 if (oldContext) *oldContext = converter->fromUContext;
758 converter->fromUContext = newContext;
759}
760
761static void
762_updateOffsets(int32_t *offsets, int32_t length,
763 int32_t sourceIndex, int32_t errorInputLength) {
764 int32_t *limit;
765 int32_t delta, offset;
766
767 if(sourceIndex>=0) {
768 /*
769 * adjust each offset by adding the previous sourceIndex
770 * minus the length of the input sequence that caused an
771 * error, if any
772 */
773 delta=sourceIndex-errorInputLength;
774 } else {
775 /*
776 * set each offset to -1 because this conversion function
777 * does not handle offsets
778 */
779 delta=-1;
780 }
781
782 limit=offsets+length;
783 if(delta==0) {
784 /* most common case, nothing to do */
785 } else if(delta>0) {
786 /* add the delta to each offset (but not if the offset is <0) */
787 while(offsets<limit) {
788 offset=*offsets;
789 if(offset>=0) {
790 *offsets=offset+delta;
791 }
792 ++offsets;
793 }
794 } else /* delta<0 */ {
795 /*
796 * set each offset to -1 because this conversion function
797 * does not handle offsets
798 * or the error input sequence started in a previous buffer
799 */
800 while(offsets<limit) {
801 *offsets++=-1;
802 }
803 }
804}
805
806/* ucnv_fromUnicode --------------------------------------------------------- */
807
808/*
809 * Implementation note for m:n conversions
810 *
811 * While collecting source units to find the longest match for m:n conversion,
812 * some source units may need to be stored for a partial match.
813 * When a second buffer does not yield a match on all of the previously stored
814 * source units, then they must be "replayed", i.e., fed back into the converter.
815 *
816 * The code relies on the fact that replaying will not nest -
817 * converting a replay buffer will not result in a replay.
818 * This is because a replay is necessary only after the _continuation_ of a
819 * partial match failed, but a replay buffer is converted as a whole.
820 * It may result in some of its units being stored again for a partial match,
821 * but there will not be a continuation _during_ the replay which could fail.
822 *
823 * It is conceivable that a callback function could call the converter
824 * recursively in a way that causes another replay to be stored, but that
825 * would be an error in the callback function.
826 * Such violations will cause assertion failures in a debug build,
827 * and wrong output, but they will not cause a crash.
828 */
829
830static void
831_fromUnicodeWithCallback(UConverterFromUnicodeArgs *pArgs, UErrorCode *err) {
832 UConverterFromUnicode fromUnicode;
833 UConverter *cnv;
834 const char16_t *s;
835 char *t;
836 int32_t *offsets;
837 int32_t sourceIndex;
838 int32_t errorInputLength;
839 UBool converterSawEndOfInput, calledCallback;
840
841 /* variables for m:n conversion */
842 char16_t replay[UCNV_EXT_MAX_UCHARS19];
843 const char16_t *realSource, *realSourceLimit;
844 int32_t realSourceIndex;
845 UBool realFlush;
846
847 cnv=pArgs->converter;
848 s=pArgs->source;
849 t=pArgs->target;
850 offsets=pArgs->offsets;
851
852 /* get the converter implementation function */
853 sourceIndex=0;
854 if(offsets==nullptr) {
855 fromUnicode=cnv->sharedData->impl->fromUnicode;
856 } else {
857 fromUnicode=cnv->sharedData->impl->fromUnicodeWithOffsets;
858 if(fromUnicode==nullptr) {
859 /* there is no WithOffsets implementation */
860 fromUnicode=cnv->sharedData->impl->fromUnicode;
861 /* we will write -1 for each offset */
862 sourceIndex=-1;
863 }
864 }
865
866 if(cnv->preFromULength>=0) {
867 /* normal mode */
868 realSource=nullptr;
869
870 /* avoid compiler warnings - not otherwise necessary, and the values do not matter */
871 realSourceLimit=nullptr;
872 realFlush=false;
873 realSourceIndex=0;
874 } else {
875 /*
876 * Previous m:n conversion stored source units from a partial match
877 * and failed to consume all of them.
878 * We need to "replay" them from a temporary buffer and convert them first.
879 */
880 realSource=pArgs->source;
881 realSourceLimit=pArgs->sourceLimit;
882 realFlush=pArgs->flush;
883 realSourceIndex=sourceIndex;
884
885 uprv_memcpy(replay, cnv->preFromU, -cnv->preFromULength*U_SIZEOF_UCHAR)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (replay != __null) ? void (0) : __assert_fail
("replay != __null", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__)); (static_cast <bool> (cnv->preFromU
!= __null) ? void (0) : __assert_fail ("cnv->preFromU != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); clang diagnostic pop :: memcpy(replay, cnv->preFromU,
-cnv->preFromULength*2); } while (false)
;
886 pArgs->source=replay;
887 pArgs->sourceLimit=replay-cnv->preFromULength;
888 pArgs->flush=false;
889 sourceIndex=-1;
890
891 cnv->preFromULength=0;
892 }
893
894 /*
895 * loop for conversion and error handling
896 *
897 * loop {
898 * convert
899 * loop {
900 * update offsets
901 * handle end of input
902 * handle errors/call callback
903 * }
904 * }
905 */
906 for(;;) {
907 if(U_SUCCESS(*err)) {
908 /* convert */
909 fromUnicode(pArgs, err);
910
911 /*
912 * set a flag for whether the converter
913 * successfully processed the end of the input
914 *
915 * need not check cnv->preFromULength==0 because a replay (<0) will cause
916 * s<sourceLimit before converterSawEndOfInput is checked
917 */
918 converterSawEndOfInput=
919 static_cast<UBool>(U_SUCCESS(*err) &&
920 pArgs->flush && pArgs->source==pArgs->sourceLimit &&
921 cnv->fromUChar32==0);
922 } else {
923 /* handle error from ucnv_convertEx() */
924 converterSawEndOfInput=false;
925 }
926
927 /* no callback called yet for this iteration */
928 calledCallback=false;
929
930 /* no sourceIndex adjustment for conversion, only for callback output */
931 errorInputLength=0;
932
933 /*
934 * loop for offsets and error handling
935 *
936 * iterates at most 3 times:
937 * 1. to clean up after the conversion function
938 * 2. after the callback
939 * 3. after the callback again if there was truncated input
940 */
941 for(;;) {
942 /* update offsets if we write any */
943 if(offsets!=nullptr) {
944 int32_t length = static_cast<int32_t>(pArgs->target - t);
945 if(length>0) {
946 _updateOffsets(offsets, length, sourceIndex, errorInputLength);
947
948 /*
949 * if a converter handles offsets and updates the offsets
950 * pointer at the end, then pArgs->offset should not change
951 * here;
952 * however, some converters do not handle offsets at all
953 * (sourceIndex<0) or may not update the offsets pointer
954 */
955 pArgs->offsets=offsets+=length;
956 }
957
958 if(sourceIndex>=0) {
959 sourceIndex += static_cast<int32_t>(pArgs->source - s);
960 }
961 }
962
963 if(cnv->preFromULength<0) {
964 /*
965 * switch the source to new replay units (cannot occur while replaying)
966 * after offset handling and before end-of-input and callback handling
967 */
968 if(realSource==nullptr) {
969 realSource=pArgs->source;
970 realSourceLimit=pArgs->sourceLimit;
971 realFlush=pArgs->flush;
972 realSourceIndex=sourceIndex;
973
974 uprv_memcpy(replay, cnv->preFromU, -cnv->preFromULength*U_SIZEOF_UCHAR)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (replay != __null) ? void (0) : __assert_fail
("replay != __null", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__)); (static_cast <bool> (cnv->preFromU
!= __null) ? void (0) : __assert_fail ("cnv->preFromU != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); clang diagnostic pop :: memcpy(replay, cnv->preFromU,
-cnv->preFromULength*2); } while (false)
;
975 pArgs->source=replay;
976 pArgs->sourceLimit=replay-cnv->preFromULength;
977 pArgs->flush=false;
978 if((sourceIndex+=cnv->preFromULength)<0) {
979 sourceIndex=-1;
980 }
981
982 cnv->preFromULength=0;
983 } else {
984 /* see implementation note before _fromUnicodeWithCallback() */
985 U_ASSERT(realSource==nullptr)(static_cast <bool> (realSource==nullptr) ? void (0) : __assert_fail
("realSource==nullptr", __builtin_FILE (), __builtin_LINE ()
, __extension__ __PRETTY_FUNCTION__))
;
986 *err=U_INTERNAL_PROGRAM_ERROR;
987 }
988 }
989
990 /* update pointers */
991 s=pArgs->source;
992 t=pArgs->target;
993
994 if(U_SUCCESS(*err)) {
995 if(s<pArgs->sourceLimit) {
996 /*
997 * continue with the conversion loop while there is still input left
998 * (continue converting by breaking out of only the inner loop)
999 */
1000 break;
1001 } else if(realSource!=nullptr) {
1002 /* switch back from replaying to the real source and continue */
1003 pArgs->source=realSource;
1004 pArgs->sourceLimit=realSourceLimit;
1005 pArgs->flush=realFlush;
1006 sourceIndex=realSourceIndex;
1007
1008 realSource=nullptr;
1009 break;
1010 } else if(pArgs->flush && cnv->fromUChar32!=0) {
1011 /*
1012 * the entire input stream is consumed
1013 * and there is a partial, truncated input sequence left
1014 */
1015
1016 /* inject an error and continue with callback handling */
1017 *err=U_TRUNCATED_CHAR_FOUND;
1018 calledCallback=false; /* new error condition */
1019 } else {
1020 /* input consumed */
1021 if(pArgs->flush) {
1022 /*
1023 * return to the conversion loop once more if the flush
1024 * flag is set and the conversion function has not
1025 * successfully processed the end of the input yet
1026 *
1027 * (continue converting by breaking out of only the inner loop)
1028 */
1029 if(!converterSawEndOfInput) {
1030 break;
1031 }
1032
1033 /* reset the converter without calling the callback function */
1034 _reset(cnv, UCNV_RESET_FROM_UNICODE, false);
1035 }
1036
1037 /* done successfully */
1038 return;
1039 }
1040 }
1041
1042 /* U_FAILURE(*err) */
1043 {
1044 UErrorCode e;
1045
1046 if( calledCallback ||
1047 (e=*err)==U_BUFFER_OVERFLOW_ERROR ||
1048 (e!=U_INVALID_CHAR_FOUND &&
1049 e!=U_ILLEGAL_CHAR_FOUND &&
1050 e!=U_TRUNCATED_CHAR_FOUND)
1051 ) {
1052 /*
1053 * the callback did not or cannot resolve the error:
1054 * set output pointers and return
1055 *
1056 * the check for buffer overflow is redundant but it is
1057 * a high-runner case and hopefully documents the intent
1058 * well
1059 *
1060 * if we were replaying, then the replay buffer must be
1061 * copied back into the UConverter
1062 * and the real arguments must be restored
1063 */
1064 if(realSource!=nullptr) {
1065 int32_t length;
1066
1067 U_ASSERT(cnv->preFromULength==0)(static_cast <bool> (cnv->preFromULength==0) ? void (
0) : __assert_fail ("cnv->preFromULength==0", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
1068
1069 length = static_cast<int32_t>(pArgs->sourceLimit - pArgs->source);
1070 if(length>0) {
1071 u_memcpy(cnv->preFromU, pArgs->source, length);
1072 cnv->preFromULength = static_cast<int8_t>(-length);
1073 }
1074
1075 pArgs->source=realSource;
1076 pArgs->sourceLimit=realSourceLimit;
1077 pArgs->flush=realFlush;
1078 }
1079
1080 return;
1081 }
1082 }
1083
1084 /* callback handling */
1085 {
1086 UChar32 codePoint;
1087
1088 /* get and write the code point */
1089 codePoint=cnv->fromUChar32;
1090 errorInputLength=0;
1091 U16_APPEND_UNSAFE(cnv->invalidUCharBuffer, errorInputLength, codePoint)do { if((uint32_t)(codePoint)<=0xffff) { (cnv->invalidUCharBuffer
)[(errorInputLength)++]=(uint16_t)(codePoint); } else { (cnv->
invalidUCharBuffer)[(errorInputLength)++]=(uint16_t)(((codePoint
)>>10)+0xd7c0); (cnv->invalidUCharBuffer)[(errorInputLength
)++]=(uint16_t)(((codePoint)&0x3ff)|0xdc00); } } while (false
)
;
1092 cnv->invalidUCharLength = static_cast<int8_t>(errorInputLength);
1093
1094 /* set the converter state to deal with the next character */
1095 cnv->fromUChar32=0;
1096
1097 /* call the callback function */
1098 cnv->fromUCharErrorBehaviour(cnv->fromUContext, pArgs,
1099 cnv->invalidUCharBuffer, errorInputLength, codePoint,
1100 *err==U_INVALID_CHAR_FOUND ? UCNV_UNASSIGNED : UCNV_ILLEGAL,
1101 err);
1102 }
1103
1104 /*
1105 * loop back to the offset handling
1106 *
1107 * this flag will indicate after offset handling
1108 * that a callback was called;
1109 * if the callback did not resolve the error, then we return
1110 */
1111 calledCallback=true;
1112 }
1113 }
1114}
1115
1116/*
1117 * Output the fromUnicode overflow buffer.
1118 * Call this function if(cnv->charErrorBufferLength>0).
1119 * @return true if overflow
1120 */
1121static UBool
1122ucnv_outputOverflowFromUnicode(UConverter *cnv,
1123 char **target, const char *targetLimit,
1124 int32_t **pOffsets,
1125 UErrorCode *err) {
1126 int32_t *offsets;
1127 char *overflow, *t;
1128 int32_t i, length;
1129
1130 t=*target;
1131 if(pOffsets!=nullptr) {
1132 offsets=*pOffsets;
1133 } else {
1134 offsets=nullptr;
1135 }
1136
1137 overflow = reinterpret_cast<char*>(cnv->charErrorBuffer);
1138 length=cnv->charErrorBufferLength;
1139 i=0;
1140 while(i<length) {
1141 if(t==targetLimit) {
1142 /* the overflow buffer contains too much, keep the rest */
1143 int32_t j=0;
1144
1145 do {
1146 overflow[j++]=overflow[i++];
1147 } while(i<length);
1148
1149 cnv->charErrorBufferLength = static_cast<int8_t>(j);
1150 *target=t;
1151 if(offsets!=nullptr) {
1152 *pOffsets=offsets;
1153 }
1154 *err=U_BUFFER_OVERFLOW_ERROR;
1155 return true;
1156 }
1157
1158 /* copy the overflow contents to the target */
1159 *t++=overflow[i++];
1160 if(offsets!=nullptr) {
1161 *offsets++=-1; /* no source index available for old output */
1162 }
1163 }
1164
1165 /* the overflow buffer is completely copied to the target */
1166 cnv->charErrorBufferLength=0;
1167 *target=t;
1168 if(offsets!=nullptr) {
1169 *pOffsets=offsets;
1170 }
1171 return false;
1172}
1173
1174U_CAPIextern "C" void U_EXPORT2
1175ucnv_fromUnicode(UConverter *cnv,
1176 char **target, const char *targetLimit,
1177 const char16_t **source, const char16_t *sourceLimit,
1178 int32_t *offsets,
1179 UBool flush,
1180 UErrorCode *err) {
1181 UConverterFromUnicodeArgs args;
1182 const char16_t *s;
1183 char *t;
1184
1185 /* check parameters */
1186 if(err==nullptr || U_FAILURE(*err)) {
1187 return;
1188 }
1189
1190 if(cnv==nullptr || target==nullptr || source==nullptr) {
1191 *err=U_ILLEGAL_ARGUMENT_ERROR;
1192 return;
1193 }
1194
1195 s=*source;
1196 t=*target;
1197
1198 if ((const void *)U_MAX_PTR(sourceLimit)((void *)(((uintptr_t)(sourceLimit)+0x7fffffffu) > (uintptr_t
)(sourceLimit) ? ((uintptr_t)(sourceLimit)+0x7fffffffu) : (uintptr_t
)-1))
== (const void *)sourceLimit) {
1199 /*
1200 Prevent code from going into an infinite loop in case we do hit this
1201 limit. The limit pointer is expected to be on a char16_t * boundary.
1202 This also prevents the next argument check from failing.
1203 */
1204 sourceLimit = (const char16_t *)(((const char *)sourceLimit) - 1);
1205 }
1206
1207 /*
1208 * All these conditions should never happen.
1209 *
1210 * 1) Make sure that the limits are >= to the address source or target
1211 *
1212 * 2) Make sure that the buffer sizes do not exceed the number range for
1213 * int32_t because some functions use the size (in units or bytes)
1214 * rather than comparing pointers, and because offsets are int32_t values.
1215 *
1216 * size_t is guaranteed to be unsigned and large enough for the job.
1217 *
1218 * Return with an error instead of adjusting the limits because we would
1219 * not be able to maintain the semantics that either the source must be
1220 * consumed or the target filled (unless an error occurs).
1221 * An adjustment would be targetLimit=t+0x7fffffff; for example.
1222 *
1223 * 3) Make sure that the user didn't incorrectly cast a char16_t * pointer
1224 * to a char * pointer and provide an incomplete char16_t code unit.
1225 */
1226 if (sourceLimit<s || targetLimit<t ||
1227 ((size_t)(sourceLimit-s)>(size_t)0x3fffffff && sourceLimit>s) ||
1228 ((size_t)(targetLimit-t)>(size_t)0x7fffffff && targetLimit>t) ||
1229 (((const char *)sourceLimit-(const char *)s) & 1) != 0)
1230 {
1231 *err=U_ILLEGAL_ARGUMENT_ERROR;
1232 return;
1233 }
1234
1235 /* output the target overflow buffer */
1236 if( cnv->charErrorBufferLength>0 &&
1237 ucnv_outputOverflowFromUnicode(cnv, target, targetLimit, &offsets, err)
1238 ) {
1239 /* U_BUFFER_OVERFLOW_ERROR */
1240 return;
1241 }
1242 /* *target may have moved, therefore stop using t */
1243
1244 if(!flush && s==sourceLimit && cnv->preFromULength>=0) {
1245 /* the overflow buffer is emptied and there is no new input: we are done */
1246 return;
1247 }
1248
1249 /*
1250 * Do not simply return with a buffer overflow error if
1251 * !flush && t==targetLimit
1252 * because it is possible that the source will not generate any output.
1253 * For example, the skip callback may be called;
1254 * it does not output anything.
1255 */
1256
1257 /* prepare the converter arguments */
1258 args.converter=cnv;
1259 args.flush=flush;
1260 args.offsets=offsets;
1261 args.source=s;
1262 args.sourceLimit=sourceLimit;
1263 args.target=*target;
1264 args.targetLimit=targetLimit;
1265 args.size=sizeof(args);
1266
1267 _fromUnicodeWithCallback(&args, err);
1268
1269 *source=args.source;
1270 *target=args.target;
1271}
1272
1273/* ucnv_toUnicode() --------------------------------------------------------- */
1274
1275static void
1276_toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
1277 UConverterToUnicode toUnicode;
1278 UConverter *cnv;
1279 const char *s;
1280 char16_t *t;
1281 int32_t *offsets;
1282 int32_t sourceIndex;
1283 int32_t errorInputLength;
1284 UBool converterSawEndOfInput, calledCallback;
1285
1286 /* variables for m:n conversion */
1287 char replay[UCNV_EXT_MAX_BYTES0x1f];
1288 const char *realSource, *realSourceLimit;
1289 int32_t realSourceIndex;
1290 UBool realFlush;
1291
1292 cnv=pArgs->converter;
1293 s=pArgs->source;
1294 t=pArgs->target;
1295 offsets=pArgs->offsets;
1296
1297 /* get the converter implementation function */
1298 sourceIndex=0;
1299 if(offsets==nullptr) {
1300 toUnicode=cnv->sharedData->impl->toUnicode;
1301 } else {
1302 toUnicode=cnv->sharedData->impl->toUnicodeWithOffsets;
1303 if(toUnicode==nullptr) {
1304 /* there is no WithOffsets implementation */
1305 toUnicode=cnv->sharedData->impl->toUnicode;
1306 /* we will write -1 for each offset */
1307 sourceIndex=-1;
1308 }
1309 }
1310
1311 if(cnv->preToULength>=0) {
1312 /* normal mode */
1313 realSource=nullptr;
1314
1315 /* avoid compiler warnings - not otherwise necessary, and the values do not matter */
1316 realSourceLimit=nullptr;
1317 realFlush=false;
1318 realSourceIndex=0;
1319 } else {
1320 /*
1321 * Previous m:n conversion stored source units from a partial match
1322 * and failed to consume all of them.
1323 * We need to "replay" them from a temporary buffer and convert them first.
1324 */
1325 realSource=pArgs->source;
1326 realSourceLimit=pArgs->sourceLimit;
1327 realFlush=pArgs->flush;
1328 realSourceIndex=sourceIndex;
1329
1330 uprv_memcpy(replay, cnv->preToU, -cnv->preToULength)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (replay != __null) ? void (0) : __assert_fail
("replay != __null", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__)); (static_cast <bool> (cnv->preToU
!= __null) ? void (0) : __assert_fail ("cnv->preToU != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); clang diagnostic pop :: memcpy(replay, cnv->preToU, -
cnv->preToULength); } while (false)
;
1331 pArgs->source=replay;
1332 pArgs->sourceLimit=replay-cnv->preToULength;
1333 pArgs->flush=false;
1334 sourceIndex=-1;
1335
1336 cnv->preToULength=0;
1337 }
1338
1339 /*
1340 * loop for conversion and error handling
1341 *
1342 * loop {
1343 * convert
1344 * loop {
1345 * update offsets
1346 * handle end of input
1347 * handle errors/call callback
1348 * }
1349 * }
1350 */
1351 for(;;) {
1352 if(U_SUCCESS(*err)) {
1353 /* convert */
1354 toUnicode(pArgs, err);
1355
1356 /*
1357 * set a flag for whether the converter
1358 * successfully processed the end of the input
1359 *
1360 * need not check cnv->preToULength==0 because a replay (<0) will cause
1361 * s<sourceLimit before converterSawEndOfInput is checked
1362 */
1363 converterSawEndOfInput=
1364 static_cast<UBool>(U_SUCCESS(*err) &&
1365 pArgs->flush && pArgs->source==pArgs->sourceLimit &&
1366 cnv->toULength==0);
1367 } else {
1368 /* handle error from getNextUChar() or ucnv_convertEx() */
1369 converterSawEndOfInput=false;
1370 }
1371
1372 /* no callback called yet for this iteration */
1373 calledCallback=false;
1374
1375 /* no sourceIndex adjustment for conversion, only for callback output */
1376 errorInputLength=0;
1377
1378 /*
1379 * loop for offsets and error handling
1380 *
1381 * iterates at most 3 times:
1382 * 1. to clean up after the conversion function
1383 * 2. after the callback
1384 * 3. after the callback again if there was truncated input
1385 */
1386 for(;;) {
1387 /* update offsets if we write any */
1388 if(offsets!=nullptr) {
1389 int32_t length = static_cast<int32_t>(pArgs->target - t);
1390 if(length>0) {
1391 _updateOffsets(offsets, length, sourceIndex, errorInputLength);
1392
1393 /*
1394 * if a converter handles offsets and updates the offsets
1395 * pointer at the end, then pArgs->offset should not change
1396 * here;
1397 * however, some converters do not handle offsets at all
1398 * (sourceIndex<0) or may not update the offsets pointer
1399 */
1400 pArgs->offsets=offsets+=length;
1401 }
1402
1403 if(sourceIndex>=0) {
1404 sourceIndex += static_cast<int32_t>(pArgs->source - s);
1405 }
1406 }
1407
1408 if(cnv->preToULength<0) {
1409 /*
1410 * switch the source to new replay units (cannot occur while replaying)
1411 * after offset handling and before end-of-input and callback handling
1412 */
1413 if(realSource==nullptr) {
1414 realSource=pArgs->source;
1415 realSourceLimit=pArgs->sourceLimit;
1416 realFlush=pArgs->flush;
1417 realSourceIndex=sourceIndex;
1418
1419 uprv_memcpy(replay, cnv->preToU, -cnv->preToULength)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (replay != __null) ? void (0) : __assert_fail
("replay != __null", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__)); (static_cast <bool> (cnv->preToU
!= __null) ? void (0) : __assert_fail ("cnv->preToU != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); clang diagnostic pop :: memcpy(replay, cnv->preToU, -
cnv->preToULength); } while (false)
;
1420 pArgs->source=replay;
1421 pArgs->sourceLimit=replay-cnv->preToULength;
1422 pArgs->flush=false;
1423 if((sourceIndex+=cnv->preToULength)<0) {
1424 sourceIndex=-1;
1425 }
1426
1427 cnv->preToULength=0;
1428 } else {
1429 /* see implementation note before _fromUnicodeWithCallback() */
1430 U_ASSERT(realSource==nullptr)(static_cast <bool> (realSource==nullptr) ? void (0) : __assert_fail
("realSource==nullptr", __builtin_FILE (), __builtin_LINE ()
, __extension__ __PRETTY_FUNCTION__))
;
1431 *err=U_INTERNAL_PROGRAM_ERROR;
1432 }
1433 }
1434
1435 /* update pointers */
1436 s=pArgs->source;
1437 t=pArgs->target;
1438
1439 if(U_SUCCESS(*err)) {
1440 if(s<pArgs->sourceLimit) {
1441 /*
1442 * continue with the conversion loop while there is still input left
1443 * (continue converting by breaking out of only the inner loop)
1444 */
1445 break;
1446 } else if(realSource!=nullptr) {
1447 /* switch back from replaying to the real source and continue */
1448 pArgs->source=realSource;
1449 pArgs->sourceLimit=realSourceLimit;
1450 pArgs->flush=realFlush;
1451 sourceIndex=realSourceIndex;
1452
1453 realSource=nullptr;
1454 break;
1455 } else if(pArgs->flush && cnv->toULength>0) {
1456 /*
1457 * the entire input stream is consumed
1458 * and there is a partial, truncated input sequence left
1459 */
1460
1461 /* inject an error and continue with callback handling */
1462 *err=U_TRUNCATED_CHAR_FOUND;
1463 calledCallback=false; /* new error condition */
1464 } else {
1465 /* input consumed */
1466 if(pArgs->flush) {
1467 /*
1468 * return to the conversion loop once more if the flush
1469 * flag is set and the conversion function has not
1470 * successfully processed the end of the input yet
1471 *
1472 * (continue converting by breaking out of only the inner loop)
1473 */
1474 if(!converterSawEndOfInput) {
1475 break;
1476 }
1477
1478 /* reset the converter without calling the callback function */
1479 _reset(cnv, UCNV_RESET_TO_UNICODE, false);
1480 }
1481
1482 /* done successfully */
1483 return;
1484 }
1485 }
1486
1487 /* U_FAILURE(*err) */
1488 {
1489 UErrorCode e;
1490
1491 if( calledCallback ||
1492 (e=*err)==U_BUFFER_OVERFLOW_ERROR ||
1493 (e!=U_INVALID_CHAR_FOUND &&
1494 e!=U_ILLEGAL_CHAR_FOUND &&
1495 e!=U_TRUNCATED_CHAR_FOUND &&
1496 e!=U_ILLEGAL_ESCAPE_SEQUENCE &&
1497 e!=U_UNSUPPORTED_ESCAPE_SEQUENCE)
1498 ) {
1499 /*
1500 * the callback did not or cannot resolve the error:
1501 * set output pointers and return
1502 *
1503 * the check for buffer overflow is redundant but it is
1504 * a high-runner case and hopefully documents the intent
1505 * well
1506 *
1507 * if we were replaying, then the replay buffer must be
1508 * copied back into the UConverter
1509 * and the real arguments must be restored
1510 */
1511 if(realSource!=nullptr) {
1512 int32_t length;
1513
1514 U_ASSERT(cnv->preToULength==0)(static_cast <bool> (cnv->preToULength==0) ? void (0
) : __assert_fail ("cnv->preToULength==0", __builtin_FILE (
), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
1515
1516 length = static_cast<int32_t>(pArgs->sourceLimit - pArgs->source);
1517 if(length>0) {
1518 uprv_memcpy(cnv->preToU, pArgs->source, length)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (cnv->preToU != __null) ? void
(0) : __assert_fail ("cnv->preToU != __null", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); (
static_cast <bool> (pArgs->source != __null) ? void (
0) : __assert_fail ("pArgs->source != __null", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); clang
diagnostic pop :: memcpy(cnv->preToU, pArgs->source, length
); } while (false)
;
1519 cnv->preToULength = static_cast<int8_t>(-length);
1520 }
1521
1522 pArgs->source=realSource;
1523 pArgs->sourceLimit=realSourceLimit;
1524 pArgs->flush=realFlush;
1525 }
1526
1527 return;
1528 }
1529 }
1530
1531 /* copy toUBytes[] to invalidCharBuffer[] */
1532 errorInputLength=cnv->invalidCharLength=cnv->toULength;
1533 if(errorInputLength>0) {
1534 uprv_memcpy(cnv->invalidCharBuffer, cnv->toUBytes, errorInputLength)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (cnv->invalidCharBuffer != __null
) ? void (0) : __assert_fail ("cnv->invalidCharBuffer != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); (static_cast <bool> (cnv->toUBytes != __null) ? void
(0) : __assert_fail ("cnv->toUBytes != __null", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); clang
diagnostic pop :: memcpy(cnv->invalidCharBuffer, cnv->
toUBytes, errorInputLength); } while (false)
;
1535 }
1536
1537 /* set the converter state to deal with the next character */
1538 cnv->toULength=0;
1539
1540 /* call the callback function */
1541 if(cnv->toUCallbackReason==UCNV_ILLEGAL && *err==U_INVALID_CHAR_FOUND) {
1542 cnv->toUCallbackReason = UCNV_UNASSIGNED;
1543 }
1544 cnv->fromCharErrorBehaviour(cnv->toUContext, pArgs,
1545 cnv->invalidCharBuffer, errorInputLength,
1546 cnv->toUCallbackReason,
1547 err);
1548 cnv->toUCallbackReason = UCNV_ILLEGAL; /* reset to default value */
1549
1550 /*
1551 * loop back to the offset handling
1552 *
1553 * this flag will indicate after offset handling
1554 * that a callback was called;
1555 * if the callback did not resolve the error, then we return
1556 */
1557 calledCallback=true;
1558 }
1559 }
1560}
1561
1562/*
1563 * Output the toUnicode overflow buffer.
1564 * Call this function if(cnv->UCharErrorBufferLength>0).
1565 * @return true if overflow
1566 */
1567static UBool
1568ucnv_outputOverflowToUnicode(UConverter *cnv,
1569 char16_t **target, const char16_t *targetLimit,
1570 int32_t **pOffsets,
1571 UErrorCode *err) {
1572 int32_t *offsets;
1573 char16_t *overflow, *t;
1574 int32_t i, length;
1575
1576 t=*target;
1577 if(pOffsets!=nullptr) {
1578 offsets=*pOffsets;
1579 } else {
1580 offsets=nullptr;
1581 }
1582
1583 overflow=cnv->UCharErrorBuffer;
1584 length=cnv->UCharErrorBufferLength;
1585 i=0;
1586 while(i<length) {
1587 if(t==targetLimit) {
1588 /* the overflow buffer contains too much, keep the rest */
1589 int32_t j=0;
1590
1591 do {
1592 overflow[j++]=overflow[i++];
1593 } while(i<length);
1594
1595 cnv->UCharErrorBufferLength = static_cast<int8_t>(j);
1596 *target=t;
1597 if(offsets!=nullptr) {
1598 *pOffsets=offsets;
1599 }
1600 *err=U_BUFFER_OVERFLOW_ERROR;
1601 return true;
1602 }
1603
1604 /* copy the overflow contents to the target */
1605 *t++=overflow[i++];
1606 if(offsets!=nullptr) {
1607 *offsets++=-1; /* no source index available for old output */
1608 }
1609 }
1610
1611 /* the overflow buffer is completely copied to the target */
1612 cnv->UCharErrorBufferLength=0;
1613 *target=t;
1614 if(offsets!=nullptr) {
1615 *pOffsets=offsets;
1616 }
1617 return false;
1618}
1619
1620U_CAPIextern "C" void U_EXPORT2
1621ucnv_toUnicode(UConverter *cnv,
1622 char16_t **target, const char16_t *targetLimit,
1623 const char **source, const char *sourceLimit,
1624 int32_t *offsets,
1625 UBool flush,
1626 UErrorCode *err) {
1627 UConverterToUnicodeArgs args;
1628 const char *s;
1629 char16_t *t;
1630
1631 /* check parameters */
1632 if(err==nullptr || U_FAILURE(*err)) {
1633 return;
1634 }
1635
1636 if(cnv==nullptr || target==nullptr || source==nullptr) {
1637 *err=U_ILLEGAL_ARGUMENT_ERROR;
1638 return;
1639 }
1640
1641 s=*source;
1642 t=*target;
1643
1644 if ((const void *)U_MAX_PTR(targetLimit)((void *)(((uintptr_t)(targetLimit)+0x7fffffffu) > (uintptr_t
)(targetLimit) ? ((uintptr_t)(targetLimit)+0x7fffffffu) : (uintptr_t
)-1))
== (const void *)targetLimit) {
1645 /*
1646 Prevent code from going into an infinite loop in case we do hit this
1647 limit. The limit pointer is expected to be on a char16_t * boundary.
1648 This also prevents the next argument check from failing.
1649 */
1650 targetLimit = (const char16_t *)(((const char *)targetLimit) - 1);
1651 }
1652
1653 /*
1654 * All these conditions should never happen.
1655 *
1656 * 1) Make sure that the limits are >= to the address source or target
1657 *
1658 * 2) Make sure that the buffer sizes do not exceed the number range for
1659 * int32_t because some functions use the size (in units or bytes)
1660 * rather than comparing pointers, and because offsets are int32_t values.
1661 *
1662 * size_t is guaranteed to be unsigned and large enough for the job.
1663 *
1664 * Return with an error instead of adjusting the limits because we would
1665 * not be able to maintain the semantics that either the source must be
1666 * consumed or the target filled (unless an error occurs).
1667 * An adjustment would be sourceLimit=t+0x7fffffff; for example.
1668 *
1669 * 3) Make sure that the user didn't incorrectly cast a char16_t * pointer
1670 * to a char * pointer and provide an incomplete char16_t code unit.
1671 */
1672 if (sourceLimit<s || targetLimit<t ||
1673 ((size_t)(sourceLimit-s)>(size_t)0x7fffffff && sourceLimit>s) ||
1674 ((size_t)(targetLimit-t)>(size_t)0x3fffffff && targetLimit>t) ||
1675 (((const char *)targetLimit-(const char *)t) & 1) != 0
1676 ) {
1677 *err=U_ILLEGAL_ARGUMENT_ERROR;
1678 return;
1679 }
1680
1681 /* output the target overflow buffer */
1682 if( cnv->UCharErrorBufferLength>0 &&
1683 ucnv_outputOverflowToUnicode(cnv, target, targetLimit, &offsets, err)
1684 ) {
1685 /* U_BUFFER_OVERFLOW_ERROR */
1686 return;
1687 }
1688 /* *target may have moved, therefore stop using t */
1689
1690 if(!flush && s==sourceLimit && cnv->preToULength>=0) {
1691 /* the overflow buffer is emptied and there is no new input: we are done */
1692 return;
1693 }
1694
1695 /*
1696 * Do not simply return with a buffer overflow error if
1697 * !flush && t==targetLimit
1698 * because it is possible that the source will not generate any output.
1699 * For example, the skip callback may be called;
1700 * it does not output anything.
1701 */
1702
1703 /* prepare the converter arguments */
1704 args.converter=cnv;
1705 args.flush=flush;
1706 args.offsets=offsets;
1707 args.source=s;
1708 args.sourceLimit=sourceLimit;
1709 args.target=*target;
1710 args.targetLimit=targetLimit;
1711 args.size=sizeof(args);
1712
1713 _toUnicodeWithCallback(&args, err);
1714
1715 *source=args.source;
1716 *target=args.target;
1717}
1718
1719/* ucnv_to/fromUChars() ----------------------------------------------------- */
1720
1721U_CAPIextern "C" int32_t U_EXPORT2
1722ucnv_fromUChars(UConverter *cnv,
1723 char *dest, int32_t destCapacity,
1724 const char16_t *src, int32_t srcLength,
1725 UErrorCode *pErrorCode) {
1726 const char16_t *srcLimit;
1727 char *originalDest, *destLimit;
1728 int32_t destLength;
1729
1730 /* check arguments */
1731 if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) {
1732 return 0;
1733 }
1734
1735 if( cnv==nullptr ||
1736 destCapacity<0 || (destCapacity>0 && dest==nullptr) ||
1737 srcLength<-1 || (srcLength!=0 && src==nullptr)
1738 ) {
1739 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
1740 return 0;
1741 }
1742
1743 /* initialize */
1744 ucnv_resetFromUnicode(cnv);
1745 originalDest=dest;
1746 if(srcLength==-1) {
1747 srcLength=u_strlen(src);
1748 }
1749 if(srcLength>0) {
1750 srcLimit=src+srcLength;
1751 destCapacity=pinCapacity(dest, destCapacity);
1752 destLimit=dest+destCapacity;
1753
1754 /* perform the conversion */
1755 UErrorCode bufferStatus = U_ZERO_ERROR;
1756 ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, nullptr, true, &bufferStatus);
1757 destLength=(int32_t)(dest-originalDest);
1758
1759 /* if an overflow occurs, then get the preflighting length */
1760 if(bufferStatus==U_BUFFER_OVERFLOW_ERROR) {
1761 char buffer[1024];
1762
1763 destLimit=buffer+sizeof(buffer);
1764 do {
1765 dest=buffer;
1766 bufferStatus=U_ZERO_ERROR;
1767 ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, nullptr, true, &bufferStatus);
1768 destLength+=(int32_t)(dest-buffer);
1769 } while(bufferStatus==U_BUFFER_OVERFLOW_ERROR);
1770 }
1771 if (U_FAILURE(bufferStatus)) {
1772 *pErrorCode = bufferStatus;
1773 }
1774 } else {
1775 destLength=0;
1776 }
1777
1778 return u_terminateChars(originalDest, destCapacity, destLength, pErrorCode);
1779}
1780
1781U_CAPIextern "C" int32_t U_EXPORT2
1782ucnv_toUChars(UConverter *cnv,
1783 char16_t *dest, int32_t destCapacity,
1784 const char *src, int32_t srcLength,
1785 UErrorCode *pErrorCode) {
1786 const char *srcLimit;
1787 char16_t *originalDest, *destLimit;
1788 int32_t destLength;
1789
1790 /* check arguments */
1791 if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) {
1792 return 0;
1793 }
1794
1795 if( cnv==nullptr ||
1796 destCapacity<0 || (destCapacity>0 && dest==nullptr) ||
1797 srcLength<-1 || (srcLength!=0 && src==nullptr))
1798 {
1799 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
1800 return 0;
1801 }
1802
1803 /* initialize */
1804 ucnv_resetToUnicode(cnv);
1805 originalDest=dest;
1806 if(srcLength==-1) {
1807 srcLength=(int32_t)uprv_strlen(src):: strlen(src);
1808 }
1809 if(srcLength>0) {
1810 srcLimit=src+srcLength;
1811 destCapacity=pinCapacity(dest, destCapacity);
1812 destLimit=dest+destCapacity;
1813
1814 /* perform the conversion */
1815 UErrorCode bufferStatus = U_ZERO_ERROR;
1816 ucnv_toUnicode(cnv, &dest, destLimit, &src, srcLimit, nullptr, true, &bufferStatus);
1817 destLength=(int32_t)(dest-originalDest);
1818
1819 /* if an overflow occurs, then get the preflighting length */
1820 if(bufferStatus==U_BUFFER_OVERFLOW_ERROR)
1821 {
1822 char16_t buffer[1024];
1823
1824 destLimit=buffer+UPRV_LENGTHOF(buffer)(int32_t)(sizeof(buffer)/sizeof((buffer)[0]));
1825 do {
1826 dest=buffer;
1827 bufferStatus=U_ZERO_ERROR;
1828 ucnv_toUnicode(cnv, &dest, destLimit, &src, srcLimit, nullptr, true, &bufferStatus);
1829 destLength+=(int32_t)(dest-buffer);
1830 }
1831 while(bufferStatus==U_BUFFER_OVERFLOW_ERROR);
1832 }
1833 if (U_FAILURE(bufferStatus)) {
1834 *pErrorCode = bufferStatus;
1835 }
1836 } else {
1837 destLength=0;
1838 }
1839
1840 return u_terminateUChars(originalDest, destCapacity, destLength, pErrorCode);
1841}
1842
1843/* ucnv_getNextUChar() ------------------------------------------------------ */
1844
1845U_CAPIextern "C" UChar32 U_EXPORT2
1846ucnv_getNextUChar(UConverter *cnv,
1847 const char **source, const char *sourceLimit,
1848 UErrorCode *err) {
1849 UConverterToUnicodeArgs args;
1850 char16_t buffer[U16_MAX_LENGTH2];
1851 const char *s;
1852 UChar32 c;
1853 int32_t i, length;
1854
1855 /* check parameters */
1856 if(err==nullptr || U_FAILURE(*err)) {
1857 return 0xffff;
1858 }
1859
1860 if(cnv==nullptr || source==nullptr) {
1861 *err=U_ILLEGAL_ARGUMENT_ERROR;
1862 return 0xffff;
1863 }
1864
1865 s=*source;
1866 if(sourceLimit<s) {
1867 *err=U_ILLEGAL_ARGUMENT_ERROR;
1868 return 0xffff;
1869 }
1870
1871 /*
1872 * Make sure that the buffer sizes do not exceed the number range for
1873 * int32_t because some functions use the size (in units or bytes)
1874 * rather than comparing pointers, and because offsets are int32_t values.
1875 *
1876 * size_t is guaranteed to be unsigned and large enough for the job.
1877 *
1878 * Return with an error instead of adjusting the limits because we would
1879 * not be able to maintain the semantics that either the source must be
1880 * consumed or the target filled (unless an error occurs).
1881 * An adjustment would be sourceLimit=t+0x7fffffff; for example.
1882 */
1883 if(((size_t)(sourceLimit-s)>(size_t)0x7fffffff && sourceLimit>s)) {
1884 *err=U_ILLEGAL_ARGUMENT_ERROR;
1885 return 0xffff;
1886 }
1887
1888 c=U_SENTINEL(-1);
1889
1890 /* flush the target overflow buffer */
1891 if(cnv->UCharErrorBufferLength>0) {
1892 char16_t *overflow;
1893
1894 overflow=cnv->UCharErrorBuffer;
1895 i=0;
1896 length=cnv->UCharErrorBufferLength;
1897 U16_NEXT(overflow, i, length, c)do { (c)=(overflow)[(i)++]; if((((c)&0xfffffc00)==0xd800)
) { uint16_t __c2; if((i)!=(length) && (((__c2=(overflow
)[(i)])&0xfffffc00)==0xdc00)) { ++(i); (c)=(((UChar32)((c
))<<10UL)+(UChar32)(__c2)-((0xd800<<10UL)+0xdc00-
0x10000)); } } } while (false)
;
1898
1899 /* move the remaining overflow contents up to the beginning */
1900 if((cnv->UCharErrorBufferLength=(int8_t)(length-i))>0) {
1901 uprv_memmove(cnv->UCharErrorBuffer, cnv->UCharErrorBuffer+i,do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (cnv->UCharErrorBuffer != __null
) ? void (0) : __assert_fail ("cnv->UCharErrorBuffer != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); (static_cast <bool> (cnv->UCharErrorBuffer+i != __null
) ? void (0) : __assert_fail ("cnv->UCharErrorBuffer+i != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); clang diagnostic pop :: memmove(cnv->UCharErrorBuffer
, cnv->UCharErrorBuffer+i, cnv->UCharErrorBufferLength*
2); } while (false)
1902 cnv->UCharErrorBufferLength*U_SIZEOF_UCHAR)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (cnv->UCharErrorBuffer != __null
) ? void (0) : __assert_fail ("cnv->UCharErrorBuffer != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); (static_cast <bool> (cnv->UCharErrorBuffer+i != __null
) ? void (0) : __assert_fail ("cnv->UCharErrorBuffer+i != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); clang diagnostic pop :: memmove(cnv->UCharErrorBuffer
, cnv->UCharErrorBuffer+i, cnv->UCharErrorBufferLength*
2); } while (false)
;
1903 }
1904
1905 if(!U16_IS_LEAD(c)(((c)&0xfffffc00)==0xd800) || i<length) {
1906 return c;
1907 }
1908 /*
1909 * Continue if the overflow buffer contained only a lead surrogate,
1910 * in case the converter outputs single surrogates from complete
1911 * input sequences.
1912 */
1913 }
1914
1915 /*
1916 * flush==true is implied for ucnv_getNextUChar()
1917 *
1918 * do not simply return even if s==sourceLimit because the converter may
1919 * not have seen flush==true before
1920 */
1921
1922 /* prepare the converter arguments */
1923 args.converter=cnv;
1924 args.flush=true;
1925 args.offsets=nullptr;
1926 args.source=s;
1927 args.sourceLimit=sourceLimit;
1928 args.target=buffer;
1929 args.targetLimit=buffer+1;
1930 args.size=sizeof(args);
1931
1932 if(c<0) {
1933 /*
1934 * call the native getNextUChar() implementation if we are
1935 * at a character boundary (toULength==0)
1936 *
1937 * unlike with _toUnicode(), getNextUChar() implementations must set
1938 * U_TRUNCATED_CHAR_FOUND for truncated input,
1939 * in addition to setting toULength/toUBytes[]
1940 */
1941 if(cnv->toULength==0 && cnv->sharedData->impl->getNextUChar!=nullptr) {
1942 c=cnv->sharedData->impl->getNextUChar(&args, err);
1943 *source=s=args.source;
Although the value stored to 's' is used in the enclosing expression, the value is never actually read from 's'
1944 if(*err==U_INDEX_OUTOFBOUNDS_ERROR) {
1945 /* reset the converter without calling the callback function */
1946 _reset(cnv, UCNV_RESET_TO_UNICODE, false);
1947 return 0xffff; /* no output */
1948 } else if(U_SUCCESS(*err) && c>=0) {
1949 return c;
1950 /*
1951 * else fall through to use _toUnicode() because
1952 * UCNV_GET_NEXT_UCHAR_USE_TO_U: the native function did not want to handle it after all
1953 * U_FAILURE: call _toUnicode() for callback handling (do not output c)
1954 */
1955 }
1956 }
1957
1958 /* convert to one char16_t in buffer[0], or handle getNextUChar() errors */
1959 _toUnicodeWithCallback(&args, err);
1960
1961 if(*err==U_BUFFER_OVERFLOW_ERROR) {
1962 *err=U_ZERO_ERROR;
1963 }
1964
1965 i=0;
1966 length=(int32_t)(args.target-buffer);
1967 } else {
1968 /* write the lead surrogate from the overflow buffer */
1969 buffer[0]=(char16_t)c;
1970 args.target=buffer+1;
1971 i=0;
1972 length=1;
1973 }
1974
1975 /* buffer contents starts at i and ends before length */
1976
1977 if(U_FAILURE(*err)) {
1978 c=0xffff; /* no output */
1979 } else if(length==0) {
1980 /* no input or only state changes */
1981 *err=U_INDEX_OUTOFBOUNDS_ERROR;
1982 /* no need to reset explicitly because _toUnicodeWithCallback() did it */
1983 c=0xffff; /* no output */
1984 } else {
1985 c=buffer[0];
1986 i=1;
1987 if(!U16_IS_LEAD(c)(((c)&0xfffffc00)==0xd800)) {
1988 /* consume c=buffer[0], done */
1989 } else {
1990 /* got a lead surrogate, see if a trail surrogate follows */
1991 char16_t c2;
1992
1993 if(cnv->UCharErrorBufferLength>0) {
1994 /* got overflow output from the conversion */
1995 if(U16_IS_TRAIL(c2=cnv->UCharErrorBuffer[0])(((c2=cnv->UCharErrorBuffer[0])&0xfffffc00)==0xdc00)) {
1996 /* got a trail surrogate, too */
1997 c=U16_GET_SUPPLEMENTARY(c, c2)(((UChar32)(c)<<10UL)+(UChar32)(c2)-((0xd800<<10UL
)+0xdc00-0x10000))
;
1998
1999 /* move the remaining overflow contents up to the beginning */
2000 if((--cnv->UCharErrorBufferLength)>0) {
2001 uprv_memmove(cnv->UCharErrorBuffer, cnv->UCharErrorBuffer+1,do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (cnv->UCharErrorBuffer != __null
) ? void (0) : __assert_fail ("cnv->UCharErrorBuffer != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); (static_cast <bool> (cnv->UCharErrorBuffer+1 != __null
) ? void (0) : __assert_fail ("cnv->UCharErrorBuffer+1 != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); clang diagnostic pop :: memmove(cnv->UCharErrorBuffer
, cnv->UCharErrorBuffer+1, cnv->UCharErrorBufferLength*
2); } while (false)
2002 cnv->UCharErrorBufferLength*U_SIZEOF_UCHAR)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (cnv->UCharErrorBuffer != __null
) ? void (0) : __assert_fail ("cnv->UCharErrorBuffer != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); (static_cast <bool> (cnv->UCharErrorBuffer+1 != __null
) ? void (0) : __assert_fail ("cnv->UCharErrorBuffer+1 != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); clang diagnostic pop :: memmove(cnv->UCharErrorBuffer
, cnv->UCharErrorBuffer+1, cnv->UCharErrorBufferLength*
2); } while (false)
;
2003 }
2004 } else {
2005 /* c is an unpaired lead surrogate, just return it */
2006 }
2007 } else if(args.source<sourceLimit) {
2008 /* convert once more, to buffer[1] */
2009 args.targetLimit=buffer+2;
2010 _toUnicodeWithCallback(&args, err);
2011 if(*err==U_BUFFER_OVERFLOW_ERROR) {
2012 *err=U_ZERO_ERROR;
2013 }
2014
2015 length=(int32_t)(args.target-buffer);
2016 if(U_SUCCESS(*err) && length==2 && U16_IS_TRAIL(c2=buffer[1])(((c2=buffer[1])&0xfffffc00)==0xdc00)) {
2017 /* got a trail surrogate, too */
2018 c=U16_GET_SUPPLEMENTARY(c, c2)(((UChar32)(c)<<10UL)+(UChar32)(c2)-((0xd800<<10UL
)+0xdc00-0x10000))
;
2019 i=2;
2020 }
2021 }
2022 }
2023 }
2024
2025 /*
2026 * move leftover output from buffer[i..length[
2027 * into the beginning of the overflow buffer
2028 */
2029 if(i<length) {
2030 /* move further overflow back */
2031 int32_t delta=length-i;
2032 if((length=cnv->UCharErrorBufferLength)>0) {
2033 uprv_memmove(cnv->UCharErrorBuffer+delta, cnv->UCharErrorBuffer,do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (cnv->UCharErrorBuffer+delta !=
__null) ? void (0) : __assert_fail ("cnv->UCharErrorBuffer+delta != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); (static_cast <bool> (cnv->UCharErrorBuffer != __null
) ? void (0) : __assert_fail ("cnv->UCharErrorBuffer != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); clang diagnostic pop :: memmove(cnv->UCharErrorBuffer
+delta, cnv->UCharErrorBuffer, length*2); } while (false)
2034 length*U_SIZEOF_UCHAR)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (cnv->UCharErrorBuffer+delta !=
__null) ? void (0) : __assert_fail ("cnv->UCharErrorBuffer+delta != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); (static_cast <bool> (cnv->UCharErrorBuffer != __null
) ? void (0) : __assert_fail ("cnv->UCharErrorBuffer != __null"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
)); clang diagnostic pop :: memmove(cnv->UCharErrorBuffer
+delta, cnv->UCharErrorBuffer, length*2); } while (false)
;
2035 }
2036 cnv->UCharErrorBufferLength=(int8_t)(length+delta);
2037
2038 cnv->UCharErrorBuffer[0]=buffer[i++];
2039 if(delta>1) {
2040 cnv->UCharErrorBuffer[1]=buffer[i];
2041 }
2042 }
2043
2044 *source=args.source;
2045 return c;
2046}
2047
2048/* ucnv_convert() and siblings ---------------------------------------------- */
2049
2050U_CAPIextern "C" void U_EXPORT2
2051ucnv_convertEx(UConverter *targetCnv, UConverter *sourceCnv,
2052 char **target, const char *targetLimit,
2053 const char **source, const char *sourceLimit,
2054 char16_t *pivotStart, char16_t **pivotSource,
2055 char16_t **pivotTarget, const char16_t *pivotLimit,
2056 UBool reset, UBool flush,
2057 UErrorCode *pErrorCode) {
2058 char16_t pivotBuffer[CHUNK_SIZE1024];
2059 const char16_t *myPivotSource;
2060 char16_t *myPivotTarget;
2061 const char *s;
2062 char *t;
2063
2064 UConverterToUnicodeArgs toUArgs;
2065 UConverterFromUnicodeArgs fromUArgs;
2066 UConverterConvert convert;
2067
2068 /* error checking */
2069 if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) {
2070 return;
2071 }
2072
2073 if( targetCnv==nullptr || sourceCnv==nullptr ||
2074 source==nullptr || *source==nullptr ||
2075 target==nullptr || *target==nullptr || targetLimit==nullptr
2076 ) {
2077 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2078 return;
2079 }
2080
2081 s=*source;
2082 t=*target;
2083 if((sourceLimit!=nullptr && sourceLimit<s) || targetLimit<t) {
2084 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2085 return;
2086 }
2087
2088 /*
2089 * Make sure that the buffer sizes do not exceed the number range for
2090 * int32_t. See ucnv_toUnicode() for a more detailed comment.
2091 */
2092 if(
2093 (sourceLimit!=nullptr && ((size_t)(sourceLimit-s)>(size_t)0x7fffffff && sourceLimit>s)) ||
2094 ((size_t)(targetLimit-t)>(size_t)0x7fffffff && targetLimit>t)
2095 ) {
2096 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2097 return;
2098 }
2099
2100 if(pivotStart==nullptr) {
2101 if(!flush) {
2102 /* streaming conversion requires an explicit pivot buffer */
2103 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2104 return;
2105 }
2106
2107 /* use the stack pivot buffer */
2108 myPivotSource=myPivotTarget=pivotStart=pivotBuffer;
2109 pivotSource=(char16_t **)&myPivotSource;
2110 pivotTarget=&myPivotTarget;
2111 pivotLimit=pivotBuffer+CHUNK_SIZE1024;
2112 } else if( pivotStart>=pivotLimit ||
2113 pivotSource==nullptr || *pivotSource==nullptr ||
2114 pivotTarget==nullptr || *pivotTarget==nullptr ||
2115 pivotLimit==nullptr
2116 ) {
2117 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2118 return;
2119 }
2120
2121 if(sourceLimit==nullptr) {
2122 /* get limit of single-byte-NUL-terminated source string */
2123 sourceLimit=uprv_strchr(*source, 0):: strchr(*source, 0);
2124 }
2125
2126 if(reset) {
2127 ucnv_resetToUnicode(sourceCnv);
2128 ucnv_resetFromUnicode(targetCnv);
2129 *pivotSource=*pivotTarget=pivotStart;
2130 } else if(targetCnv->charErrorBufferLength>0) {
2131 /* output the targetCnv overflow buffer */
2132 if(ucnv_outputOverflowFromUnicode(targetCnv, target, targetLimit, nullptr, pErrorCode)) {
2133 /* U_BUFFER_OVERFLOW_ERROR */
2134 return;
2135 }
2136 /* *target has moved, therefore stop using t */
2137
2138 if( !flush &&
2139 targetCnv->preFromULength>=0 && *pivotSource==*pivotTarget &&
2140 sourceCnv->UCharErrorBufferLength==0 && sourceCnv->preToULength>=0 && s==sourceLimit
2141 ) {
2142 /* the fromUnicode overflow buffer is emptied and there is no new input: we are done */
2143 return;
2144 }
2145 }
2146
2147 /* Is direct-UTF-8 conversion available? */
2148 if( sourceCnv->sharedData->staticData->conversionType==UCNV_UTF8 &&
2149 targetCnv->sharedData->impl->fromUTF8!=nullptr
2150 ) {
2151 convert=targetCnv->sharedData->impl->fromUTF8;
2152 } else if( targetCnv->sharedData->staticData->conversionType==UCNV_UTF8 &&
2153 sourceCnv->sharedData->impl->toUTF8!=nullptr
2154 ) {
2155 convert=sourceCnv->sharedData->impl->toUTF8;
2156 } else {
2157 convert=nullptr;
2158 }
2159
2160 /*
2161 * If direct-UTF-8 conversion is available, then we use a smaller
2162 * pivot buffer for error handling and partial matches
2163 * so that we quickly return to direct conversion.
2164 *
2165 * 32 is large enough for UCNV_EXT_MAX_UCHARS and UCNV_ERROR_BUFFER_LENGTH.
2166 *
2167 * We could reduce the pivot buffer size further, at the cost of
2168 * buffer overflows from callbacks.
2169 * The pivot buffer should not be smaller than the maximum number of
2170 * fromUnicode extension table input UChars
2171 * (for m:n conversion, see
2172 * targetCnv->sharedData->mbcs.extIndexes[UCNV_EXT_COUNT_UCHARS])
2173 * or 2 for surrogate pairs.
2174 *
2175 * Too small a buffer can cause thrashing between pivoting and direct
2176 * conversion, with function call overhead outweighing the benefits
2177 * of direct conversion.
2178 */
2179 if(convert!=nullptr && (pivotLimit-pivotStart)>32) {
2180 pivotLimit=pivotStart+32;
2181 }
2182
2183 /* prepare the converter arguments */
2184 fromUArgs.converter=targetCnv;
2185 fromUArgs.flush=false;
2186 fromUArgs.offsets=nullptr;
2187 fromUArgs.target=*target;
2188 fromUArgs.targetLimit=targetLimit;
2189 fromUArgs.size=sizeof(fromUArgs);
2190
2191 toUArgs.converter=sourceCnv;
2192 toUArgs.flush=flush;
2193 toUArgs.offsets=nullptr;
2194 toUArgs.source=s;
2195 toUArgs.sourceLimit=sourceLimit;
2196 toUArgs.targetLimit=pivotLimit;
2197 toUArgs.size=sizeof(toUArgs);
2198
2199 /*
2200 * TODO: Consider separating this function into two functions,
2201 * extracting exactly the conversion loop,
2202 * for readability and to reduce the set of visible variables.
2203 *
2204 * Otherwise stop using s and t from here on.
2205 */
2206 s=t=nullptr;
2207
2208 /*
2209 * conversion loop
2210 *
2211 * The sequence of steps in the loop may appear backward,
2212 * but the principle is simple:
2213 * In the chain of
2214 * source - sourceCnv overflow - pivot - targetCnv overflow - target
2215 * empty out later buffers before refilling them from earlier ones.
2216 *
2217 * The targetCnv overflow buffer is flushed out only once before the loop.
2218 */
2219 for(;;) {
2220 /*
2221 * if(pivot not empty or error or replay or flush fromUnicode) {
2222 * fromUnicode(pivot -> target);
2223 * }
2224 *
2225 * For pivoting conversion; and for direct conversion for
2226 * error callback handling and flushing the replay buffer.
2227 */
2228 if( *pivotSource<*pivotTarget ||
2229 U_FAILURE(*pErrorCode) ||
2230 targetCnv->preFromULength<0 ||
2231 fromUArgs.flush
2232 ) {
2233 fromUArgs.source=*pivotSource;
2234 fromUArgs.sourceLimit=*pivotTarget;
2235 _fromUnicodeWithCallback(&fromUArgs, pErrorCode);
2236 if(U_FAILURE(*pErrorCode)) {
2237 /* target overflow, or conversion error */
2238 *pivotSource=(char16_t *)fromUArgs.source;
2239 break;
2240 }
2241
2242 /*
2243 * _fromUnicodeWithCallback() must have consumed the pivot contents
2244 * (*pivotSource==*pivotTarget) since it returned with U_SUCCESS()
2245 */
2246 }
2247
2248 /* The pivot buffer is empty; reset it so we start at pivotStart. */
2249 *pivotSource=*pivotTarget=pivotStart;
2250
2251 /*
2252 * if(sourceCnv overflow buffer not empty) {
2253 * move(sourceCnv overflow buffer -> pivot);
2254 * continue;
2255 * }
2256 */
2257 /* output the sourceCnv overflow buffer */
2258 if(sourceCnv->UCharErrorBufferLength>0) {
2259 if(ucnv_outputOverflowToUnicode(sourceCnv, pivotTarget, pivotLimit, nullptr, pErrorCode)) {
2260 /* U_BUFFER_OVERFLOW_ERROR */
2261 *pErrorCode=U_ZERO_ERROR;
2262 }
2263 continue;
2264 }
2265
2266 /*
2267 * check for end of input and break if done
2268 *
2269 * Checking both flush and fromUArgs.flush ensures that the converters
2270 * have been called with the flush flag set if the ucnv_convertEx()
2271 * caller set it.
2272 */
2273 if( toUArgs.source==sourceLimit &&
2274 sourceCnv->preToULength>=0 && sourceCnv->toULength==0 &&
2275 (!flush || fromUArgs.flush)
2276 ) {
2277 /* done successfully */
2278 break;
2279 }
2280
2281 /*
2282 * use direct conversion if available
2283 * but not if continuing a partial match
2284 * or flushing the toUnicode replay buffer
2285 */
2286 if(convert!=nullptr && targetCnv->preFromUFirstCP<0 && sourceCnv->preToULength==0) {
2287 if(*pErrorCode==U_USING_DEFAULT_WARNING) {
2288 /* remove a warning that may be set by this function */
2289 *pErrorCode=U_ZERO_ERROR;
2290 }
2291 convert(&fromUArgs, &toUArgs, pErrorCode);
2292 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
2293 break;
2294 } else if(U_FAILURE(*pErrorCode)) {
2295 if(sourceCnv->toULength>0) {
2296 /*
2297 * Fall through to calling _toUnicodeWithCallback()
2298 * for callback handling.
2299 *
2300 * The pivot buffer will be reset with
2301 * *pivotSource=*pivotTarget=pivotStart;
2302 * which indicates a toUnicode error to the caller
2303 * (*pivotSource==pivotStart shows no pivot UChars consumed).
2304 */
2305 } else {
2306 /*
2307 * Indicate a fromUnicode error to the caller
2308 * (*pivotSource>pivotStart shows some pivot UChars consumed).
2309 */
2310 *pivotSource=*pivotTarget=pivotStart+1;
2311 /*
2312 * Loop around to calling _fromUnicodeWithCallbacks()
2313 * for callback handling.
2314 */
2315 continue;
2316 }
2317 } else if(*pErrorCode==U_USING_DEFAULT_WARNING) {
2318 /*
2319 * No error, but the implementation requested to temporarily
2320 * fall back to pivoting.
2321 */
2322 *pErrorCode=U_ZERO_ERROR;
2323 /*
2324 * The following else branches are almost identical to the end-of-input
2325 * handling in _toUnicodeWithCallback().
2326 * Avoid calling it just for the end of input.
2327 */
2328 } else if(flush && sourceCnv->toULength>0) { /* flush==toUArgs.flush */
2329 /*
2330 * the entire input stream is consumed
2331 * and there is a partial, truncated input sequence left
2332 */
2333
2334 /* inject an error and continue with callback handling */
2335 *pErrorCode=U_TRUNCATED_CHAR_FOUND;
2336 } else {
2337 /* input consumed */
2338 if(flush) {
2339 /* reset the converters without calling the callback functions */
2340 _reset(sourceCnv, UCNV_RESET_TO_UNICODE, false);
2341 _reset(targetCnv, UCNV_RESET_FROM_UNICODE, false);
2342 }
2343
2344 /* done successfully */
2345 break;
2346 }
2347 }
2348
2349 /*
2350 * toUnicode(source -> pivot);
2351 *
2352 * For pivoting conversion; and for direct conversion for
2353 * error callback handling, continuing partial matches
2354 * and flushing the replay buffer.
2355 *
2356 * The pivot buffer is empty and reset.
2357 */
2358 toUArgs.target=pivotStart; /* ==*pivotTarget */
2359 /* toUArgs.targetLimit=pivotLimit; already set before the loop */
2360 _toUnicodeWithCallback(&toUArgs, pErrorCode);
2361 *pivotTarget=toUArgs.target;
2362 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
2363 /* pivot overflow: continue with the conversion loop */
2364 *pErrorCode=U_ZERO_ERROR;
2365 } else if(U_FAILURE(*pErrorCode) || (!flush && *pivotTarget==pivotStart)) {
2366 /* conversion error, or there was nothing left to convert */
2367 break;
2368 }
2369 /*
2370 * else:
2371 * _toUnicodeWithCallback() wrote into the pivot buffer,
2372 * continue with fromUnicode conversion.
2373 *
2374 * Set the fromUnicode flush flag if we flush and if toUnicode has
2375 * processed the end of the input.
2376 */
2377 if( flush && toUArgs.source==sourceLimit &&
2378 sourceCnv->preToULength>=0 &&
2379 sourceCnv->UCharErrorBufferLength==0
2380 ) {
2381 fromUArgs.flush=true;
2382 }
2383 }
2384
2385 /*
2386 * The conversion loop is exited when one of the following is true:
2387 * - the entire source text has been converted successfully to the target buffer
2388 * - a target buffer overflow occurred
2389 * - a conversion error occurred
2390 */
2391
2392 *source=toUArgs.source;
2393 *target=fromUArgs.target;
2394
2395 /* terminate the target buffer if possible */
2396 if(flush && U_SUCCESS(*pErrorCode)) {
2397 if(*target!=targetLimit) {
2398 **target=0;
2399 if(*pErrorCode==U_STRING_NOT_TERMINATED_WARNING) {
2400 *pErrorCode=U_ZERO_ERROR;
2401 }
2402 } else {
2403 *pErrorCode=U_STRING_NOT_TERMINATED_WARNING;
2404 }
2405 }
2406}
2407
2408/* internal implementation of ucnv_convert() etc. with preflighting */
2409static int32_t
2410ucnv_internalConvert(UConverter *outConverter, UConverter *inConverter,
2411 char *target, int32_t targetCapacity,
2412 const char *source, int32_t sourceLength,
2413 UErrorCode *pErrorCode) {
2414 char16_t pivotBuffer[CHUNK_SIZE1024];
2415 char16_t *pivot, *pivot2;
2416
2417 char *myTarget;
2418 const char *sourceLimit;
2419 const char *targetLimit;
2420 int32_t targetLength=0;
2421
2422 /* set up */
2423 if(sourceLength<0) {
2424 sourceLimit=uprv_strchr(source, 0):: strchr(source, 0);
2425 } else {
2426 sourceLimit=source+sourceLength;
2427 }
2428
2429 /* if there is no input data, we're done */
2430 if(source==sourceLimit) {
2431 return u_terminateChars(target, targetCapacity, 0, pErrorCode);
2432 }
2433
2434 pivot=pivot2=pivotBuffer;
2435 myTarget=target;
2436 targetLength=0;
2437
2438 if(targetCapacity>0) {
2439 /* perform real conversion */
2440 targetLimit=target+targetCapacity;
2441 ucnv_convertEx(outConverter, inConverter,
2442 &myTarget, targetLimit,
2443 &source, sourceLimit,
2444 pivotBuffer, &pivot, &pivot2, pivotBuffer+CHUNK_SIZE1024,
2445 false,
2446 true,
2447 pErrorCode);
2448 targetLength = static_cast<int32_t>(myTarget - target);
2449 }
2450
2451 /*
2452 * If the output buffer is exhausted (or we are only "preflighting"), we need to stop writing
2453 * to it but continue the conversion in order to store in targetCapacity
2454 * the number of bytes that was required.
2455 */
2456 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR || targetCapacity==0)
2457 {
2458 char targetBuffer[CHUNK_SIZE1024];
2459
2460 targetLimit=targetBuffer+CHUNK_SIZE1024;
2461 do {
2462 *pErrorCode=U_ZERO_ERROR;
2463 myTarget=targetBuffer;
2464 ucnv_convertEx(outConverter, inConverter,
2465 &myTarget, targetLimit,
2466 &source, sourceLimit,
2467 pivotBuffer, &pivot, &pivot2, pivotBuffer+CHUNK_SIZE1024,
2468 false,
2469 true,
2470 pErrorCode);
2471 targetLength += static_cast<int32_t>(myTarget - targetBuffer);
2472 } while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR);
2473
2474 /* done with preflighting, set warnings and errors as appropriate */
2475 return u_terminateChars(target, targetCapacity, targetLength, pErrorCode);
2476 }
2477
2478 /* no need to call u_terminateChars() because ucnv_convertEx() took care of that */
2479 return targetLength;
2480}
2481
2482U_CAPIextern "C" int32_t U_EXPORT2
2483ucnv_convert(const char *toConverterName, const char *fromConverterName,
2484 char *target, int32_t targetCapacity,
2485 const char *source, int32_t sourceLength,
2486 UErrorCode *pErrorCode) {
2487 UConverter in, out; /* stack-allocated */
2488 UConverter *inConverter, *outConverter;
2489 int32_t targetLength;
2490
2491 if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) {
2492 return 0;
2493 }
2494
2495 if( source==nullptr || sourceLength<-1 ||
2496 targetCapacity<0 || (targetCapacity>0 && target==nullptr)
2497 ) {
2498 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2499 return 0;
2500 }
2501
2502 /* if there is no input data, we're done */
2503 if(sourceLength==0 || (sourceLength<0 && *source==0)) {
2504 return u_terminateChars(target, targetCapacity, 0, pErrorCode);
2505 }
2506
2507 /* create the converters */
2508 inConverter=ucnv_createConverter(&in, fromConverterName, pErrorCode);
2509 if(U_FAILURE(*pErrorCode)) {
2510 return 0;
2511 }
2512
2513 outConverter=ucnv_createConverter(&out, toConverterName, pErrorCode);
2514 if(U_FAILURE(*pErrorCode)) {
2515 ucnv_close(inConverter);
2516 return 0;
2517 }
2518
2519 targetLength=ucnv_internalConvert(outConverter, inConverter,
2520 target, targetCapacity,
2521 source, sourceLength,
2522 pErrorCode);
2523
2524 ucnv_close(inConverter);
2525 ucnv_close(outConverter);
2526
2527 return targetLength;
2528}
2529
2530/* @internal */
2531static int32_t
2532ucnv_convertAlgorithmic(UBool convertToAlgorithmic,
2533 UConverterType algorithmicType,
2534 UConverter *cnv,
2535 char *target, int32_t targetCapacity,
2536 const char *source, int32_t sourceLength,
2537 UErrorCode *pErrorCode) {
2538 UConverter algoConverterStatic; /* stack-allocated */
2539 UConverter *algoConverter, *to, *from;
2540 int32_t targetLength;
2541
2542 if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) {
2543 return 0;
2544 }
2545
2546 if( cnv==nullptr || source==nullptr || sourceLength<-1 ||
2547 targetCapacity<0 || (targetCapacity>0 && target==nullptr)
2548 ) {
2549 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2550 return 0;
2551 }
2552
2553 /* if there is no input data, we're done */
2554 if(sourceLength==0 || (sourceLength<0 && *source==0)) {
2555 return u_terminateChars(target, targetCapacity, 0, pErrorCode);
2556 }
2557
2558 /* create the algorithmic converter */
2559 algoConverter=ucnv_createAlgorithmicConverter(&algoConverterStatic, algorithmicType,
2560 "", 0, pErrorCode);
2561 if(U_FAILURE(*pErrorCode)) {
2562 return 0;
2563 }
2564
2565 /* reset the other converter */
2566 if(convertToAlgorithmic) {
2567 /* cnv->Unicode->algo */
2568 ucnv_resetToUnicode(cnv);
2569 to=algoConverter;
2570 from=cnv;
2571 } else {
2572 /* algo->Unicode->cnv */
2573 ucnv_resetFromUnicode(cnv);
2574 from=algoConverter;
2575 to=cnv;
2576 }
2577
2578 targetLength=ucnv_internalConvert(to, from,
2579 target, targetCapacity,
2580 source, sourceLength,
2581 pErrorCode);
2582
2583 ucnv_close(algoConverter);
2584
2585 return targetLength;
2586}
2587
2588U_CAPIextern "C" int32_t U_EXPORT2
2589ucnv_toAlgorithmic(UConverterType algorithmicType,
2590 UConverter *cnv,
2591 char *target, int32_t targetCapacity,
2592 const char *source, int32_t sourceLength,
2593 UErrorCode *pErrorCode) {
2594 return ucnv_convertAlgorithmic(true, algorithmicType, cnv,
2595 target, targetCapacity,
2596 source, sourceLength,
2597 pErrorCode);
2598}
2599
2600U_CAPIextern "C" int32_t U_EXPORT2
2601ucnv_fromAlgorithmic(UConverter *cnv,
2602 UConverterType algorithmicType,
2603 char *target, int32_t targetCapacity,
2604 const char *source, int32_t sourceLength,
2605 UErrorCode *pErrorCode) UPRV_NO_SANITIZE_UNDEFINED__attribute__((no_sanitize("undefined"))) {
2606
2607 if(algorithmicType<0 || UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES<=algorithmicType) {
2608 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
2609 return 0;
2610 }
2611 return ucnv_convertAlgorithmic(false, algorithmicType, cnv,
2612 target, targetCapacity,
2613 source, sourceLength,
2614 pErrorCode);
2615}
2616
2617U_CAPIextern "C" UConverterType U_EXPORT2
2618ucnv_getType(const UConverter* converter)
2619{
2620 int8_t type = converter->sharedData->staticData->conversionType;
2621#if !UCONFIG_NO_LEGACY_CONVERSION1
2622 if(type == UCNV_MBCS) {
2623 return ucnv_MBCSGetType(converter);
2624 }
2625#endif
2626 return (UConverterType)type;
2627}
2628
2629U_CAPIextern "C" void U_EXPORT2
2630ucnv_getStarters(const UConverter* converter,
2631 UBool starters[256],
2632 UErrorCode* err)
2633{
2634 if (err == nullptr || U_FAILURE(*err)) {
2635 return;
2636 }
2637
2638 if(converter->sharedData->impl->getStarters != nullptr) {
2639 converter->sharedData->impl->getStarters(converter, starters, err);
2640 } else {
2641 *err = U_ILLEGAL_ARGUMENT_ERROR;
2642 }
2643}
2644
2645static const UAmbiguousConverter *ucnv_getAmbiguous(const UConverter *cnv)
2646{
2647 UErrorCode errorCode;
2648 const char *name;
2649 int32_t i;
2650
2651 if(cnv==nullptr) {
2652 return nullptr;
2653 }
2654
2655 errorCode=U_ZERO_ERROR;
2656 name=ucnv_getName(cnv, &errorCode);
2657 if(U_FAILURE(errorCode)) {
2658 return nullptr;
2659 }
2660
2661 for(i=0; i<UPRV_LENGTHOF(ambiguousConverters)(int32_t)(sizeof(ambiguousConverters)/sizeof((ambiguousConverters
)[0]))
; ++i)
2662 {
2663 if(0==uprv_strcmp(name, ambiguousConverters[i].name):: strcmp(name, ambiguousConverters[i].name))
2664 {
2665 return ambiguousConverters+i;
2666 }
2667 }
2668
2669 return nullptr;
2670}
2671
2672U_CAPIextern "C" void U_EXPORT2
2673ucnv_fixFileSeparator(const UConverter *cnv,
2674 char16_t* source,
2675 int32_t sourceLength) {
2676 const UAmbiguousConverter *a;
2677 int32_t i;
2678 char16_t variant5c;
2679
2680 if(cnv==nullptr || source==nullptr || sourceLength<=0 || (a=ucnv_getAmbiguous(cnv))==nullptr)
2681 {
2682 return;
2683 }
2684
2685 variant5c=a->variant5c;
2686 for(i=0; i<sourceLength; ++i) {
2687 if(source[i]==variant5c) {
2688 source[i]=0x5c;
2689 }
2690 }
2691}
2692
2693U_CAPIextern "C" UBool U_EXPORT2
2694ucnv_isAmbiguous(const UConverter *cnv) {
2695 return ucnv_getAmbiguous(cnv)!=nullptr;
2696}
2697
2698U_CAPIextern "C" void U_EXPORT2
2699ucnv_setFallback(UConverter *cnv, UBool usesFallback)
2700{
2701 cnv->useFallback = usesFallback;
2702}
2703
2704U_CAPIextern "C" UBool U_EXPORT2
2705ucnv_usesFallback(const UConverter *cnv)
2706{
2707 return cnv->useFallback;
2708}
2709
2710U_CAPIextern "C" void U_EXPORT2
2711ucnv_getInvalidChars (const UConverter * converter,
2712 char *errBytes,
2713 int8_t * len,
2714 UErrorCode * err)
2715{
2716 if (err == nullptr || U_FAILURE(*err))
2717 {
2718 return;
2719 }
2720 if (len == nullptr || errBytes == nullptr || converter == nullptr)
2721 {
2722 *err = U_ILLEGAL_ARGUMENT_ERROR;
2723 return;
2724 }
2725 if (*len < converter->invalidCharLength)
2726 {
2727 *err = U_INDEX_OUTOFBOUNDS_ERROR;
2728 return;
2729 }
2730 if ((*len = converter->invalidCharLength) > 0)
2731 {
2732 uprv_memcpy (errBytes, converter->invalidCharBuffer, *len)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (errBytes != __null) ? void (0) :
__assert_fail ("errBytes != __null", __builtin_FILE (), __builtin_LINE
(), __extension__ __PRETTY_FUNCTION__)); (static_cast <bool
> (converter->invalidCharBuffer != __null) ? void (0) :
__assert_fail ("converter->invalidCharBuffer != __null", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); clang
diagnostic pop :: memcpy(errBytes, converter->invalidCharBuffer
, *len); } while (false)
;
2733 }
2734}
2735
2736U_CAPIextern "C" void U_EXPORT2
2737ucnv_getInvalidUChars (const UConverter * converter,
2738 char16_t *errChars,
2739 int8_t * len,
2740 UErrorCode * err)
2741{
2742 if (err == nullptr || U_FAILURE(*err))
2743 {
2744 return;
2745 }
2746 if (len == nullptr || errChars == nullptr || converter == nullptr)
2747 {
2748 *err = U_ILLEGAL_ARGUMENT_ERROR;
2749 return;
2750 }
2751 if (*len < converter->invalidUCharLength)
2752 {
2753 *err = U_INDEX_OUTOFBOUNDS_ERROR;
2754 return;
2755 }
2756 if ((*len = converter->invalidUCharLength) > 0)
2757 {
2758 u_memcpy (errChars, converter->invalidUCharBuffer, *len);
2759 }
2760}
2761
2762#define SIG_MAX_LEN5 5
2763
2764U_CAPIextern "C" const char* U_EXPORT2
2765ucnv_detectUnicodeSignature( const char* source,
2766 int32_t sourceLength,
2767 int32_t* signatureLength,
2768 UErrorCode* pErrorCode) {
2769 int32_t dummy;
2770
2771 /* initial 0xa5 bytes: make sure that if we read <SIG_MAX_LEN
2772 * bytes we don't misdetect something
2773 */
2774 char start[SIG_MAX_LEN5]={ '\xa5', '\xa5', '\xa5', '\xa5', '\xa5' };
2775 int i = 0;
2776
2777 if((pErrorCode==nullptr) || U_FAILURE(*pErrorCode)){
2778 return nullptr;
2779 }
2780
2781 if(source == nullptr || sourceLength < -1){
2782 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
2783 return nullptr;
2784 }
2785
2786 if(signatureLength == nullptr) {
2787 signatureLength = &dummy;
2788 }
2789
2790 if(sourceLength==-1){
2791 sourceLength=(int32_t)uprv_strlen(source):: strlen(source);
2792 }
2793
2794
2795 while(i<sourceLength&& i<SIG_MAX_LEN5){
2796 start[i]=source[i];
2797 i++;
2798 }
2799
2800 if(start[0] == '\xFE' && start[1] == '\xFF') {
2801 *signatureLength=2;
2802 return "UTF-16BE";
2803 } else if(start[0] == '\xFF' && start[1] == '\xFE') {
2804 if(start[2] == '\x00' && start[3] =='\x00') {
2805 *signatureLength=4;
2806 return "UTF-32LE";
2807 } else {
2808 *signatureLength=2;
2809 return "UTF-16LE";
2810 }
2811 } else if(start[0] == '\xEF' && start[1] == '\xBB' && start[2] == '\xBF') {
2812 *signatureLength=3;
2813 return "UTF-8";
2814 } else if(start[0] == '\x00' && start[1] == '\x00' &&
2815 start[2] == '\xFE' && start[3]=='\xFF') {
2816 *signatureLength=4;
2817 return "UTF-32BE";
2818 } else if(start[0] == '\x0E' && start[1] == '\xFE' && start[2] == '\xFF') {
2819 *signatureLength=3;
2820 return "SCSU";
2821 } else if(start[0] == '\xFB' && start[1] == '\xEE' && start[2] == '\x28') {
2822 *signatureLength=3;
2823 return "BOCU-1";
2824 } else if(start[0] == '\x2B' && start[1] == '\x2F' && start[2] == '\x76') {
2825 /*
2826 * UTF-7: Initial U+FEFF is encoded as +/v8 or +/v9 or +/v+ or +/v/
2827 * depending on the second UTF-16 code unit.
2828 * Detect the entire, closed Unicode mode sequence +/v8- for only U+FEFF
2829 * if it occurs.
2830 *
2831 * So far we have +/v
2832 */
2833 if(start[3] == '\x38' && start[4] == '\x2D') {
2834 /* 5 bytes +/v8- */
2835 *signatureLength=5;
2836 return "UTF-7";
2837 } else if(start[3] == '\x38' || start[3] == '\x39' || start[3] == '\x2B' || start[3] == '\x2F') {
2838 /* 4 bytes +/v8 or +/v9 or +/v+ or +/v/ */
2839 *signatureLength=4;
2840 return "UTF-7";
2841 }
2842 }else if(start[0]=='\xDD' && start[1]== '\x73'&& start[2]=='\x66' && start[3]=='\x73'){
2843 *signatureLength=4;
2844 return "UTF-EBCDIC";
2845 }
2846
2847
2848 /* no known Unicode signature byte sequence recognized */
2849 *signatureLength=0;
2850 return nullptr;
2851}
2852
2853U_CAPIextern "C" int32_t U_EXPORT2
2854ucnv_fromUCountPending(const UConverter* cnv, UErrorCode* status)
2855{
2856 if(status == nullptr || U_FAILURE(*status)){
2857 return -1;
2858 }
2859 if(cnv == nullptr){
2860 *status = U_ILLEGAL_ARGUMENT_ERROR;
2861 return -1;
2862 }
2863
2864 if(cnv->preFromUFirstCP >= 0){
2865 return U16_LENGTH(cnv->preFromUFirstCP)((uint32_t)(cnv->preFromUFirstCP)<=0xffff ? 1 : 2)+cnv->preFromULength ;
2866 }else if(cnv->preFromULength < 0){
2867 return -cnv->preFromULength ;
2868 }else if(cnv->fromUChar32 > 0){
2869 return 1;
2870 }
2871 return 0;
2872
2873}
2874
2875U_CAPIextern "C" int32_t U_EXPORT2
2876ucnv_toUCountPending(const UConverter* cnv, UErrorCode* status){
2877
2878 if(status == nullptr || U_FAILURE(*status)){
2879 return -1;
2880 }
2881 if(cnv == nullptr){
2882 *status = U_ILLEGAL_ARGUMENT_ERROR;
2883 return -1;
2884 }
2885
2886 if(cnv->preToULength > 0){
2887 return cnv->preToULength ;
2888 }else if(cnv->preToULength < 0){
2889 return -cnv->preToULength;
2890 }else if(cnv->toULength > 0){
2891 return cnv->toULength;
2892 }
2893 return 0;
2894}
2895
2896U_CAPIextern "C" UBool U_EXPORT2
2897ucnv_isFixedWidth(UConverter *cnv, UErrorCode *status){
2898 if (U_FAILURE(*status)) {
2899 return false;
2900 }
2901
2902 if (cnv == nullptr) {
2903 *status = U_ILLEGAL_ARGUMENT_ERROR;
2904 return false;
2905 }
2906
2907 switch (ucnv_getType(cnv)) {
2908 case UCNV_SBCS:
2909 case UCNV_DBCS:
2910 case UCNV_UTF32_BigEndian:
2911 case UCNV_UTF32_LittleEndian:
2912 case UCNV_UTF32:
2913 case UCNV_US_ASCII:
2914 return true;
2915 default:
2916 return false;
2917 }
2918}
2919#endif
2920
2921/*
2922 * Hey, Emacs, please set the following:
2923 *
2924 * Local Variables:
2925 * indent-tabs-mode: nil
2926 * End:
2927 *
2928 */