diff --git a/icu4c/source/common/ucnv_ext.c b/icu4c/source/common/ucnv_ext.c index f18547672d6..9e334ed0db6 100644 --- a/icu4c/source/common/ucnv_ext.c +++ b/icu4c/source/common/ucnv_ext.c @@ -45,7 +45,7 @@ */ static U_INLINE uint32_t ucnv_extFindToU(const uint32_t *toUSection, int32_t length, uint8_t byte) { - uint32_t word; + uint32_t word0, word; int32_t i, start, limit; /* check the input byte against the lowest and highest section bytes */ @@ -60,6 +60,9 @@ ucnv_extFindToU(const uint32_t *toUSection, int32_t length, uint8_t byte) { return UCNV_EXT_TO_U_GET_VALUE(toUSection[byte-start]); /* could be 0 */ } + /* word0 is suitable for <=toUSection[] comparison, word for =toUSection[start]) { + if(word<=toUSection[start]) { break; } - if(++start=toUSection[start]) { + if(++start=toUSection[start]) { + if(++startsharedData->table->mbcs.outputType!=MBCS_OUTPUT_2_SISO || \ + ((uint8_t)(cnv->mode)==0) == (match==1)) + /* * targetuseFallback, flush); - if(match>0) { + if(match>0 && UCNV_EXT_TO_U_VERIFY_SISO_MATCH(cnv, match)) { /* advance src pointer for the consumed input */ *src+=match-firstLength; @@ -351,7 +362,7 @@ ucnv_extContinueMatchToU(UConverter *cnv, pArgs->source, (int32_t)(pArgs->sourceLimit-pArgs->source), &value, cnv->useFallback, pArgs->flush); - if(match>0) { + if(match>0 && UCNV_EXT_TO_U_VERIFY_SISO_MATCH(cnv, match)) { if(match>=cnv->preToULength) { /* advance src pointer for the consumed input */ pArgs->source+=match-cnv->preToULength; @@ -440,13 +451,13 @@ ucnv_extFindFromU(const UChar *fromUSection, int32_t length, UChar u) { if(i<=4) { /* linear search for the last part */ - if(u>=fromUSection[start]) { + if(u<=fromUSection[start]) { break; } - if(++start=fromUSection[start]) { + if(++start=fromUSection[start]) { + if(++start>16); @@ -666,12 +677,40 @@ ucnv_extWriteFromU(UConverter *cnv, const int32_t *cx, default: break; /* will never occur */ } - result=buffer; + result=buffer+1; } else { result=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_BYTES_INDEX, uint8_t)+value; } - /* with correct data we have resultLength>0 */ + /* with correct data we have length>0 */ + + if((prevLength=cnv->fromUnicodeStatus)!=0) { + /* handle SI/SO stateful output */ + uint8_t shiftByte; + + if(prevLength>1 && length==1) { + /* change from double-byte mode to single-byte */ + shiftByte=(uint8_t)UCNV_SI; + cnv->fromUnicodeStatus=1; + } else if(prevLength==1 && length>1) { + /* change from single-byte mode to double-byte */ + shiftByte=(uint8_t)UCNV_SO; + cnv->fromUnicodeStatus=2; + } else { + shiftByte=0; + } + + if(shiftByte!=0) { + /* prepend the shift byte to the result bytes */ + buffer[0]=shiftByte; + if(result!=buffer+1) { + uprv_memcpy(buffer+1, result, length); + } + result=buffer; + ++length; + } + } + ucnv_fromUWriteBytes(cnv, (const char *)result, length, target, targetLimit, offsets, srcIndex,