ICU-1991 fix for safeclone on ISO-2022

X-SVN-Rev: 9582
This commit is contained in:
Steven R. Loomis 2002-08-05 22:55:17 +00:00
parent 0aacd9f8eb
commit 7f327f311d
3 changed files with 190 additions and 47 deletions

View File

@ -42,17 +42,44 @@ void UCNV_DEBUG_LOG(char *what, char *who, void *p, int l)
static FILE *f = NULL;
if(f==NULL)
{
f = fopen("c:\\UCNV_DEBUG_LOG.txt", "w");
/* stderr, or open another file */
f = stderr;
/* f = fopen("c:\\UCNV_DEBUG_LOG.txt", "w"); */
}
fprintf(f, "%-20s %-10s %p@%d\n",
who,what,p,l);
fprintf(f, "%p\t:%d\t%-20s\t%-10s\n",
p, l, who, what);
fflush(f);
}
/* dump the contents of a converter */
static void UCNV_DEBUG_CNV(UConverter *c, int line)
{
UErrorCode err = U_ZERO_ERROR;
fprintf(stderr, "%p\t:%d\t", c, line);
if(c!=NULL) {
fprintf(stderr, "%s\t", ucnv_getName(c, &err));
fprintf(stderr, "shr=%p, ref=%x\n",
c->sharedData,
c->sharedData->referenceCounter);
} else {
fprintf(stderr, "DEMISED\n");
}
}
# define UCNV_DEBUG 1
# define UCNV_DEBUG_LOG(x,y,z) UCNV_DEBUG_LOG(x,y,z,__LINE__)
# define UCNV_DEBUG_CNV(c) UCNV_DEBUG_CNV(c, __LINE__)
#else
# define UCNV_DEBUG_LOG(x,y,z)
# define UCNV_DEBUG_CNV(c)
#endif
/* size of intermediate and preflighting buffers in ucnv_convert() */
#define CHUNK_SIZE 5*1024
@ -86,11 +113,17 @@ U_CAPI UConverter* U_EXPORT2
ucnv_open (const char *name,
UErrorCode * err)
{
UConverter *r;
if (err == NULL || U_FAILURE (*err)) {
UCNV_DEBUG_LOG("open", name, NULL);
return NULL;
}
return ucnv_createConverter(name, err);
r = ucnv_createConverter(name, err);
UCNV_DEBUG_LOG("open", name, r);
UCNV_DEBUG_CNV(r);
return r;
}
U_CAPI UConverter* U_EXPORT2
@ -173,10 +206,16 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
if (status == NULL || U_FAILURE(*status)){
return 0;
}
if (!pBufferSize || !cnv){
*status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
UCNV_DEBUG_LOG("cloning FROM", ucnv_getName(cnv,status), cnv);
UCNV_DEBUG_LOG("cloning WITH", "memory", stackBuffer);
UCNV_DEBUG_CNV(cnv);
/* Pointers on 64-bit platforms need to be aligned
* on a 64-bit boundry in memory.
*/
@ -227,6 +266,16 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
localConverter = (UConverter*) stackBuffer;
}
/* Copy initial state */
uprv_memcpy(localConverter, cnv, sizeof(UConverter));
localConverter->isCopyLocal = FALSE;
/* now either call the safeclone fcn or not */
if (cnv->sharedData->impl->safeClone != NULL) {
/* call the custom safeClone function */
localConverter = cnv->sharedData->impl->safeClone(cnv, localConverter, pBufferSize, status);
}
/* increment refcount of shared data if needed */
if (cnv->sharedData->referenceCounter != ~0) {
umtx_lock (NULL);
@ -236,18 +285,24 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
umtx_unlock (NULL);
}
/* Copy initial state */
uprv_memcpy(localConverter, cnv, sizeof(UConverter));
/* now either call the safeclone fcn or not */
if (cnv->sharedData->impl->safeClone != NULL) {
/* call the custom safeClone function */
localConverter = cnv->sharedData->impl->safeClone(cnv, localConverter, pBufferSize, status);
if(localConverter==NULL || U_FAILURE(*status)) {
return NULL;
}
if(localConverter == (UConverter*)stackBuffer) {
/* we're using user provided data - set to not destroy */
localConverter->isCopyLocal = TRUE;
#ifdef UCNV_DEBUG
fprintf(stderr, "%p\t:%d\t\t==stackbuffer %p, isCopyLocal TRUE\n",
localConverter, __LINE__, stackBuffer);
#endif
} else {
#ifdef UCNV_DEBUG
fprintf(stderr, "%p\t:%d\t\t!=stackbuffer %p, isCopyLocal left at %s\n",
localConverter, __LINE__, stackBuffer,
localConverter->isCopyLocal?"TRUE":"FALSE");
#endif
}
/* allow callback functions to handle any memory allocation */
@ -257,6 +312,11 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
cbErr = U_ZERO_ERROR;
cnv->fromUCharErrorBehaviour(cnv->fromUContext, &fromUArgs, NULL, 0, 0, UCNV_CLONE, &cbErr);
UCNV_DEBUG_LOG("cloning TO", ucnv_getName(localConverter,status), localConverter);
UCNV_DEBUG_CNV(localConverter);
UCNV_DEBUG_CNV(cnv);
return localConverter;
}
@ -289,39 +349,54 @@ ucnv_close (UConverter * converter)
NULL,
NULL
};
UErrorCode errorCode;
UErrorCode errorCode = U_ZERO_ERROR;
if (converter == NULL)
{
return;
}
UCNV_DEBUG_LOG("close", ucnv_getName(converter, &errorCode), converter);
UCNV_DEBUG_CNV(converter);
toUArgs.converter = fromUArgs.converter = converter;
errorCode = U_ZERO_ERROR;
converter->fromCharErrorBehaviour(converter->toUContext, &toUArgs, NULL, 0, UCNV_CLOSE, &errorCode);
errorCode = U_ZERO_ERROR;
converter->fromUCharErrorBehaviour(converter->fromUContext, &fromUArgs, NULL, 0, 0, UCNV_CLOSE, &errorCode);
UCNV_DEBUG_CNV(converter);
if (converter->sharedData->impl->close != NULL) {
converter->sharedData->impl->close(converter);
}
#if 1
if(!converter->isCopyLocal)
#endif
if (converter->sharedData->referenceCounter != ~0) {
umtx_lock (NULL);
if (converter->sharedData->referenceCounter != 0) {
converter->sharedData->referenceCounter--;
}
umtx_unlock (NULL);
#ifdef UCNV_DEBUG
{
char c[4];
c[1]=0;
c[0]='0'+converter->sharedData->referenceCounter;
UCNV_DEBUG_LOG("close--", c, converter);
}
#endif
if((converter->sharedData->referenceCounter == 0)&&(converter->sharedData->sharedDataCached == FALSE)) {
UCNV_DEBUG_CNV(converter);
UCNV_DEBUG_LOG("close:delDead", "??", converter);
ucnv_deleteSharedConverterData(converter->sharedData);
}
}
if(!converter->isCopyLocal){
UCNV_DEBUG_LOG("close:free", "", converter);
uprv_free (converter);
}
return;
@ -1373,4 +1448,3 @@ ucnv_detectUnicodeSignature( const char* source,
* End:
*
*/

View File

@ -1,3 +1,4 @@
#include <stdio.h>
/*
**********************************************************************
* Copyright (C) 2000-2001, International Business Machines
@ -74,6 +75,7 @@ typedef enum {
}Cnv2022Type;
#define UCNV_OPTIONS_VERSION_MASK 0xf
#define UCNV_2022_MAX_CONVERTERS 10
typedef struct{
UConverter *currentConverter;
@ -84,7 +86,7 @@ typedef struct{
StateEnum toUnicodeSaveState;
Cnv2022Type currentType;
int plane;
UConverter* myConverterArray[10];
UConverter* myConverterArray[UCNV_2022_MAX_CONVERTERS];
UBool isEscapeAppended;
UBool isShiftAppended;
UBool isLocaleSpecified;
@ -671,24 +673,19 @@ _ISO2022Close(UConverter *converter) {
UConverter **array = myData->myConverterArray;
if (converter->extraInfo != NULL) {
if(!converter->isCopyLocal){
/*close the array of converter pointers and free the memory*/
while(*array!=NULL){
if(*array==myData->currentConverter){
myData->currentConverter=NULL;
}
ucnv_close(*array++);
/*close the array of converter pointers and free the memory*/
while(*array!=NULL){
if(*array==myData->currentConverter){
myData->currentConverter=NULL;
}
ucnv_close(*array++);
}
}
ucnv_close(myData->currentConverter);
ucnv_close(myData->currentConverter); /* if not closed above */
if(!converter->isCopyLocal){
uprv_free (converter->extraInfo);
}else{
/* close the currentConverter if and only if the
* ISO-2022 framework converter
*/
if(!myData->isLocaleSpecified){
ucnv_close(myData->currentConverter);
}
}
}
}
@ -3284,9 +3281,13 @@ struct cloneStruct
UConverter cnv;
UConverterDataISO2022 mydata;
UConverter currentCnv; /**< for ISO_2022 converter if the current converter is open */
UConverter clonedConverters[1]; /* Actually a variable sized array for all of the sub converters to be cloned. */
};
static UConverter *
/* static */
UConverter *
_ISO_2022_SafeClone(
const UConverter *cnv,
void *stackBuffer,
@ -3296,36 +3297,104 @@ _ISO_2022_SafeClone(
struct cloneStruct * localClone;
int32_t bufferSizeNeeded = sizeof(struct cloneStruct);
UConverterDataISO2022* cnvData = (UConverterDataISO2022*)cnv->extraInfo;
int32_t i;
int32_t sizes[UCNV_2022_MAX_CONVERTERS];
int32_t numConverters = 0;
int32_t currentConverterIndex = -1;
int32_t fromUnicodeConverterIndex = -1;
int32_t currentConverterSize = 0;
char *ptr; /* buffer pointer */
if (U_FAILURE(*status)){
if (U_FAILURE(*status)) {
return 0;
}
if (*pBufferSize == 0){ /* 'preflighting' request - set needed size into *pBufferSize */
for(i=0;(i<UCNV_2022_MAX_CONVERTERS)&&cnvData->myConverterArray[i];i++) {
int32_t size;
size = 0;
ucnv_safeClone(cnvData->myConverterArray[i], NULL, &size, status);
bufferSizeNeeded += size;
sizes[i] = size;
numConverters++;
if(cnvData->currentConverter == cnvData->myConverterArray[i]) {
currentConverterIndex = i;
}
if(cnvData->fromUnicodeConverter == cnvData->myConverterArray[i]) {
fromUnicodeConverterIndex = i;
}
}
if(currentConverterIndex == -1) { /* -1 means - not found in array. Clone separately */
currentConverterSize = 0;
if(cnvData->currentConverter) {
ucnv_safeClone(cnvData->currentConverter, NULL, &currentConverterSize, status);
bufferSizeNeeded += currentConverterSize;
}
}
for(;i<UCNV_2022_MAX_CONVERTERS;i++) { /* zero the other sizes */
sizes[i]=0;
}
if (*pBufferSize == 0) { /* 'preflighting' request - set needed size into *pBufferSize */
*pBufferSize = bufferSizeNeeded;
return 0;
}
if(*pBufferSize < bufferSizeNeeded) {
*status = U_BUFFER_OVERFLOW_ERROR;
return 0;
}
localClone = (struct cloneStruct *)stackBuffer;
uprv_memcpy(&localClone->cnv, cnv, sizeof(UConverter));
uprv_memcpy(&localClone->mydata, cnv->extraInfo, sizeof(UConverterDataISO2022));
/* clone the current converter if it is open in ISO-2022 converter and since it
* preserves conversion state in currentConverter object we need to clone it
*/
if((!cnvData->isLocaleSpecified && cnvData->currentConverter!=NULL) ||
/* clone back sub cnvs */
ptr = (char*)&localClone->clonedConverters;
for(i=0;i<numConverters;i++) {
int32_t size;
size = sizes[i];
localClone->mydata.myConverterArray[i] = ucnv_safeClone(cnvData->myConverterArray[i], (UConverter*)ptr, &size, status);
ptr += size;
}
for(;i<UCNV_2022_MAX_CONVERTERS;i++) {
localClone->mydata.myConverterArray[i] = NULL;
}
if(currentConverterIndex == -1) { /* -1 = not found in list */
/* KR version 1 also uses the state in currentConverter for preserving state
* so we need to clone it too!
*/
(cnvData->isLocaleSpecified && cnvData->locale[0]=='k' && cnvData->version==1)){
if(cnvData->currentConverter) {
localClone->mydata.currentConverter = ucnv_safeClone(cnvData->currentConverter, ptr, &currentConverterSize, status);
ptr += currentConverterSize;
} else {
localClone->mydata.currentConverter = NULL;
}
} else {
localClone->mydata.currentConverter = localClone->mydata.myConverterArray[currentConverterIndex];
}
uprv_memcpy(&localClone->currentCnv, cnvData->currentConverter, sizeof(UConverter));
localClone->mydata.currentConverter = &localClone->currentCnv;
if(fromUnicodeConverterIndex != -1) {
/* fromUnicodeConverter is in the list */
localClone->mydata.fromUnicodeConverter = localClone->mydata.myConverterArray[fromUnicodeConverterIndex];
} else if(cnvData->currentConverter == cnvData->fromUnicodeConverter) {
/* fromUnicodeConverter is the same as currentConverter */
localClone->mydata.fromUnicodeConverter = localClone->mydata.currentConverter;
} else {
/* fromUnicodeConverter is NULL */
localClone->mydata.fromUnicodeConverter = NULL;
}
localClone->cnv.extraInfo = &localClone->mydata;
localClone->cnv.extraInfo = &localClone->mydata; /* set pointer to extra data */
return &localClone->cnv;
}

View File

@ -379,7 +379,7 @@ ucnv_safeClone(const UConverter *cnv,
UErrorCode *status);
/** @draft ICU 1.8 */
#define U_CNV_SAFECLONE_BUFFERSIZE 512
#define U_CNV_SAFECLONE_BUFFERSIZE 3072
/**
* Deletes the unicode converter and releases resources associated