BreakIterator *newBI = ((BreakIterator *)bi)->clone();
if (newBI == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
- } else {
+ } else if (pBufferSize != NULL) {
*status = U_SAFECLONE_ALLOCATED_WARNING;
}
return (UBreakIterator *)newBI;
U_CAPI UBreakIterator * U_EXPORT2
ubrk_clone(const UBreakIterator *bi, UErrorCode *status) {
- if (U_FAILURE(*status)) {
- return nullptr;
- }
- BreakIterator *newBI = ((BreakIterator *)bi)->clone();
- if (newBI == nullptr) {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- return (UBreakIterator *)newBI;
+ return ubrk_safeClone(bi, nullptr, nullptr, status);
}
UTRACE_EXIT_STATUS(*status);
return NULL;
}
- *status = U_SAFECLONE_ALLOCATED_WARNING;
+ // If pBufferSize was NULL as the input, pBufferSize is set to &stackBufferSize in this function.
+ if (pBufferSize != &stackBufferSize) {
+ *status = U_SAFECLONE_ALLOCATED_WARNING;
+ }
/* record the fact that memory was allocated */
*pBufferSize = bufferSizeNeeded;
return localConverter;
}
-
+U_CAPI UConverter* U_EXPORT2
+ucnv_clone(const UConverter* cnv, UErrorCode *status)
+{
+ return ucnv_safeClone(cnv, nullptr, nullptr, status);
+}
/*Decreases the reference counter in the shared immutable section of the object
*and frees the mutable part*/
* If *pBufferSize is not enough for a stack-based safe clone,
* new memory will be allocated.
* @param status to indicate whether the operation went on smoothly or there were errors
- * An informational status value, U_SAFECLONE_ALLOCATED_ERROR, is used if any allocations were necessary.
+ * An informational status value, U_SAFECLONE_ALLOCATED_ERROR, is used
+ * if pBufferSize != NULL and any allocations were necessary
* @return pointer to the new clone
* @deprecated ICU 69 Use ubrk_clone() instead.
*/
*
* <p>The name will NOT be looked up in the alias mechanism, nor will the converter be
* stored in the converter cache or the alias table. The only way to open further converters
- * is call this function multiple times, or use the ucnv_safeClone() function to clone a
+ * is call this function multiple times, or use the ucnv_clone() function to clone a
* 'primary' converter.</p>
*
* <p>A future version of ICU may add alias table lookups and/or caching
* @return the created Unicode converter object, or <TT>NULL</TT> if an error occurred
* @see udata_open
* @see ucnv_open
- * @see ucnv_safeClone
+ * @see ucnv_clone
* @see ucnv_close
* @stable ICU 2.2
*/
U_CAPI UConverter* U_EXPORT2
ucnv_openPackage(const char *packageName, const char *converterName, UErrorCode *err);
+/**
+ * Thread safe converter cloning operation.
+ *
+ * You must ucnv_close() the clone.
+ *
+ * @param cnv converter to be cloned
+ * @param status to indicate whether the operation went on smoothly or there were errors
+ * @return pointer to the new clone
+ * @stable ICU 71
+ */
+U_CAPI UConverter* U_EXPORT2 ucnv_clone(const UConverter *cnv, UErrorCode *status);
+
+#ifndef U_HIDE_DEPRECATED_API
+
/**
* Thread safe converter cloning operation.
* For most efficient operation, pass in a stackBuffer (and a *pBufferSize)
* pointer to size of allocated space.
* @param status to indicate whether the operation went on smoothly or there were errors
* An informational status value, U_SAFECLONE_ALLOCATED_WARNING,
- * is used if any allocations were necessary.
+ * is used if pBufferSize != NULL and any allocations were necessary
* However, it is better to check if *pBufferSize grew for checking for
* allocations because warning codes can be overridden by subsequent
* function calls.
* @return pointer to the new clone
- * @stable ICU 2.0
+ * @deprecated ICU 71 Use ucnv_clone() instead.
*/
U_CAPI UConverter * U_EXPORT2
ucnv_safeClone(const UConverter *cnv,
int32_t *pBufferSize,
UErrorCode *status);
-#ifndef U_HIDE_DEPRECATED_API
-
/**
* \def U_CNV_SAFECLONE_BUFFERSIZE
* Definition of a buffer size that is designed to be large enough for
if (newColl == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return nullptr;
- } else {
+ } else if (pBufferSize != NULL) {
*status = U_SAFECLONE_ALLOCATED_WARNING;
}
return newColl->toUCollator();
}
+U_CAPI UCollator* U_EXPORT2
+ucol_clone(const UCollator *coll, UErrorCode *status)
+{
+ return ucol_safeClone(coll, nullptr, nullptr, status);
+}
+
U_CAPI void U_EXPORT2
ucol_close(UCollator *coll)
{
* @param status A pointer to a UErrorCode to receive any errors
* @return A pointer to a UCollator, or 0 if an error occurred.
* @see ucol_openRules
- * @see ucol_safeClone
+ * @see ucol_clone
* @see ucol_close
* @stable ICU 2.0
*/
* @return A pointer to a UCollator. It is not guaranteed that NULL be returned in case
* of error - please use status argument to check for errors.
* @see ucol_open
- * @see ucol_safeClone
+ * @see ucol_clone
* @see ucol_close
* @stable ICU 2.0
*/
* @param coll The UCollator to close.
* @see ucol_open
* @see ucol_openRules
- * @see ucol_safeClone
+ * @see ucol_clone
* @stable ICU 2.0
*/
U_CAPI void U_EXPORT2
*
* @deprecated ICU 54
*/
-
U_DEPRECATED int32_t U_EXPORT2
ucol_normalizeShortDefinitionString(const char *source,
char *destination,
ucol_restoreVariableTop(UCollator *coll, const uint32_t varTop, UErrorCode *status);
#endif /* U_HIDE_DEPRECATED_API */
+/**
+ * Thread safe cloning operation. The result is a clone of a given collator.
+ * @param coll collator to be cloned
+ * @param status to indicate whether the operation went on smoothly or there were errors
+ * @return pointer to the new clone
+ * @see ucol_open
+ * @see ucol_openRules
+ * @see ucol_close
+ * @stable ICU 71
+ */
+U_CAPI UCollator* U_EXPORT2 ucol_clone(const UCollator *coll, UErrorCode *status);
+
+#ifndef U_HIDE_DEPRECATED_API
+
/**
* Thread safe cloning operation. The result is a clone of a given collator.
* @param coll collator to be cloned
* If *pBufferSize is not enough for a stack-based safe clone,
* new memory will be allocated.
* @param status to indicate whether the operation went on smoothly or there were errors
- * An informational status value, U_SAFECLONE_ALLOCATED_ERROR, is used if any
- * allocations were necessary.
+ * An informational status value, U_SAFECLONE_ALLOCATED_ERROR, is used
+ * if pBufferSize != NULL and any allocations were necessary
* @return pointer to the new clone
* @see ucol_open
* @see ucol_openRules
* @see ucol_close
- * @stable ICU 2.0
+ * @deprecated ICU 71 Use ucol_clone() instead.
*/
U_CAPI UCollator* U_EXPORT2
ucol_safeClone(const UCollator *coll,
int32_t *pBufferSize,
UErrorCode *status);
-#ifndef U_HIDE_DEPRECATED_API
/** default memory size for the new clone.
* @deprecated ICU 52. Do not rely on ucol_safeClone() cloning into any provided buffer.
/*addTest(root, &TestGetDefaultRules, "tscoll/capitst/TestGetDefaultRules");*/
addTest(root, &TestDecomposition, "tscoll/capitst/TestDecomposition");
addTest(root, &TestSafeClone, "tscoll/capitst/TestSafeClone");
+ addTest(root, &TestClone, "tscoll/capitst/TestClone");
addTest(root, &TestCloneBinary, "tscoll/capitst/TestCloneBinary");
addTest(root, &TestGetSetAttr, "tscoll/capitst/TestGetSetAttr");
addTest(root, &TestBounds, "tscoll/capitst/TestBounds");
}
}
+void TestClone() {
+ UChar test1[6];
+ UChar test2[6];
+ static const UChar umlautUStr[] = {0x00DC, 0};
+ static const UChar oeStr[] = {0x0055, 0x0045, 0};
+ UCollator * someCollators [CLONETEST_COLLATOR_COUNT];
+ UCollator * someClonedCollators [CLONETEST_COLLATOR_COUNT];
+ UCollator * col = NULL;
+ UErrorCode err = U_ZERO_ERROR;
+ int8_t idx = 6; /* Leave this here to test buffer alignment in memory*/
+ const char sampleRuleChars[] = "&Z < CH";
+ UChar sampleRule[sizeof(sampleRuleChars)];
+
+ u_uastrcpy(test1, "abCda");
+ u_uastrcpy(test2, "abcda");
+ u_uastrcpy(sampleRule, sampleRuleChars);
+
+ /* one default collator & two complex ones */
+ someCollators[0] = ucol_open("en_US", &err);
+ someCollators[1] = ucol_open("ko", &err);
+ someCollators[2] = ucol_open("ja_JP", &err);
+ someCollators[3] = ucol_openRules(sampleRule, -1, UCOL_ON, UCOL_TERTIARY, NULL, &err);
+ if(U_FAILURE(err)) {
+ for (idx = 0; idx < CLONETEST_COLLATOR_COUNT; idx++) {
+ ucol_close(someCollators[idx]);
+ }
+ log_data_err("Couldn't open one or more collators\n");
+ return;
+ }
+
+ /* Check the various error & informational states: */
+
+ /* Null status - just returns NULL */
+ if (NULL != ucol_clone(someCollators[0], NULL))
+ {
+ log_err("FAIL: Cloned Collator failed to deal correctly with null status\n");
+ }
+ /* error status - should return 0 & keep error the same */
+ err = U_MEMORY_ALLOCATION_ERROR;
+ if (NULL != ucol_clone(someCollators[0], &err) || err != U_MEMORY_ALLOCATION_ERROR)
+ {
+ log_err("FAIL: Cloned Collator failed to deal correctly with incoming error status\n");
+ }
+ err = U_ZERO_ERROR;
+
+ /* Verify we can use this run-time calculated size */
+ if (NULL == (col = ucol_clone(someCollators[0], &err)) || U_FAILURE(err))
+ {
+ log_err("FAIL: Collator can't be cloned.\n");
+ }
+ if (col) ucol_close(col);
+
+ if (NULL == (col = ucol_clone(someCollators[0], &err)) || err != U_ZERO_ERROR)
+ {
+ log_err("FAIL: Cloned Collator failed to deal correctly\n");
+ }
+ if (col) ucol_close(col);
+ err = U_ZERO_ERROR;
+
+ /* Null Collator - return NULL & set U_ILLEGAL_ARGUMENT_ERROR */
+ if (NULL != ucol_clone(NULL, &err) || err != U_ILLEGAL_ARGUMENT_ERROR)
+ {
+ log_err("FAIL: Cloned Collator failed to deal correctly with null Collator pointer\n");
+ }
+ err = U_ZERO_ERROR;
+
+ /* Test that a cloned collator doesn't accidentally use UCA. */
+ col=ucol_open("de@collation=phonebook", &err);
+ someClonedCollators[0] = ucol_clone(col, &err);
+ doAssert( (ucol_greater(col, umlautUStr, u_strlen(umlautUStr), oeStr, u_strlen(oeStr))), "Original German phonebook collation sorts differently than expected");
+ doAssert( (ucol_greater(someClonedCollators[0], umlautUStr, u_strlen(umlautUStr), oeStr, u_strlen(oeStr))), "Cloned German phonebook collation sorts differently than expected");
+ if (!ucol_equals(someClonedCollators[0], col)) {
+ log_err("FAIL: Cloned German phonebook collator is not equal to original.\n");
+ }
+ ucol_close(col);
+ ucol_close(someClonedCollators[0]);
+
+ err = U_ZERO_ERROR;
+
+ /* change orig & clone & make sure they are independent */
+
+ for (idx = 0; idx < CLONETEST_COLLATOR_COUNT; idx++)
+ {
+ ucol_setStrength(someCollators[idx], UCOL_IDENTICAL);
+ err = U_ZERO_ERROR;
+ ucol_close(ucol_clone(someCollators[idx], &err));
+ if (err != U_ZERO_ERROR) {
+ log_err("FAIL: collator number %d was not allocated.\n", idx);
+ log_err("FAIL: status of Collator[%d] is %d (hex: %x).\n", idx, err, err);
+ }
+
+ err = U_ZERO_ERROR;
+ someClonedCollators[idx] = ucol_clone(someCollators[idx], &err);
+ if (U_FAILURE(err)) {
+ log_err("FAIL: Unable to clone collator %d - %s\n", idx, u_errorName(err));
+ continue;
+ }
+ if (!ucol_equals(someClonedCollators[idx], someCollators[idx])) {
+ log_err("FAIL: Cloned collator is not equal to original at index = %d.\n", idx);
+ }
+
+ /* Check the usability */
+ ucol_setStrength(someCollators[idx], UCOL_PRIMARY);
+ ucol_setAttribute(someCollators[idx], UCOL_CASE_LEVEL, UCOL_OFF, &err);
+
+ doAssert( (ucol_equal(someCollators[idx], test1, u_strlen(test1), test2, u_strlen(test2))), "Result should be \"abcda\" == \"abCda\"");
+
+ /* Close the original to make sure that the clone is usable. */
+ ucol_close(someCollators[idx]);
+
+ ucol_setStrength(someClonedCollators[idx], UCOL_TERTIARY);
+ ucol_setAttribute(someClonedCollators[idx], UCOL_CASE_LEVEL, UCOL_OFF, &err);
+ doAssert( (ucol_greater(someClonedCollators[idx], test1, u_strlen(test1), test2, u_strlen(test2))), "Result should be \"abCda\" >>> \"abcda\" ");
+
+ ucol_close(someClonedCollators[idx]);
+ }
+}
+
void TestCloneBinary(){
UErrorCode err = U_ZERO_ERROR;
UCollator * col = ucol_open("en_US", &err);
**/
void TestSafeClone(void);
+ /**
+ * Test ucol_clone ()
+ **/
+ void TestClone(void);
+
/**
* Test ucol_cloneBinary(), ucol_openBinary()
**/
static void TestLMBCSMaxChar(void);
#endif
+static void TestConvertClone(void);
#if !UCONFIG_NO_LEGACY_CONVERSION
static void TestConvertSafeCloneCallback(void);
#endif
addTest(root, &TestAlias, "tsconv/ccapitst/TestAlias");
addTest(root, &TestDuplicateAlias, "tsconv/ccapitst/TestDuplicateAlias");
addTest(root, &TestConvertSafeClone, "tsconv/ccapitst/TestConvertSafeClone");
+ addTest(root, &TestConvertClone, "tsconv/ccapitst/TestConvertClone");
#if !UCONFIG_NO_LEGACY_CONVERSION
addTest(root, &TestConvertSafeCloneCallback,"tsconv/ccapitst/TestConvertSafeCloneCallback");
#endif
}
}
+
+static void TestConvertClone()
+{
+ /* one 'regular' & all the 'private stateful' converters */
+ static const char *const names[] = {
+#if !UCONFIG_NO_LEGACY_CONVERSION
+ "ibm-1047",
+ "ISO_2022,locale=zh,version=1",
+#endif
+ "SCSU",
+#if !UCONFIG_NO_LEGACY_CONVERSION
+ "HZ",
+ "lmbcs",
+ "ISCII,version=0",
+ "ISO_2022,locale=kr,version=1",
+ "ISO_2022,locale=jp,version=2",
+#endif
+ "BOCU-1",
+ "UTF-7",
+#if !UCONFIG_NO_LEGACY_CONVERSION
+ "IMAP-mailbox-name",
+ "ibm-1047-s390"
+#else
+ "IMAP=mailbox-name"
+#endif
+ };
+
+ char charBuffer[21]; /* Leave at an odd number for alignment testing */
+ UConverter * cnv, *cnv2;
+ UErrorCode err;
+
+ char *pCharBuffer;
+ const char *pConstCharBuffer;
+ const char *charBufferLimit = charBuffer + UPRV_LENGTHOF(charBuffer);
+ UChar uniBuffer[] = {0x0058, 0x0059, 0x005A}; /* "XYZ" */
+ UChar uniCharBuffer[20];
+ char charSourceBuffer[] = { 0x1b, 0x24, 0x42 };
+ const char *pCharSource = charSourceBuffer;
+ const char *pCharSourceLimit = charSourceBuffer + sizeof(charSourceBuffer);
+ UChar *pUCharTarget = uniCharBuffer;
+ UChar *pUCharTargetLimit = uniCharBuffer + UPRV_LENGTHOF(uniCharBuffer);
+ const UChar * pUniBuffer;
+ const UChar *uniBufferLimit = uniBuffer + UPRV_LENGTHOF(uniBuffer);
+ int32_t idx;
+
+ err = U_ZERO_ERROR;
+ cnv = ucnv_open(names[0], &err);
+ if(U_SUCCESS(err)) {
+ /* Check the various error & informational states: */
+
+ /* Null status - just returns NULL */
+ if (NULL != ucnv_clone(cnv, NULL))
+ {
+ log_err("FAIL: Cloned converter failed to deal correctly with null status\n");
+ }
+ /* error status - should return 0 & keep error the same */
+ err = U_MEMORY_ALLOCATION_ERROR;
+ if (NULL != ucnv_clone(cnv, &err) || err != U_MEMORY_ALLOCATION_ERROR)
+ {
+ log_err("FAIL: Cloned converter failed to deal correctly with incoming error status\n");
+ }
+ err = U_ZERO_ERROR;
+
+ /* Null buffer size pointer is ok */
+ if (NULL == (cnv2 = ucnv_clone(cnv, &err)) || U_FAILURE(err))
+ {
+ log_err("FAIL: Failed to clone.\n");
+ }
+ ucnv_close(cnv2);
+ err = U_ZERO_ERROR;
+
+ /* Null converter - return NULL & set U_ILLEGAL_ARGUMENT_ERROR */
+ if (NULL != ucnv_clone(NULL, &err) || err != U_ILLEGAL_ARGUMENT_ERROR)
+ {
+ log_err("FAIL: Cloned converter failed to deal correctly with null converter pointer\n");
+ }
+
+ ucnv_close(cnv);
+ }
+
+ /* Do these cloned converters work at all - shuffle UChars to chars & back again..*/
+ for (idx = 0; idx < UPRV_LENGTHOF(names); idx++)
+ {
+ err = U_ZERO_ERROR;
+ cnv = ucnv_open(names[idx], &err);
+ if(U_FAILURE(err)) {
+ log_data_err("ucnv_open(\"%s\") failed - %s\n", names[idx], u_errorName(err));
+ continue;
+ }
+
+ cnv2 = ucnv_clone(cnv, &err);
+
+ /* close the original immediately to make sure that the clone works by itself */
+ ucnv_close(cnv);
+
+ pCharBuffer = charBuffer;
+ pUniBuffer = uniBuffer;
+
+ ucnv_fromUnicode(cnv2,
+ &pCharBuffer,
+ charBufferLimit,
+ &pUniBuffer,
+ uniBufferLimit,
+ NULL,
+ TRUE,
+ &err);
+ if(U_FAILURE(err)){
+ log_err("FAIL: cloned converter failed to do fromU conversion. Error: %s\n",u_errorName(err));
+ }
+ ucnv_toUnicode(cnv2,
+ &pUCharTarget,
+ pUCharTargetLimit,
+ &pCharSource,
+ pCharSourceLimit,
+ NULL,
+ TRUE,
+ &err
+ );
+
+ if(U_FAILURE(err)){
+ log_err("FAIL: cloned converter failed to do toU conversion. Error: %s\n",u_errorName(err));
+ }
+
+ pConstCharBuffer = charBuffer;
+ if (uniBuffer [0] != ucnv_getNextUChar(cnv2, &pConstCharBuffer, pCharBuffer, &err))
+ {
+ log_err("FAIL: Cloned converter failed to do conversion. Error: %s\n",u_errorName(err));
+ }
+ ucnv_close(cnv2);
+ }
+}
+
static void TestCCSID() {
#if !UCONFIG_NO_LEGACY_CONVERSION
UConverter *cnv;