ICU-1991 fix for safeclone on ISO-2022
X-SVN-Rev: 9582
This commit is contained in:
parent
0aacd9f8eb
commit
7f327f311d
@ -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:
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -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, ¤tConverterSize, 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, ¤tConverterSize, 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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user