From a4663ad545e8de85b00efb1e39dc716ea5291521 Mon Sep 17 00:00:00 2001 From: George Rhoten Date: Sun, 21 May 2006 17:52:09 +0000 Subject: [PATCH] ICU-5190 Fix ucol_safeClone to properly clone a collator. X-SVN-Rev: 19629 --- icu4c/source/i18n/ucol.cpp | 95 ++++++++++++++++++++++++-- icu4c/source/i18n/ucol_res.cpp | 121 +++++++++------------------------ 2 files changed, 124 insertions(+), 92 deletions(-) diff --git a/icu4c/source/i18n/ucol.cpp b/icu4c/source/i18n/ucol.cpp index 5b6b89a3750..7cec86c1b00 100644 --- a/icu4c/source/i18n/ucol.cpp +++ b/icu4c/source/i18n/ucol.cpp @@ -351,7 +351,7 @@ ucol_initFromBinary(const uint8_t *bin, int32_t length, UErrorCode *status) { UCollator *result = fillIn; - if(U_FAILURE(*status)){ + if(U_FAILURE(*status)) { return NULL; } /* @@ -371,14 +371,16 @@ ucol_initFromBinary(const uint8_t *bin, int32_t length, { *status = U_COLLATOR_VERSION_MISMATCH; return NULL; - } else { + } + else { if((uint32_t)length > (paddedsize(sizeof(UCATableHeader)) + paddedsize(sizeof(UColOptionSet)))) { result = ucol_initCollator((const UCATableHeader *)bin, result, base, status); if(U_FAILURE(*status)){ return NULL; } result->hasRealData = TRUE; - } else { + } + else { if(base) { result = ucol_initCollator(base->image, result, base, status); ucol_setOptionsFromHeader(result, (UColOptionSet *)(bin+((const UCATableHeader *)bin)->options), status); @@ -386,7 +388,8 @@ ucol_initFromBinary(const uint8_t *bin, int32_t length, return NULL; } result->hasRealData = FALSE; - } else { + } + else { *status = U_USELESS_COLLATOR_ERROR; return NULL; } @@ -411,6 +414,90 @@ ucol_openBinary(const uint8_t *bin, int32_t length, return ucol_initFromBinary(bin, length, base, NULL, status); } +U_CAPI UCollator* U_EXPORT2 +ucol_safeClone(const UCollator *coll, void *stackBuffer, int32_t * pBufferSize, UErrorCode *status) +{ + UCollator * localCollator; + int32_t bufferSizeNeeded = (int32_t)sizeof(UCollator); + char *stackBufferChars = (char *)stackBuffer; + int32_t imageSize = 0; + int32_t rulesSize = 0; + int32_t rulesPadding = 0; + uint8_t *image; + UChar *rules; + + if (status == NULL || U_FAILURE(*status)){ + return 0; + } + if ((stackBuffer && !pBufferSize) || !coll){ + *status = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + /* Pointers on 64-bit platforms need to be aligned + * on a 64-bit boundry in memory. + */ + if (U_ALIGNMENT_OFFSET(stackBuffer) != 0) { + int32_t offsetUp = (int32_t)U_ALIGNMENT_OFFSET_UP(stackBufferChars); + *pBufferSize -= offsetUp; + stackBufferChars += offsetUp; + } + stackBuffer = (void *)stackBufferChars; + + if (!coll->freeImageOnClose) { + UErrorCode tempStatus = U_ZERO_ERROR; + imageSize = ucol_cloneBinary(coll, NULL, 0, &tempStatus); + } + if (coll->rules && coll->freeRulesOnClose) { + rulesSize = (int32_t)(coll->rulesLength + 1)*sizeof(UChar); + rulesPadding = (int32_t)(bufferSizeNeeded % sizeof(UChar)); + bufferSizeNeeded += rulesSize + rulesPadding; + } + if (stackBuffer && *pBufferSize <= 0){ /* 'preflighting' request - set needed size into *pBufferSize */ + *pBufferSize = bufferSizeNeeded; + return 0; + } + + if (!stackBuffer || *pBufferSize < bufferSizeNeeded) { + /* allocate one here...*/ + stackBufferChars = (char *)uprv_malloc(bufferSizeNeeded); + if (U_SUCCESS(*status)) { + *status = U_SAFECLONE_ALLOCATED_WARNING; + } + } + localCollator = (UCollator *)stackBufferChars; + rules = (UChar *)(stackBufferChars + sizeof(UCollator) + rulesPadding); + if (imageSize > 0) { + image = (uint8_t *)uprv_malloc(imageSize); + ucol_cloneBinary(coll, image, imageSize, status); + } + else { + image = (uint8_t *)coll->image; + } + localCollator = ucol_initFromBinary(image, imageSize, coll->UCA, localCollator, status); + + if (coll->rules) { + if (coll->freeRulesOnClose) { + localCollator->rules = u_strcpy(rules, coll->rules); + //bufferEnd += rulesSize; + } + else { + localCollator->rules = coll->rules; + } + localCollator->freeRulesOnClose = FALSE; + localCollator->rulesLength = coll->rulesLength; + } + + int32_t i; + for(i = 0; i < UCOL_ATTRIBUTE_COUNT; i++) { + ucol_setAttribute(localCollator, (UColAttribute)i, ucol_getAttribute(coll, (UColAttribute)i, status), status); + } + localCollator->requestedLocale = NULL; // zero copies of pointers + localCollator->validLocale = NULL; + localCollator->rb = NULL; + localCollator->elements = NULL; + return localCollator; +} + U_CAPI void U_EXPORT2 ucol_close(UCollator *coll) { diff --git a/icu4c/source/i18n/ucol_res.cpp b/icu4c/source/i18n/ucol_res.cpp index 74016a4478c..578fa8a36e0 100644 --- a/icu4c/source/i18n/ucol_res.cpp +++ b/icu4c/source/i18n/ucol_res.cpp @@ -108,7 +108,6 @@ ucol_open_internal(const char *loc, collElem = ures_getByKeyWithFallback(collations, keyBuffer, collElem, status); UResourceBundle *binary = NULL; - UErrorCode binaryStatus = U_ZERO_ERROR; if(*status == U_MISSING_RESOURCE_ERROR) { /* We didn't find the tailoring data, we fallback to the UCA */ *status = U_USING_DEFAULT_WARNING; @@ -122,6 +121,9 @@ ucol_open_internal(const char *loc, ures_close(b); result->hasRealData = FALSE; } else if(U_SUCCESS(*status)) { + int32_t len = 0; + UErrorCode binaryStatus = U_ZERO_ERROR; + binary = ures_getByKey(collElem, "%%CollationBin", NULL, &binaryStatus); if(binaryStatus == U_MISSING_RESOURCE_ERROR) { /* we didn't find the binary image, we should use the rules */ @@ -131,37 +133,42 @@ ucol_open_internal(const char *loc, goto clean; } } else if(U_SUCCESS(*status)) { /* otherwise, we'll pick a collation data that exists */ - int32_t len = 0; const uint8_t *inData = ures_getBinary(binary, &len, status); UCATableHeader *colData = (UCATableHeader *)inData; if(uprv_memcmp(colData->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo)) != 0 || uprv_memcmp(colData->UCDVersion, UCA->image->UCDVersion, sizeof(UVersionInfo)) != 0 || - colData->version[0] != UCOL_BUILDER_VERSION) { - *status = U_DIFFERENT_UCA_VERSION; - result = tryOpeningFromRules(collElem, status); - } else { + colData->version[0] != UCOL_BUILDER_VERSION) + { + *status = U_DIFFERENT_UCA_VERSION; + result = tryOpeningFromRules(collElem, status); + } else { + if(U_FAILURE(*status)){ + goto clean; + } + if((uint32_t)len > (paddedsize(sizeof(UCATableHeader)) + paddedsize(sizeof(UColOptionSet)))) { + result = ucol_initCollator((const UCATableHeader *)inData, result, UCA, status); if(U_FAILURE(*status)){ goto clean; } - if((uint32_t)len > (paddedsize(sizeof(UCATableHeader)) + paddedsize(sizeof(UColOptionSet)))) { - result = ucol_initCollator((const UCATableHeader *)inData, result, UCA, status); - if(U_FAILURE(*status)){ - goto clean; - } - result->hasRealData = TRUE; - } else { - result = ucol_initCollator(UCA->image, result, UCA, status); - ucol_setOptionsFromHeader(result, (UColOptionSet *)(inData+((const UCATableHeader *)inData)->options), status); - if(U_FAILURE(*status)){ - goto clean; - } - result->hasRealData = FALSE; + result->hasRealData = TRUE; + } else { + result = ucol_initCollator(UCA->image, result, UCA, status); + ucol_setOptionsFromHeader(result, (UColOptionSet *)(inData+((const UCATableHeader *)inData)->options), status); + if(U_FAILURE(*status)){ + goto clean; } - result->freeImageOnClose = FALSE; + result->hasRealData = FALSE; } + result->freeImageOnClose = FALSE; + } } result->rb = b; result->elements = collElem; + len = 0; + binaryStatus = U_ZERO_ERROR; + result->rules = ures_getStringByKey(result->elements, "Sequence", &len, &binaryStatus); + result->rulesLength = len; + result->freeRulesOnClose = FALSE; } else { /* There is another error, and we're just gonna clean up */ goto clean; } @@ -397,23 +404,14 @@ U_CAPI const UChar* U_EXPORT2 ucol_getRules( const UCollator *coll, int32_t *length) { - if(coll->rules != NULL) { - *length = coll->rulesLength; - return coll->rules; - } else { - UErrorCode status = U_ZERO_ERROR; - if(coll->elements != NULL) { - if(U_SUCCESS(status)) { - /*Semantic const */ - ((UCollator *)coll)->rules = ures_getStringByKey(coll->elements, "Sequence", length, &status); - ((UCollator *)coll)->rulesLength = *length; - ((UCollator *)coll)->freeRulesOnClose = FALSE; + if(coll->rules != NULL) { + *length = coll->rulesLength; return coll->rules; - } } - *length = 0; - return &_NUL; - } + else { + *length = 0; + return &_NUL; + } } U_CAPI UBool U_EXPORT2 @@ -718,57 +716,4 @@ ucol_getTailoredSet(const UCollator *coll, UErrorCode *status) return (USet *)tailored; } -U_CAPI UCollator* U_EXPORT2 -ucol_safeClone(const UCollator *coll, void *stackBuffer, int32_t * pBufferSize, UErrorCode *status) -{ - UCollator * localCollator; - int32_t bufferSizeNeeded = (int32_t)sizeof(UCollator); - char *stackBufferChars = (char *)stackBuffer; - - if (status == NULL || U_FAILURE(*status)){ - return 0; - } - if ((stackBuffer && !pBufferSize) || !coll){ - *status = U_ILLEGAL_ARGUMENT_ERROR; - return 0; - } - /* Pointers on 64-bit platforms need to be aligned - * on a 64-bit boundry in memory. - */ - if (U_ALIGNMENT_OFFSET(stackBuffer) != 0) { - int32_t offsetUp = (int32_t)U_ALIGNMENT_OFFSET_UP(stackBufferChars); - *pBufferSize -= offsetUp; - stackBufferChars += offsetUp; - } - stackBuffer = (void *)stackBufferChars; - - if (stackBuffer && *pBufferSize <= 0){ /* 'preflighting' request - set needed size into *pBufferSize */ - *pBufferSize = bufferSizeNeeded; - return 0; - } - if (!stackBuffer || *pBufferSize < bufferSizeNeeded) { - /* allocate one here...*/ - int32_t length; - const UChar * rules = ucol_getRules(coll, &length); - - localCollator = ucol_openRules(rules, - length, - ucol_getAttribute(coll, UCOL_NORMALIZATION_MODE, status), - ucol_getStrength(coll), - NULL, - status); - if (U_SUCCESS(*status)) - { - *status = U_SAFECLONE_ALLOCATED_WARNING; - } - } else { - localCollator = (UCollator *)stackBuffer; - uprv_memcpy(localCollator, coll, sizeof(UCollator)); - localCollator->freeOnClose = FALSE; - localCollator->requestedLocale = NULL; // zero copies of pointers - localCollator->validLocale = NULL; - } - return localCollator; -} - #endif /* #if !UCONFIG_NO_COLLATION */