diff --git a/icu4c/source/common/ucnv.c b/icu4c/source/common/ucnv.c index 6edd274b0ec..94a5f121bca 100644 --- a/icu4c/source/common/ucnv.c +++ b/icu4c/source/common/ucnv.c @@ -135,6 +135,63 @@ UConverter* ucnv_openCCSID (int32_t codepage, return createConverter (myName, err); } +/* Creating a temporary stack-based object that can be used in one thread, +and created from a converter that is shared across threads. +*/ + +UConverter *ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, UErrorCode *status) +{ + UConverter * localConverter; + int32_t bufferSizeNeeded; + + if (status == NULL || U_FAILURE(*status)){ + return 0; + } + if (!pBufferSize || !cnv){ + *status = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + + if (cnv->sharedData->impl->safeClone != NULL) { + /* call the custom safeClone function for sizing */ + bufferSizeNeeded = 0; + cnv->sharedData->impl->safeClone(cnv, stackBuffer, &bufferSizeNeeded, status); + } + else + { + bufferSizeNeeded = sizeof(UConverter); + } + + if (*pBufferSize == 0){ /* 'preflighting' request - set needed size into *pBufferSize */ + *pBufferSize = bufferSizeNeeded; + return 0; + } + + if (*pBufferSize < bufferSizeNeeded || stackBuffer == NULL) + { + /* allocate one here...*/ + localConverter = createConverter (ucnv_getName (cnv, status), status); + if (U_SUCCESS(*status)) + { + *status = U_SAFECLONE_ALLOCATED_ERROR; + } + } else { + if (cnv->sharedData->impl->safeClone != NULL) { + /* call the custom safeClone function */ + localConverter = cnv->sharedData->impl->safeClone(cnv, stackBuffer, pBufferSize, status); + } + else + { + localConverter = (UConverter *)stackBuffer; + memcpy(localConverter, cnv, sizeof(UConverter)); + localConverter->isCopyLocal = TRUE; + } + } + return localConverter; +} + + + /*Decreases the reference counter in the shared immutable section of the object *and frees the mutable part*/ @@ -163,7 +220,7 @@ void ucnv_close (UConverter * converter) }; UErrorCode errorCode; - if (converter == NULL) + if (converter == NULL || converter->isCopyLocal) { return; } diff --git a/icu4c/source/common/ucnv2022.c b/icu4c/source/common/ucnv2022.c index bec801861d9..78e8057c284 100644 --- a/icu4c/source/common/ucnv2022.c +++ b/icu4c/source/common/ucnv2022.c @@ -313,6 +313,7 @@ static void _ISO2022Close(UConverter *converter); static void _ISO2022Reset(UConverter *converter, UConverterResetChoice choice); static const char* _ISO2022getName(const UConverter* cnv); U_CFUNC void _ISO_2022_WriteSub(UConverterFromUnicodeArgs *args, int32_t offsetIndex, UErrorCode *err) ; +U_CFUNC UConverter * _ISO_2022_SafeClone(const UConverter *cnv, void *stackBuffer, int32_t *pBufferSize, UErrorCode *status); /************ protos of functions for setting the initial state *********************/ static void setInitialStateToUnicodeJPCN(UConverter* converter,UConverterDataISO2022 *myConverterData); static void setInitialStateFromUnicodeJPCN(UConverter* converter,UConverterDataISO2022 *myConverterData); @@ -337,7 +338,9 @@ static const UConverterImpl _ISO2022Impl={ T_UConverter_getNextUChar_ISO_2022, NULL, - _ISO2022getName + _ISO2022getName, + _ISO_2022_WriteSub, + _ISO_2022_SafeClone }; const UConverterStaticData _ISO2022StaticData={ @@ -388,7 +391,8 @@ static const UConverterImpl _ISO2022JPImpl={ NULL, _ISO2022getName, - _ISO_2022_WriteSub + _ISO_2022_WriteSub, + _ISO_2022_SafeClone }; const UConverterStaticData _ISO2022JPStaticData={ sizeof(UConverterStaticData), @@ -436,7 +440,8 @@ static const UConverterImpl _ISO2022KRImpl={ NULL, _ISO2022getName, - _ISO_2022_WriteSub + _ISO_2022_WriteSub, + _ISO_2022_SafeClone }; const UConverterStaticData _ISO2022KRStaticData={ sizeof(UConverterStaticData), @@ -484,8 +489,8 @@ static const UConverterImpl _ISO2022CNImpl={ NULL, _ISO2022getName, - _ISO_2022_WriteSub - + _ISO_2022_WriteSub, + _ISO_2022_SafeClone }; const UConverterStaticData _ISO2022CNStaticData={ sizeof(UConverterStaticData), @@ -3098,3 +3103,40 @@ _ISO_2022_WriteSub(UConverterFromUnicodeArgs *args, int32_t offsetIndex, UErrorC buffer, (int32_t)(p - buffer), offsetIndex, err); } + +/* structure for SafeClone calculations */ +struct cloneStruct +{ + UConverter cnv; + UConverterDataISO2022 mydata; +}; + + +U_CFUNC UConverter * +_ISO_2022_SafeClone( + const UConverter *cnv, + void *stackBuffer, + int32_t *pBufferSize, + UErrorCode *status) +{ + struct cloneStruct * localClone; + int32_t bufferSizeNeeded = sizeof(struct cloneStruct); + + if (U_FAILURE(*status)){ + return 0; + } + + if (*pBufferSize == 0){ /* 'preflighting' request - set needed size into *pBufferSize */ + *pBufferSize = bufferSizeNeeded; + return 0; + } + + localClone = (struct cloneStruct *)stackBuffer; + memcpy(&localClone->cnv, cnv, sizeof(UConverter)); + localClone->cnv.isCopyLocal = TRUE; + + memcpy(&localClone->mydata, cnv->extraInfo, sizeof(UConverterDataISO2022)); + localClone->cnv.extraInfo = &localClone->mydata; + + return &localClone->cnv; +} diff --git a/icu4c/source/common/ucnv_bld.h b/icu4c/source/common/ucnv_bld.h index 1e2a516ce4b..b5439ee4a84 100644 --- a/icu4c/source/common/ucnv_bld.h +++ b/icu4c/source/common/ucnv_bld.h @@ -153,6 +153,7 @@ struct UConverter { void *fromUContext; void *toUContext; + UBool isCopyLocal; /* TRUE if created by safeClone with no allocation or ref count */ UConverterSharedData *sharedData; /* Pointer to the shared immutable part of the converter object */ /* diff --git a/icu4c/source/common/ucnv_cnv.h b/icu4c/source/common/ucnv_cnv.h index 2a97d0348c2..84aa97c5ba8 100644 --- a/icu4c/source/common/ucnv_cnv.h +++ b/icu4c/source/common/ucnv_cnv.h @@ -83,6 +83,16 @@ typedef const char * (*UConverterGetName) (const UConverter *cnv); */ typedef void (*UConverterWriteSub) (UConverterFromUnicodeArgs *pArgs, int32_t offsetIndex, UErrorCode *pErrorCode); +/** + * For converter-specific safeClone processing + * If this function is not set, then ucnv_safeClone assumes that the converter has no private data that changes + * after the converter is done opening. + */ +typedef UConverter * (*UConverterSafeClone) ( const UConverter *cnv, + void *stackBuffer, + int32_t *pBufferSize, + UErrorCode *status); + UBool CONVERSION_U_SUCCESS (UErrorCode err); void flushInternalUnicodeBuffer (UConverter * _this, @@ -134,6 +144,7 @@ struct UConverterImpl { UConverterGetStarters getStarters; UConverterGetName getName; UConverterWriteSub writeSub; + UConverterSafeClone safeClone; }; extern const UConverterSharedData diff --git a/icu4c/source/common/ucnvhz.c b/icu4c/source/common/ucnvhz.c index aed3e3ff3fd..b4d9bc1d424 100644 --- a/icu4c/source/common/ucnvhz.c +++ b/icu4c/source/common/ucnvhz.c @@ -56,6 +56,7 @@ static void _HZClose(UConverter *converter); static void _HZReset(UConverter *converter, UConverterResetChoice choice); U_CFUNC void _HZ_WriteSub(UConverterFromUnicodeArgs *args, int32_t offsetIndex, UErrorCode *err); +U_CFUNC UConverter * _HZ_SafeClone(const UConverter *cnv, void *stackBuffer, int32_t *pBufferSize, UErrorCode *status); U_CFUNC void UConverter_toUnicode_HZ_OFFSETS_LOGIC (UConverterToUnicodeArgs *args, UErrorCode *err); @@ -82,7 +83,8 @@ static UConverterImpl _HZImpl={ NULL, NULL, - _HZ_WriteSub + _HZ_WriteSub, + _HZ_SafeClone }; const UConverterStaticData _HZStaticData={ @@ -643,3 +645,42 @@ _HZ_WriteSub(UConverterFromUnicodeArgs *args, int32_t offsetIndex, UErrorCode *e buffer, (int32_t)(p - buffer), offsetIndex, err); } + +/* structure for SafeClone calculations */ +struct cloneStruct +{ + UConverter cnv; + UConverterDataHZ mydata; +}; + + +U_CFUNC UConverter * +_HZ_SafeClone( + const UConverter *cnv, + void *stackBuffer, + int32_t *pBufferSize, + UErrorCode *status) +{ + struct cloneStruct * localClone; + int32_t bufferSizeNeeded = sizeof(struct cloneStruct); + + if (U_FAILURE(*status)){ + return 0; + } + + if (*pBufferSize == 0){ /* 'preflighting' request - set needed size into *pBufferSize */ + *pBufferSize = bufferSizeNeeded; + return 0; + } + + localClone = (struct cloneStruct *)stackBuffer; + memcpy(&localClone->cnv, cnv, sizeof(UConverter)); + localClone->cnv.isCopyLocal = TRUE; + + memcpy(&localClone->mydata, cnv->extraInfo, sizeof(UConverterDataHZ)); + localClone->cnv.extraInfo = &localClone->mydata; + + return &localClone->cnv; +} + + diff --git a/icu4c/source/common/ucnvscsu.c b/icu4c/source/common/ucnvscsu.c index 78b7f58de72..a705bf65493 100644 --- a/icu4c/source/common/ucnvscsu.c +++ b/icu4c/source/common/ucnvscsu.c @@ -55,6 +55,12 @@ U_CFUNC void _SCSUWriteSub(UConverterFromUnicodeArgs *pArgs, int32_t offsetIndex, UErrorCode *pErrorCode); +U_CFUNC UConverter * +_SCSUSafeClone(const UConverter *cnv, + void *stackBuffer, + int32_t *pBufferSize, + UErrorCode *status); + /* SCSU definitions --------------------------------------------------------- */ @@ -1361,6 +1367,46 @@ _SCSUWriteSub(UConverterFromUnicodeArgs *pArgs, } } +/* structure for SafeClone calculations */ +struct cloneStruct +{ + UConverter cnv; + SCSUData mydata; +}; + +U_CFUNC UConverter * +_SCSUSafeClone( + const UConverter *cnv, + void *stackBuffer, + int32_t *pBufferSize, + UErrorCode *status) +{ + struct cloneStruct * localClone; + int32_t bufferSizeNeeded = sizeof(struct cloneStruct); + + if (U_FAILURE(*status)){ + return 0; + } + + if (*pBufferSize == 0){ /* 'preflighting' request - set needed size into *pBufferSize */ + *pBufferSize = bufferSizeNeeded; + return 0; + } + + localClone = (struct cloneStruct *)stackBuffer; + memcpy(&localClone->cnv, cnv, sizeof(UConverter)); + localClone->cnv.isCopyLocal = TRUE; + + memcpy(&localClone->mydata, cnv->extraInfo, sizeof(SCSUData)); + localClone->cnv.extraInfo = &localClone->mydata; + + return &localClone->cnv; +} + + + + + static const UConverterImpl _SCSUImpl={ UCNV_SCSU, @@ -1379,7 +1425,8 @@ static const UConverterImpl _SCSUImpl={ NULL, _SCSUGetName, - _SCSUWriteSub + _SCSUWriteSub, + _SCSUSafeClone }; static const UConverterStaticData _SCSUStaticData={