ICU-5190 Fix ucol_safeClone to properly clone a collator.

X-SVN-Rev: 19629
This commit is contained in:
George Rhoten 2006-05-21 17:52:09 +00:00
parent d2ec6dee38
commit a4663ad545
2 changed files with 124 additions and 92 deletions

View file

@ -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)
{

View file

@ -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 */