// Use roundtrips, "good one-way" mappings, and some normal fallbacks. static inline UBool extFromUUseMapping(UBool useFallback, uint32_t value, UChar32 firstCP) { return ((value&UCNV_EXT_FROM_U_STATUS_MASK)!=0 || FROM_U_USE_FALLBACK(useFallback, firstCP)) && (value&UCNV_EXT_FROM_U_RESERVED_MASK)==0; }
/* * @param cx pointer to extension data; if NULL, returns 0 * @param firstCP the first code point before all the other UChars * @param pre UChars that must match; !initialMatch: partial match with them * @param preLength length of pre, >=0 * @param src UChars that can be used to complete a match * @param srcLength length of src, >=0 * @param pMatchValue [out] output result value for the match from the data structure * @param useFallback "use fallback" flag, usually from cnv->useFallback * @param flush TRUE if the end of the input stream is reached * @return >1: matched, return value=total match length (number of input units matched) * 1: matched, no mapping but request for <subchar1> * (only for the first code point) * 0: no match * <0: partial match, return value=negative total match length * (partial matches are never returned for flush==TRUE) * (partial matches are never returned as being longer than UCNV_EXT_MAX_UCHARS) * the matchLength is 2 if only firstCP matched, and >2 if firstCP and * further code units matched */ static int32_t ucnv_extMatchFromU(const int32_t *cx, UChar32 firstCP, const UChar *pre, int32_t preLength, const UChar *src, int32_t srcLength, uint32_t *pMatchValue, UBool useFallback, UBool flush) { const uint16_t *stage12, *stage3; const uint32_t *stage3b; const UChar *fromUTableUChars, *fromUSectionUChars; const uint32_t *fromUTableValues, *fromUSectionValues; uint32_t value, matchValue; int32_t i, j, index, length, matchLength; UChar c; if(cx==NULL) { return 0; /* no extension data, no match */ } /* trie lookup of firstCP */ index=firstCP>>10; /* stage 1 index */ if(index>=cx[UCNV_EXT_FROM_U_STAGE_1_LENGTH]) { return 0; /* the first code point is outside the trie */ } stage12=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_STAGE_12_INDEX, uint16_t); stage3=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_STAGE_3_INDEX, uint16_t); index=UCNV_EXT_FROM_U(stage12, stage3, index, firstCP); stage3b=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_STAGE_3B_INDEX, uint32_t); value=stage3b[index]; if(value==0) { return 0; } if(UCNV_EXT_TO_U_IS_PARTIAL(value)) { /* partial match, enter the loop below */ index=(int32_t)UCNV_EXT_FROM_U_GET_PARTIAL_INDEX(value); /* initialize */ fromUTableUChars=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_UCHARS_INDEX, UChar); fromUTableValues=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_VALUES_INDEX, uint32_t); matchValue=0; i=j=matchLength=0; /* we must not remember fallback matches when not using fallbacks */ /* match input units until there is a full match or the input is consumed */ for(;;) { /* go to the next section */ fromUSectionUChars=fromUTableUChars+index; fromUSectionValues=fromUTableValues+index; /* read first pair of the section */ length=*fromUSectionUChars++; value=*fromUSectionValues++; if( value!=0 && (UCNV_EXT_FROM_U_IS_ROUNDTRIP(value) || FROM_U_USE_FALLBACK(useFallback, firstCP)) ) { /* remember longest match so far */ matchValue=value; matchLength=2+i+j; } /* match pre[] then src[] */ if(i<preLength) { c=pre[i++]; } else if(j<srcLength) { c=src[j++]; } else { /* all input consumed, partial match */ if(flush || (length=(i+j))>UCNV_EXT_MAX_UCHARS) { /* * end of the entire input stream, stop with the longest match so far * or: partial match must not be longer than UCNV_EXT_MAX_UCHARS * because it must fit into state buffers */ break; } else { /* continue with more input next time */ return -(2+length); } } /* search for the current UChar */ index=ucnv_extFindFromU(fromUSectionUChars, length, c); if(index<0) { /* no match here, stop with the longest match so far */ break; } else { value=fromUSectionValues[index]; if(UCNV_EXT_FROM_U_IS_PARTIAL(value)) { /* partial match, continue */ index=(int32_t)UCNV_EXT_FROM_U_GET_PARTIAL_INDEX(value); } else { if( UCNV_EXT_FROM_U_IS_ROUNDTRIP(value) || FROM_U_USE_FALLBACK(useFallback, firstCP) ) { /* full match, stop with result */ matchValue=value; matchLength=2+i+j; } else { /* full match on fallback not taken, stop with the longest match so far */ } break; } } } if(matchLength==0) { /* no match at all */ return 0; } } else /* result from firstCP trie lookup */ { if( UCNV_EXT_FROM_U_IS_ROUNDTRIP(value) || FROM_U_USE_FALLBACK(useFallback, firstCP) ) { /* full match, stop with result */ matchValue=value; matchLength=2; } else { /* fallback not taken */ return 0; } } if(matchValue&UCNV_EXT_FROM_U_RESERVED_MASK) { /* do not interpret values with reserved bits used, for forward compatibility */ return 0; } /* return result */ if(matchValue==UCNV_EXT_FROM_U_SUBCHAR1) { return 1; /* assert matchLength==2 */ } *pMatchValue=UCNV_EXT_FROM_U_MASK_ROUNDTRIP(matchValue); return matchLength; }