LCOV - code coverage report
Current view: top level - intl/icu/source/common - normalizer2impl.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 38 1064 3.6 %
Date: 2017-07-14 16:53:18 Functions: 2 64 3.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*
       4             : *******************************************************************************
       5             : *
       6             : *   Copyright (C) 2009-2014, International Business Machines
       7             : *   Corporation and others.  All Rights Reserved.
       8             : *
       9             : *******************************************************************************
      10             : *   file name:  normalizer2impl.cpp
      11             : *   encoding:   UTF-8
      12             : *   tab size:   8 (not used)
      13             : *   indentation:4
      14             : *
      15             : *   created on: 2009nov22
      16             : *   created by: Markus W. Scherer
      17             : */
      18             : 
      19             : #include "unicode/utypes.h"
      20             : 
      21             : #if !UCONFIG_NO_NORMALIZATION
      22             : 
      23             : #include "unicode/normalizer2.h"
      24             : #include "unicode/udata.h"
      25             : #include "unicode/ustring.h"
      26             : #include "unicode/utf16.h"
      27             : #include "cmemory.h"
      28             : #include "mutex.h"
      29             : #include "normalizer2impl.h"
      30             : #include "putilimp.h"
      31             : #include "uassert.h"
      32             : #include "uset_imp.h"
      33             : #include "utrie2.h"
      34             : #include "uvector.h"
      35             : 
      36             : U_NAMESPACE_BEGIN
      37             : 
      38             : // ReorderingBuffer -------------------------------------------------------- ***
      39             : 
      40           0 : UBool ReorderingBuffer::init(int32_t destCapacity, UErrorCode &errorCode) {
      41           0 :     int32_t length=str.length();
      42           0 :     start=str.getBuffer(destCapacity);
      43           0 :     if(start==NULL) {
      44             :         // getBuffer() already did str.setToBogus()
      45           0 :         errorCode=U_MEMORY_ALLOCATION_ERROR;
      46           0 :         return FALSE;
      47             :     }
      48           0 :     limit=start+length;
      49           0 :     remainingCapacity=str.getCapacity()-length;
      50           0 :     reorderStart=start;
      51           0 :     if(start==limit) {
      52           0 :         lastCC=0;
      53             :     } else {
      54           0 :         setIterator();
      55           0 :         lastCC=previousCC();
      56             :         // Set reorderStart after the last code point with cc<=1 if there is one.
      57           0 :         if(lastCC>1) {
      58           0 :             while(previousCC()>1) {}
      59             :         }
      60           0 :         reorderStart=codePointLimit;
      61             :     }
      62           0 :     return TRUE;
      63             : }
      64             : 
      65           0 : UBool ReorderingBuffer::equals(const UChar *otherStart, const UChar *otherLimit) const {
      66           0 :     int32_t length=(int32_t)(limit-start);
      67             :     return
      68           0 :         length==(int32_t)(otherLimit-otherStart) &&
      69           0 :         0==u_memcmp(start, otherStart, length);
      70             : }
      71             : 
      72           0 : UBool ReorderingBuffer::appendSupplementary(UChar32 c, uint8_t cc, UErrorCode &errorCode) {
      73           0 :     if(remainingCapacity<2 && !resize(2, errorCode)) {
      74           0 :         return FALSE;
      75             :     }
      76           0 :     if(lastCC<=cc || cc==0) {
      77           0 :         limit[0]=U16_LEAD(c);
      78           0 :         limit[1]=U16_TRAIL(c);
      79           0 :         limit+=2;
      80           0 :         lastCC=cc;
      81           0 :         if(cc<=1) {
      82           0 :             reorderStart=limit;
      83             :         }
      84             :     } else {
      85           0 :         insert(c, cc);
      86             :     }
      87           0 :     remainingCapacity-=2;
      88           0 :     return TRUE;
      89             : }
      90             : 
      91           0 : UBool ReorderingBuffer::append(const UChar *s, int32_t length,
      92             :                                uint8_t leadCC, uint8_t trailCC,
      93             :                                UErrorCode &errorCode) {
      94           0 :     if(length==0) {
      95           0 :         return TRUE;
      96             :     }
      97           0 :     if(remainingCapacity<length && !resize(length, errorCode)) {
      98           0 :         return FALSE;
      99             :     }
     100           0 :     remainingCapacity-=length;
     101           0 :     if(lastCC<=leadCC || leadCC==0) {
     102           0 :         if(trailCC<=1) {
     103           0 :             reorderStart=limit+length;
     104           0 :         } else if(leadCC<=1) {
     105           0 :             reorderStart=limit+1;  // Ok if not a code point boundary.
     106             :         }
     107           0 :         const UChar *sLimit=s+length;
     108           0 :         do { *limit++=*s++; } while(s!=sLimit);
     109           0 :         lastCC=trailCC;
     110             :     } else {
     111           0 :         int32_t i=0;
     112             :         UChar32 c;
     113           0 :         U16_NEXT(s, i, length, c);
     114           0 :         insert(c, leadCC);  // insert first code point
     115           0 :         while(i<length) {
     116           0 :             U16_NEXT(s, i, length, c);
     117           0 :             if(i<length) {
     118             :                 // s must be in NFD, otherwise we need to use getCC().
     119           0 :                 leadCC=Normalizer2Impl::getCCFromYesOrMaybe(impl.getNorm16(c));
     120             :             } else {
     121           0 :                 leadCC=trailCC;
     122             :             }
     123           0 :             append(c, leadCC, errorCode);
     124             :         }
     125             :     }
     126           0 :     return TRUE;
     127             : }
     128             : 
     129           0 : UBool ReorderingBuffer::appendZeroCC(UChar32 c, UErrorCode &errorCode) {
     130           0 :     int32_t cpLength=U16_LENGTH(c);
     131           0 :     if(remainingCapacity<cpLength && !resize(cpLength, errorCode)) {
     132           0 :         return FALSE;
     133             :     }
     134           0 :     remainingCapacity-=cpLength;
     135           0 :     if(cpLength==1) {
     136           0 :         *limit++=(UChar)c;
     137             :     } else {
     138           0 :         limit[0]=U16_LEAD(c);
     139           0 :         limit[1]=U16_TRAIL(c);
     140           0 :         limit+=2;
     141             :     }
     142           0 :     lastCC=0;
     143           0 :     reorderStart=limit;
     144           0 :     return TRUE;
     145             : }
     146             : 
     147           0 : UBool ReorderingBuffer::appendZeroCC(const UChar *s, const UChar *sLimit, UErrorCode &errorCode) {
     148           0 :     if(s==sLimit) {
     149           0 :         return TRUE;
     150             :     }
     151           0 :     int32_t length=(int32_t)(sLimit-s);
     152           0 :     if(remainingCapacity<length && !resize(length, errorCode)) {
     153           0 :         return FALSE;
     154             :     }
     155           0 :     u_memcpy(limit, s, length);
     156           0 :     limit+=length;
     157           0 :     remainingCapacity-=length;
     158           0 :     lastCC=0;
     159           0 :     reorderStart=limit;
     160           0 :     return TRUE;
     161             : }
     162             : 
     163           0 : void ReorderingBuffer::remove() {
     164           0 :     reorderStart=limit=start;
     165           0 :     remainingCapacity=str.getCapacity();
     166           0 :     lastCC=0;
     167           0 : }
     168             : 
     169           0 : void ReorderingBuffer::removeSuffix(int32_t suffixLength) {
     170           0 :     if(suffixLength<(limit-start)) {
     171           0 :         limit-=suffixLength;
     172           0 :         remainingCapacity+=suffixLength;
     173             :     } else {
     174           0 :         limit=start;
     175           0 :         remainingCapacity=str.getCapacity();
     176             :     }
     177           0 :     lastCC=0;
     178           0 :     reorderStart=limit;
     179           0 : }
     180             : 
     181           0 : UBool ReorderingBuffer::resize(int32_t appendLength, UErrorCode &errorCode) {
     182           0 :     int32_t reorderStartIndex=(int32_t)(reorderStart-start);
     183           0 :     int32_t length=(int32_t)(limit-start);
     184           0 :     str.releaseBuffer(length);
     185           0 :     int32_t newCapacity=length+appendLength;
     186           0 :     int32_t doubleCapacity=2*str.getCapacity();
     187           0 :     if(newCapacity<doubleCapacity) {
     188           0 :         newCapacity=doubleCapacity;
     189             :     }
     190           0 :     if(newCapacity<256) {
     191           0 :         newCapacity=256;
     192             :     }
     193           0 :     start=str.getBuffer(newCapacity);
     194           0 :     if(start==NULL) {
     195             :         // getBuffer() already did str.setToBogus()
     196           0 :         errorCode=U_MEMORY_ALLOCATION_ERROR;
     197           0 :         return FALSE;
     198             :     }
     199           0 :     reorderStart=start+reorderStartIndex;
     200           0 :     limit=start+length;
     201           0 :     remainingCapacity=str.getCapacity()-length;
     202           0 :     return TRUE;
     203             : }
     204             : 
     205           0 : void ReorderingBuffer::skipPrevious() {
     206           0 :     codePointLimit=codePointStart;
     207           0 :     UChar c=*--codePointStart;
     208           0 :     if(U16_IS_TRAIL(c) && start<codePointStart && U16_IS_LEAD(*(codePointStart-1))) {
     209           0 :         --codePointStart;
     210             :     }
     211           0 : }
     212             : 
     213           0 : uint8_t ReorderingBuffer::previousCC() {
     214           0 :     codePointLimit=codePointStart;
     215           0 :     if(reorderStart>=codePointStart) {
     216           0 :         return 0;
     217             :     }
     218           0 :     UChar32 c=*--codePointStart;
     219           0 :     if(c<Normalizer2Impl::MIN_CCC_LCCC_CP) {
     220           0 :         return 0;
     221             :     }
     222             : 
     223             :     UChar c2;
     224           0 :     if(U16_IS_TRAIL(c) && start<codePointStart && U16_IS_LEAD(c2=*(codePointStart-1))) {
     225           0 :         --codePointStart;
     226           0 :         c=U16_GET_SUPPLEMENTARY(c2, c);
     227             :     }
     228           0 :     return Normalizer2Impl::getCCFromYesOrMaybe(impl.getNorm16(c));
     229             : }
     230             : 
     231             : // Inserts c somewhere before the last character.
     232             : // Requires 0<cc<lastCC which implies reorderStart<limit.
     233           0 : void ReorderingBuffer::insert(UChar32 c, uint8_t cc) {
     234           0 :     for(setIterator(), skipPrevious(); previousCC()>cc;) {}
     235             :     // insert c at codePointLimit, after the character with prevCC<=cc
     236           0 :     UChar *q=limit;
     237           0 :     UChar *r=limit+=U16_LENGTH(c);
     238           0 :     do {
     239           0 :         *--r=*--q;
     240           0 :     } while(codePointLimit!=q);
     241           0 :     writeCodePoint(q, c);
     242           0 :     if(cc<=1) {
     243           0 :         reorderStart=r;
     244             :     }
     245           0 : }
     246             : 
     247             : // Normalizer2Impl --------------------------------------------------------- ***
     248             : 
     249             : struct CanonIterData : public UMemory {
     250             :     CanonIterData(UErrorCode &errorCode);
     251             :     ~CanonIterData();
     252             :     void addToStartSet(UChar32 origin, UChar32 decompLead, UErrorCode &errorCode);
     253             :     UTrie2 *trie;
     254             :     UVector canonStartSets;  // contains UnicodeSet *
     255             : };
     256             : 
     257           0 : Normalizer2Impl::~Normalizer2Impl() {
     258           0 :     delete fCanonIterData;
     259           0 : }
     260             : 
     261             : void
     262           5 : Normalizer2Impl::init(const int32_t *inIndexes, const UTrie2 *inTrie,
     263             :                       const uint16_t *inExtraData, const uint8_t *inSmallFCD) {
     264           5 :     minDecompNoCP=inIndexes[IX_MIN_DECOMP_NO_CP];
     265           5 :     minCompNoMaybeCP=inIndexes[IX_MIN_COMP_NO_MAYBE_CP];
     266             : 
     267           5 :     minYesNo=inIndexes[IX_MIN_YES_NO];
     268           5 :     minYesNoMappingsOnly=inIndexes[IX_MIN_YES_NO_MAPPINGS_ONLY];
     269           5 :     minNoNo=inIndexes[IX_MIN_NO_NO];
     270           5 :     limitNoNo=inIndexes[IX_LIMIT_NO_NO];
     271           5 :     minMaybeYes=inIndexes[IX_MIN_MAYBE_YES];
     272             : 
     273           5 :     normTrie=inTrie;
     274             : 
     275           5 :     maybeYesCompositions=inExtraData;
     276           5 :     extraData=maybeYesCompositions+(MIN_NORMAL_MAYBE_YES-minMaybeYes);
     277             : 
     278           5 :     smallFCD=inSmallFCD;
     279             : 
     280             :     // Build tccc180[].
     281             :     // gennorm2 enforces lccc=0 for c<MIN_CCC_LCCC_CP=U+0300.
     282           5 :     uint8_t bits=0;
     283          65 :     for(UChar c=0; c<0x180; bits>>=1) {
     284          60 :         if((c&0xff)==0) {
     285          10 :             bits=smallFCD[c>>8];  // one byte per 0x100 code points
     286             :         }
     287          60 :         if(bits&1) {
     288         990 :             for(int i=0; i<0x20; ++i, ++c) {
     289         960 :                 tccc180[c]=(uint8_t)getFCD16FromNormData(c);
     290             :             }
     291             :         } else {
     292          30 :             uprv_memset(tccc180+c, 0, 0x20);
     293          30 :             c+=0x20;
     294             :         }
     295             :     }
     296           5 : }
     297             : 
     298           0 : uint8_t Normalizer2Impl::getTrailCCFromCompYesAndZeroCC(const UChar *cpStart, const UChar *cpLimit) const {
     299             :     UChar32 c;
     300           0 :     if(cpStart==(cpLimit-1)) {
     301           0 :         c=*cpStart;
     302             :     } else {
     303           0 :         c=U16_GET_SUPPLEMENTARY(cpStart[0], cpStart[1]);
     304             :     }
     305           0 :     uint16_t prevNorm16=getNorm16(c);
     306           0 :     if(prevNorm16<=minYesNo) {
     307           0 :         return 0;  // yesYes and Hangul LV/LVT have ccc=tccc=0
     308             :     } else {
     309           0 :         return (uint8_t)(*getMapping(prevNorm16)>>8);  // tccc from yesNo
     310             :     }
     311             : }
     312             : 
     313             : namespace {
     314             : 
     315             : class LcccContext {
     316             : public:
     317           0 :     LcccContext(const Normalizer2Impl &ni, UnicodeSet &s) : impl(ni), set(s) {}
     318             : 
     319           0 :     void handleRange(UChar32 start, UChar32 end, uint16_t norm16) {
     320           0 :         if(impl.isAlgorithmicNoNo(norm16)) {
     321             :             // Range of code points with same-norm16-value algorithmic decompositions.
     322             :             // They might have different non-zero FCD16 values.
     323           0 :             do {
     324           0 :                 uint16_t fcd16=impl.getFCD16(start);
     325           0 :                 if(fcd16>0xff) { set.add(start); }
     326             :             } while(++start<=end);
     327             :         } else {
     328           0 :             uint16_t fcd16=impl.getFCD16(start);
     329           0 :             if(fcd16>0xff) { set.add(start, end); }
     330             :         }
     331           0 :     }
     332             : 
     333             : private:
     334             :     const Normalizer2Impl &impl;
     335             :     UnicodeSet &set;
     336             : };
     337             : 
     338             : struct PropertyStartsContext {
     339           0 :     PropertyStartsContext(const Normalizer2Impl &ni, const USetAdder *adder)
     340           0 :             : impl(ni), sa(adder) {}
     341             : 
     342             :     const Normalizer2Impl &impl;
     343             :     const USetAdder *sa;
     344             : };
     345             : 
     346             : }  // namespace
     347             : 
     348             : U_CDECL_BEGIN
     349             : 
     350             : static UBool U_CALLCONV
     351           0 : enumLcccRange(const void *context, UChar32 start, UChar32 end, uint32_t value) {
     352           0 :     ((LcccContext *)context)->handleRange(start, end, (uint16_t)value);
     353           0 :     return TRUE;
     354             : }
     355             : 
     356             : static UBool U_CALLCONV
     357           0 : enumNorm16PropertyStartsRange(const void *context, UChar32 start, UChar32 end, uint32_t value) {
     358             :     /* add the start code point to the USet */
     359           0 :     const PropertyStartsContext *ctx=(const PropertyStartsContext *)context;
     360           0 :     const USetAdder *sa=ctx->sa;
     361           0 :     sa->add(sa->set, start);
     362           0 :     if(start!=end && ctx->impl.isAlgorithmicNoNo((uint16_t)value)) {
     363             :         // Range of code points with same-norm16-value algorithmic decompositions.
     364             :         // They might have different non-zero FCD16 values.
     365           0 :         uint16_t prevFCD16=ctx->impl.getFCD16(start);
     366           0 :         while(++start<=end) {
     367           0 :             uint16_t fcd16=ctx->impl.getFCD16(start);
     368           0 :             if(fcd16!=prevFCD16) {
     369           0 :                 sa->add(sa->set, start);
     370           0 :                 prevFCD16=fcd16;
     371             :             }
     372             :         }
     373             :     }
     374           0 :     return TRUE;
     375             : }
     376             : 
     377             : static UBool U_CALLCONV
     378           0 : enumPropertyStartsRange(const void *context, UChar32 start, UChar32 /*end*/, uint32_t /*value*/) {
     379             :     /* add the start code point to the USet */
     380           0 :     const USetAdder *sa=(const USetAdder *)context;
     381           0 :     sa->add(sa->set, start);
     382           0 :     return TRUE;
     383             : }
     384             : 
     385             : static uint32_t U_CALLCONV
     386           0 : segmentStarterMapper(const void * /*context*/, uint32_t value) {
     387           0 :     return value&CANON_NOT_SEGMENT_STARTER;
     388             : }
     389             : 
     390             : U_CDECL_END
     391             : 
     392             : void
     393           0 : Normalizer2Impl::addLcccChars(UnicodeSet &set) const {
     394             :     /* add the start code point of each same-value range of each trie */
     395           0 :     LcccContext context(*this, set);
     396           0 :     utrie2_enum(normTrie, NULL, enumLcccRange, &context);
     397           0 : }
     398             : 
     399             : void
     400           0 : Normalizer2Impl::addPropertyStarts(const USetAdder *sa, UErrorCode & /*errorCode*/) const {
     401             :     /* add the start code point of each same-value range of each trie */
     402           0 :     PropertyStartsContext context(*this, sa);
     403           0 :     utrie2_enum(normTrie, NULL, enumNorm16PropertyStartsRange, &context);
     404             : 
     405             :     /* add Hangul LV syllables and LV+1 because of skippables */
     406           0 :     for(UChar c=Hangul::HANGUL_BASE; c<Hangul::HANGUL_LIMIT; c+=Hangul::JAMO_T_COUNT) {
     407           0 :         sa->add(sa->set, c);
     408           0 :         sa->add(sa->set, c+1);
     409             :     }
     410           0 :     sa->add(sa->set, Hangul::HANGUL_LIMIT); /* add Hangul+1 to continue with other properties */
     411           0 : }
     412             : 
     413             : void
     414           0 : Normalizer2Impl::addCanonIterPropertyStarts(const USetAdder *sa, UErrorCode &errorCode) const {
     415             :     /* add the start code point of each same-value range of the canonical iterator data trie */
     416           0 :     if(ensureCanonIterData(errorCode)) {
     417             :         // currently only used for the SEGMENT_STARTER property
     418           0 :         utrie2_enum(fCanonIterData->trie, segmentStarterMapper, enumPropertyStartsRange, sa);
     419             :     }
     420           0 : }
     421             : 
     422             : const UChar *
     423           0 : Normalizer2Impl::copyLowPrefixFromNulTerminated(const UChar *src,
     424             :                                                 UChar32 minNeedDataCP,
     425             :                                                 ReorderingBuffer *buffer,
     426             :                                                 UErrorCode &errorCode) const {
     427             :     // Make some effort to support NUL-terminated strings reasonably.
     428             :     // Take the part of the fast quick check loop that does not look up
     429             :     // data and check the first part of the string.
     430             :     // After this prefix, determine the string length to simplify the rest
     431             :     // of the code.
     432           0 :     const UChar *prevSrc=src;
     433             :     UChar c;
     434           0 :     while((c=*src++)<minNeedDataCP && c!=0) {}
     435             :     // Back out the last character for full processing.
     436             :     // Copy this prefix.
     437           0 :     if(--src!=prevSrc) {
     438           0 :         if(buffer!=NULL) {
     439           0 :             buffer->appendZeroCC(prevSrc, src, errorCode);
     440             :         }
     441             :     }
     442           0 :     return src;
     443             : }
     444             : 
     445             : UnicodeString &
     446           0 : Normalizer2Impl::decompose(const UnicodeString &src, UnicodeString &dest,
     447             :                            UErrorCode &errorCode) const {
     448           0 :     if(U_FAILURE(errorCode)) {
     449           0 :         dest.setToBogus();
     450           0 :         return dest;
     451             :     }
     452           0 :     const UChar *sArray=src.getBuffer();
     453           0 :     if(&dest==&src || sArray==NULL) {
     454           0 :         errorCode=U_ILLEGAL_ARGUMENT_ERROR;
     455           0 :         dest.setToBogus();
     456           0 :         return dest;
     457             :     }
     458           0 :     decompose(sArray, sArray+src.length(), dest, src.length(), errorCode);
     459           0 :     return dest;
     460             : }
     461             : 
     462             : void
     463           0 : Normalizer2Impl::decompose(const UChar *src, const UChar *limit,
     464             :                            UnicodeString &dest,
     465             :                            int32_t destLengthEstimate,
     466             :                            UErrorCode &errorCode) const {
     467           0 :     if(destLengthEstimate<0 && limit!=NULL) {
     468           0 :         destLengthEstimate=(int32_t)(limit-src);
     469             :     }
     470           0 :     dest.remove();
     471           0 :     ReorderingBuffer buffer(*this, dest);
     472           0 :     if(buffer.init(destLengthEstimate, errorCode)) {
     473           0 :         decompose(src, limit, &buffer, errorCode);
     474             :     }
     475           0 : }
     476             : 
     477             : // Dual functionality:
     478             : // buffer!=NULL: normalize
     479             : // buffer==NULL: isNormalized/spanQuickCheckYes
     480             : const UChar *
     481           0 : Normalizer2Impl::decompose(const UChar *src, const UChar *limit,
     482             :                            ReorderingBuffer *buffer,
     483             :                            UErrorCode &errorCode) const {
     484           0 :     UChar32 minNoCP=minDecompNoCP;
     485           0 :     if(limit==NULL) {
     486           0 :         src=copyLowPrefixFromNulTerminated(src, minNoCP, buffer, errorCode);
     487           0 :         if(U_FAILURE(errorCode)) {
     488           0 :             return src;
     489             :         }
     490           0 :         limit=u_strchr(src, 0);
     491             :     }
     492             : 
     493             :     const UChar *prevSrc;
     494           0 :     UChar32 c=0;
     495           0 :     uint16_t norm16=0;
     496             : 
     497             :     // only for quick check
     498           0 :     const UChar *prevBoundary=src;
     499           0 :     uint8_t prevCC=0;
     500             : 
     501             :     for(;;) {
     502             :         // count code units below the minimum or with irrelevant data for the quick check
     503           0 :         for(prevSrc=src; src!=limit;) {
     504           0 :             if( (c=*src)<minNoCP ||
     505           0 :                 isMostDecompYesAndZeroCC(norm16=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(normTrie, c))
     506             :             ) {
     507           0 :                 ++src;
     508           0 :             } else if(!U16_IS_SURROGATE(c)) {
     509           0 :                 break;
     510             :             } else {
     511             :                 UChar c2;
     512           0 :                 if(U16_IS_SURROGATE_LEAD(c)) {
     513           0 :                     if((src+1)!=limit && U16_IS_TRAIL(c2=src[1])) {
     514           0 :                         c=U16_GET_SUPPLEMENTARY(c, c2);
     515             :                     }
     516             :                 } else /* trail surrogate */ {
     517           0 :                     if(prevSrc<src && U16_IS_LEAD(c2=*(src-1))) {
     518           0 :                         --src;
     519           0 :                         c=U16_GET_SUPPLEMENTARY(c2, c);
     520             :                     }
     521             :                 }
     522           0 :                 if(isMostDecompYesAndZeroCC(norm16=getNorm16(c))) {
     523           0 :                     src+=U16_LENGTH(c);
     524             :                 } else {
     525           0 :                     break;
     526             :                 }
     527             :             }
     528             :         }
     529             :         // copy these code units all at once
     530           0 :         if(src!=prevSrc) {
     531           0 :             if(buffer!=NULL) {
     532           0 :                 if(!buffer->appendZeroCC(prevSrc, src, errorCode)) {
     533           0 :                     break;
     534             :                 }
     535             :             } else {
     536           0 :                 prevCC=0;
     537           0 :                 prevBoundary=src;
     538             :             }
     539             :         }
     540           0 :         if(src==limit) {
     541           0 :             break;
     542             :         }
     543             : 
     544             :         // Check one above-minimum, relevant code point.
     545           0 :         src+=U16_LENGTH(c);
     546           0 :         if(buffer!=NULL) {
     547           0 :             if(!decompose(c, norm16, *buffer, errorCode)) {
     548           0 :                 break;
     549             :             }
     550             :         } else {
     551           0 :             if(isDecompYes(norm16)) {
     552           0 :                 uint8_t cc=getCCFromYesOrMaybe(norm16);
     553           0 :                 if(prevCC<=cc || cc==0) {
     554           0 :                     prevCC=cc;
     555           0 :                     if(cc<=1) {
     556           0 :                         prevBoundary=src;
     557             :                     }
     558           0 :                     continue;
     559             :                 }
     560             :             }
     561           0 :             return prevBoundary;  // "no" or cc out of order
     562             :         }
     563           0 :     }
     564           0 :     return src;
     565             : }
     566             : 
     567             : // Decompose a short piece of text which is likely to contain characters that
     568             : // fail the quick check loop and/or where the quick check loop's overhead
     569             : // is unlikely to be amortized.
     570             : // Called by the compose() and makeFCD() implementations.
     571           0 : UBool Normalizer2Impl::decomposeShort(const UChar *src, const UChar *limit,
     572             :                                       ReorderingBuffer &buffer,
     573             :                                       UErrorCode &errorCode) const {
     574           0 :     while(src<limit) {
     575             :         UChar32 c;
     576             :         uint16_t norm16;
     577           0 :         UTRIE2_U16_NEXT16(normTrie, src, limit, c, norm16);
     578           0 :         if(!decompose(c, norm16, buffer, errorCode)) {
     579           0 :             return FALSE;
     580             :         }
     581             :     }
     582           0 :     return TRUE;
     583             : }
     584             : 
     585           0 : UBool Normalizer2Impl::decompose(UChar32 c, uint16_t norm16,
     586             :                                  ReorderingBuffer &buffer,
     587             :                                  UErrorCode &errorCode) const {
     588             :     // Only loops for 1:1 algorithmic mappings.
     589             :     for(;;) {
     590             :         // get the decomposition and the lead and trail cc's
     591           0 :         if(isDecompYes(norm16)) {
     592             :             // c does not decompose
     593           0 :             return buffer.append(c, getCCFromYesOrMaybe(norm16), errorCode);
     594           0 :         } else if(isHangul(norm16)) {
     595             :             // Hangul syllable: decompose algorithmically
     596             :             UChar jamos[3];
     597           0 :             return buffer.appendZeroCC(jamos, jamos+Hangul::decompose(c, jamos), errorCode);
     598           0 :         } else if(isDecompNoAlgorithmic(norm16)) {
     599           0 :             c=mapAlgorithmic(c, norm16);
     600           0 :             norm16=getNorm16(c);
     601             :         } else {
     602             :             // c decomposes, get everything from the variable-length extra data
     603           0 :             const uint16_t *mapping=getMapping(norm16);
     604           0 :             uint16_t firstUnit=*mapping;
     605           0 :             int32_t length=firstUnit&MAPPING_LENGTH_MASK;
     606             :             uint8_t leadCC, trailCC;
     607           0 :             trailCC=(uint8_t)(firstUnit>>8);
     608           0 :             if(firstUnit&MAPPING_HAS_CCC_LCCC_WORD) {
     609           0 :                 leadCC=(uint8_t)(*(mapping-1)>>8);
     610             :             } else {
     611           0 :                 leadCC=0;
     612             :             }
     613           0 :             return buffer.append((const UChar *)mapping+1, length, leadCC, trailCC, errorCode);
     614             :         }
     615           0 :     }
     616             : }
     617             : 
     618             : const UChar *
     619           0 : Normalizer2Impl::getDecomposition(UChar32 c, UChar buffer[4], int32_t &length) const {
     620           0 :     const UChar *decomp=NULL;
     621             :     uint16_t norm16;
     622             :     for(;;) {
     623           0 :         if(c<minDecompNoCP || isDecompYes(norm16=getNorm16(c))) {
     624             :             // c does not decompose
     625           0 :             return decomp;
     626           0 :         } else if(isHangul(norm16)) {
     627             :             // Hangul syllable: decompose algorithmically
     628           0 :             length=Hangul::decompose(c, buffer);
     629           0 :             return buffer;
     630           0 :         } else if(isDecompNoAlgorithmic(norm16)) {
     631           0 :             c=mapAlgorithmic(c, norm16);
     632           0 :             decomp=buffer;
     633           0 :             length=0;
     634           0 :             U16_APPEND_UNSAFE(buffer, length, c);
     635             :         } else {
     636             :             // c decomposes, get everything from the variable-length extra data
     637           0 :             const uint16_t *mapping=getMapping(norm16);
     638           0 :             length=*mapping&MAPPING_LENGTH_MASK;
     639           0 :             return (const UChar *)mapping+1;
     640             :         }
     641           0 :     }
     642             : }
     643             : 
     644             : // The capacity of the buffer must be 30=MAPPING_LENGTH_MASK-1
     645             : // so that a raw mapping fits that consists of one unit ("rm0")
     646             : // plus all but the first two code units of the normal mapping.
     647             : // The maximum length of a normal mapping is 31=MAPPING_LENGTH_MASK.
     648             : const UChar *
     649           0 : Normalizer2Impl::getRawDecomposition(UChar32 c, UChar buffer[30], int32_t &length) const {
     650             :     // We do not loop in this method because an algorithmic mapping itself
     651             :     // becomes a final result rather than having to be decomposed recursively.
     652             :     uint16_t norm16;
     653           0 :     if(c<minDecompNoCP || isDecompYes(norm16=getNorm16(c))) {
     654             :         // c does not decompose
     655           0 :         return NULL;
     656           0 :     } else if(isHangul(norm16)) {
     657             :         // Hangul syllable: decompose algorithmically
     658           0 :         Hangul::getRawDecomposition(c, buffer);
     659           0 :         length=2;
     660           0 :         return buffer;
     661           0 :     } else if(isDecompNoAlgorithmic(norm16)) {
     662           0 :         c=mapAlgorithmic(c, norm16);
     663           0 :         length=0;
     664           0 :         U16_APPEND_UNSAFE(buffer, length, c);
     665           0 :         return buffer;
     666             :     } else {
     667             :         // c decomposes, get everything from the variable-length extra data
     668           0 :         const uint16_t *mapping=getMapping(norm16);
     669           0 :         uint16_t firstUnit=*mapping;
     670           0 :         int32_t mLength=firstUnit&MAPPING_LENGTH_MASK;  // length of normal mapping
     671           0 :         if(firstUnit&MAPPING_HAS_RAW_MAPPING) {
     672             :             // Read the raw mapping from before the firstUnit and before the optional ccc/lccc word.
     673             :             // Bit 7=MAPPING_HAS_CCC_LCCC_WORD
     674           0 :             const uint16_t *rawMapping=mapping-((firstUnit>>7)&1)-1;
     675           0 :             uint16_t rm0=*rawMapping;
     676           0 :             if(rm0<=MAPPING_LENGTH_MASK) {
     677           0 :                 length=rm0;
     678           0 :                 return (const UChar *)rawMapping-rm0;
     679             :             } else {
     680             :                 // Copy the normal mapping and replace its first two code units with rm0.
     681           0 :                 buffer[0]=(UChar)rm0;
     682           0 :                 u_memcpy(buffer+1, (const UChar *)mapping+1+2, mLength-2);
     683           0 :                 length=mLength-1;
     684           0 :                 return buffer;
     685             :             }
     686             :         } else {
     687           0 :             length=mLength;
     688           0 :             return (const UChar *)mapping+1;
     689             :         }
     690             :     }
     691             : }
     692             : 
     693           0 : void Normalizer2Impl::decomposeAndAppend(const UChar *src, const UChar *limit,
     694             :                                          UBool doDecompose,
     695             :                                          UnicodeString &safeMiddle,
     696             :                                          ReorderingBuffer &buffer,
     697             :                                          UErrorCode &errorCode) const {
     698           0 :     buffer.copyReorderableSuffixTo(safeMiddle);
     699           0 :     if(doDecompose) {
     700           0 :         decompose(src, limit, &buffer, errorCode);
     701           0 :         return;
     702             :     }
     703             :     // Just merge the strings at the boundary.
     704           0 :     ForwardUTrie2StringIterator iter(normTrie, src, limit);
     705             :     uint8_t firstCC, prevCC, cc;
     706           0 :     firstCC=prevCC=cc=getCC(iter.next16());
     707           0 :     while(cc!=0) {
     708           0 :         prevCC=cc;
     709           0 :         cc=getCC(iter.next16());
     710             :     };
     711           0 :     if(limit==NULL) {  // appendZeroCC() needs limit!=NULL
     712           0 :         limit=u_strchr(iter.codePointStart, 0);
     713             :     }
     714             : 
     715           0 :     if (buffer.append(src, (int32_t)(iter.codePointStart-src), firstCC, prevCC, errorCode)) {
     716           0 :         buffer.appendZeroCC(iter.codePointStart, limit, errorCode);
     717             :     }
     718             : }
     719             : 
     720             : // Note: hasDecompBoundary() could be implemented as aliases to
     721             : // hasFCDBoundaryBefore() and hasFCDBoundaryAfter()
     722             : // at the cost of building the FCD trie for a decomposition normalizer.
     723           0 : UBool Normalizer2Impl::hasDecompBoundary(UChar32 c, UBool before) const {
     724             :     for(;;) {
     725           0 :         if(c<minDecompNoCP) {
     726           0 :             return TRUE;
     727             :         }
     728           0 :         uint16_t norm16=getNorm16(c);
     729           0 :         if(isHangul(norm16) || isDecompYesAndZeroCC(norm16)) {
     730           0 :             return TRUE;
     731           0 :         } else if(norm16>MIN_NORMAL_MAYBE_YES) {
     732           0 :             return FALSE;  // ccc!=0
     733           0 :         } else if(isDecompNoAlgorithmic(norm16)) {
     734           0 :             c=mapAlgorithmic(c, norm16);
     735             :         } else {
     736             :             // c decomposes, get everything from the variable-length extra data
     737           0 :             const uint16_t *mapping=getMapping(norm16);
     738           0 :             uint16_t firstUnit=*mapping;
     739           0 :             if((firstUnit&MAPPING_LENGTH_MASK)==0) {
     740           0 :                 return FALSE;
     741             :             }
     742           0 :             if(!before) {
     743             :                 // decomp after-boundary: same as hasFCDBoundaryAfter(),
     744             :                 // fcd16<=1 || trailCC==0
     745           0 :                 if(firstUnit>0x1ff) {
     746           0 :                     return FALSE;  // trailCC>1
     747             :                 }
     748           0 :                 if(firstUnit<=0xff) {
     749           0 :                     return TRUE;  // trailCC==0
     750             :                 }
     751             :                 // if(trailCC==1) test leadCC==0, same as checking for before-boundary
     752             :             }
     753             :             // TRUE if leadCC==0 (hasFCDBoundaryBefore())
     754           0 :             return (firstUnit&MAPPING_HAS_CCC_LCCC_WORD)==0 || (*(mapping-1)&0xff00)==0;
     755             :         }
     756           0 :     }
     757             : }
     758             : 
     759             : /*
     760             :  * Finds the recomposition result for
     761             :  * a forward-combining "lead" character,
     762             :  * specified with a pointer to its compositions list,
     763             :  * and a backward-combining "trail" character.
     764             :  *
     765             :  * If the lead and trail characters combine, then this function returns
     766             :  * the following "compositeAndFwd" value:
     767             :  * Bits 21..1  composite character
     768             :  * Bit      0  set if the composite is a forward-combining starter
     769             :  * otherwise it returns -1.
     770             :  *
     771             :  * The compositions list has (trail, compositeAndFwd) pair entries,
     772             :  * encoded as either pairs or triples of 16-bit units.
     773             :  * The last entry has the high bit of its first unit set.
     774             :  *
     775             :  * The list is sorted by ascending trail characters (there are no duplicates).
     776             :  * A linear search is used.
     777             :  *
     778             :  * See normalizer2impl.h for a more detailed description
     779             :  * of the compositions list format.
     780             :  */
     781           0 : int32_t Normalizer2Impl::combine(const uint16_t *list, UChar32 trail) {
     782             :     uint16_t key1, firstUnit;
     783           0 :     if(trail<COMP_1_TRAIL_LIMIT) {
     784             :         // trail character is 0..33FF
     785             :         // result entry may have 2 or 3 units
     786           0 :         key1=(uint16_t)(trail<<1);
     787           0 :         while(key1>(firstUnit=*list)) {
     788           0 :             list+=2+(firstUnit&COMP_1_TRIPLE);
     789             :         }
     790           0 :         if(key1==(firstUnit&COMP_1_TRAIL_MASK)) {
     791           0 :             if(firstUnit&COMP_1_TRIPLE) {
     792           0 :                 return ((int32_t)list[1]<<16)|list[2];
     793             :             } else {
     794           0 :                 return list[1];
     795             :             }
     796             :         }
     797             :     } else {
     798             :         // trail character is 3400..10FFFF
     799             :         // result entry has 3 units
     800           0 :         key1=(uint16_t)(COMP_1_TRAIL_LIMIT+
     801           0 :                         (((trail>>COMP_1_TRAIL_SHIFT))&
     802             :                           ~COMP_1_TRIPLE));
     803           0 :         uint16_t key2=(uint16_t)(trail<<COMP_2_TRAIL_SHIFT);
     804             :         uint16_t secondUnit;
     805             :         for(;;) {
     806           0 :             if(key1>(firstUnit=*list)) {
     807           0 :                 list+=2+(firstUnit&COMP_1_TRIPLE);
     808           0 :             } else if(key1==(firstUnit&COMP_1_TRAIL_MASK)) {
     809           0 :                 if(key2>(secondUnit=list[1])) {
     810           0 :                     if(firstUnit&COMP_1_LAST_TUPLE) {
     811           0 :                         break;
     812             :                     } else {
     813           0 :                         list+=3;
     814             :                     }
     815           0 :                 } else if(key2==(secondUnit&COMP_2_TRAIL_MASK)) {
     816           0 :                     return ((int32_t)(secondUnit&~COMP_2_TRAIL_MASK)<<16)|list[2];
     817             :                 } else {
     818           0 :                     break;
     819             :                 }
     820             :             } else {
     821           0 :                 break;
     822             :             }
     823             :         }
     824             :     }
     825           0 :     return -1;
     826             : }
     827             : 
     828             : /**
     829             :   * @param list some character's compositions list
     830             :   * @param set recursively receives the composites from these compositions
     831             :   */
     832           0 : void Normalizer2Impl::addComposites(const uint16_t *list, UnicodeSet &set) const {
     833             :     uint16_t firstUnit;
     834             :     int32_t compositeAndFwd;
     835           0 :     do {
     836           0 :         firstUnit=*list;
     837           0 :         if((firstUnit&COMP_1_TRIPLE)==0) {
     838           0 :             compositeAndFwd=list[1];
     839           0 :             list+=2;
     840             :         } else {
     841           0 :             compositeAndFwd=(((int32_t)list[1]&~COMP_2_TRAIL_MASK)<<16)|list[2];
     842           0 :             list+=3;
     843             :         }
     844           0 :         UChar32 composite=compositeAndFwd>>1;
     845           0 :         if((compositeAndFwd&1)!=0) {
     846           0 :             addComposites(getCompositionsListForComposite(getNorm16(composite)), set);
     847             :         }
     848           0 :         set.add(composite);
     849           0 :     } while((firstUnit&COMP_1_LAST_TUPLE)==0);
     850           0 : }
     851             : 
     852             : /*
     853             :  * Recomposes the buffer text starting at recomposeStartIndex
     854             :  * (which is in NFD - decomposed and canonically ordered),
     855             :  * and truncates the buffer contents.
     856             :  *
     857             :  * Note that recomposition never lengthens the text:
     858             :  * Any character consists of either one or two code units;
     859             :  * a composition may contain at most one more code unit than the original starter,
     860             :  * while the combining mark that is removed has at least one code unit.
     861             :  */
     862           0 : void Normalizer2Impl::recompose(ReorderingBuffer &buffer, int32_t recomposeStartIndex,
     863             :                                 UBool onlyContiguous) const {
     864           0 :     UChar *p=buffer.getStart()+recomposeStartIndex;
     865           0 :     UChar *limit=buffer.getLimit();
     866           0 :     if(p==limit) {
     867           0 :         return;
     868             :     }
     869             : 
     870             :     UChar *starter, *pRemove, *q, *r;
     871             :     const uint16_t *compositionsList;
     872             :     UChar32 c, compositeAndFwd;
     873             :     uint16_t norm16;
     874             :     uint8_t cc, prevCC;
     875             :     UBool starterIsSupplementary;
     876             : 
     877             :     // Some of the following variables are not used until we have a forward-combining starter
     878             :     // and are only initialized now to avoid compiler warnings.
     879           0 :     compositionsList=NULL;  // used as indicator for whether we have a forward-combining starter
     880           0 :     starter=NULL;
     881           0 :     starterIsSupplementary=FALSE;
     882           0 :     prevCC=0;
     883             : 
     884             :     for(;;) {
     885           0 :         UTRIE2_U16_NEXT16(normTrie, p, limit, c, norm16);
     886           0 :         cc=getCCFromYesOrMaybe(norm16);
     887           0 :         if( // this character combines backward and
     888           0 :             isMaybe(norm16) &&
     889             :             // we have seen a starter that combines forward and
     890           0 :             compositionsList!=NULL &&
     891             :             // the backward-combining character is not blocked
     892           0 :             (prevCC<cc || prevCC==0)
     893             :         ) {
     894           0 :             if(isJamoVT(norm16)) {
     895             :                 // c is a Jamo V/T, see if we can compose it with the previous character.
     896           0 :                 if(c<Hangul::JAMO_T_BASE) {
     897             :                     // c is a Jamo Vowel, compose with previous Jamo L and following Jamo T.
     898           0 :                     UChar prev=(UChar)(*starter-Hangul::JAMO_L_BASE);
     899           0 :                     if(prev<Hangul::JAMO_L_COUNT) {
     900           0 :                         pRemove=p-1;
     901             :                         UChar syllable=(UChar)
     902           0 :                             (Hangul::HANGUL_BASE+
     903           0 :                              (prev*Hangul::JAMO_V_COUNT+(c-Hangul::JAMO_V_BASE))*
     904           0 :                              Hangul::JAMO_T_COUNT);
     905             :                         UChar t;
     906           0 :                         if(p!=limit && (t=(UChar)(*p-Hangul::JAMO_T_BASE))<Hangul::JAMO_T_COUNT) {
     907           0 :                             ++p;
     908           0 :                             syllable+=t;  // The next character was a Jamo T.
     909             :                         }
     910           0 :                         *starter=syllable;
     911             :                         // remove the Jamo V/T
     912           0 :                         q=pRemove;
     913           0 :                         r=p;
     914           0 :                         while(r<limit) {
     915           0 :                             *q++=*r++;
     916             :                         }
     917           0 :                         limit=q;
     918           0 :                         p=pRemove;
     919             :                     }
     920             :                 }
     921             :                 /*
     922             :                  * No "else" for Jamo T:
     923             :                  * Since the input is in NFD, there are no Hangul LV syllables that
     924             :                  * a Jamo T could combine with.
     925             :                  * All Jamo Ts are combined above when handling Jamo Vs.
     926             :                  */
     927           0 :                 if(p==limit) {
     928           0 :                     break;
     929             :                 }
     930           0 :                 compositionsList=NULL;
     931           0 :                 continue;
     932           0 :             } else if((compositeAndFwd=combine(compositionsList, c))>=0) {
     933             :                 // The starter and the combining mark (c) do combine.
     934           0 :                 UChar32 composite=compositeAndFwd>>1;
     935             : 
     936             :                 // Replace the starter with the composite, remove the combining mark.
     937           0 :                 pRemove=p-U16_LENGTH(c);  // pRemove & p: start & limit of the combining mark
     938           0 :                 if(starterIsSupplementary) {
     939           0 :                     if(U_IS_SUPPLEMENTARY(composite)) {
     940             :                         // both are supplementary
     941           0 :                         starter[0]=U16_LEAD(composite);
     942           0 :                         starter[1]=U16_TRAIL(composite);
     943             :                     } else {
     944           0 :                         *starter=(UChar)composite;
     945             :                         // The composite is shorter than the starter,
     946             :                         // move the intermediate characters forward one.
     947           0 :                         starterIsSupplementary=FALSE;
     948           0 :                         q=starter+1;
     949           0 :                         r=q+1;
     950           0 :                         while(r<pRemove) {
     951           0 :                             *q++=*r++;
     952             :                         }
     953           0 :                         --pRemove;
     954             :                     }
     955           0 :                 } else if(U_IS_SUPPLEMENTARY(composite)) {
     956             :                     // The composite is longer than the starter,
     957             :                     // move the intermediate characters back one.
     958           0 :                     starterIsSupplementary=TRUE;
     959           0 :                     ++starter;  // temporarily increment for the loop boundary
     960           0 :                     q=pRemove;
     961           0 :                     r=++pRemove;
     962           0 :                     while(starter<q) {
     963           0 :                         *--r=*--q;
     964             :                     }
     965           0 :                     *starter=U16_TRAIL(composite);
     966           0 :                     *--starter=U16_LEAD(composite);  // undo the temporary increment
     967             :                 } else {
     968             :                     // both are on the BMP
     969           0 :                     *starter=(UChar)composite;
     970             :                 }
     971             : 
     972             :                 /* remove the combining mark by moving the following text over it */
     973           0 :                 if(pRemove<p) {
     974           0 :                     q=pRemove;
     975           0 :                     r=p;
     976           0 :                     while(r<limit) {
     977           0 :                         *q++=*r++;
     978             :                     }
     979           0 :                     limit=q;
     980           0 :                     p=pRemove;
     981             :                 }
     982             :                 // Keep prevCC because we removed the combining mark.
     983             : 
     984           0 :                 if(p==limit) {
     985           0 :                     break;
     986             :                 }
     987             :                 // Is the composite a starter that combines forward?
     988           0 :                 if(compositeAndFwd&1) {
     989             :                     compositionsList=
     990           0 :                         getCompositionsListForComposite(getNorm16(composite));
     991             :                 } else {
     992           0 :                     compositionsList=NULL;
     993             :                 }
     994             : 
     995             :                 // We combined; continue with looking for compositions.
     996           0 :                 continue;
     997             :             }
     998             :         }
     999             : 
    1000             :         // no combination this time
    1001           0 :         prevCC=cc;
    1002           0 :         if(p==limit) {
    1003           0 :             break;
    1004             :         }
    1005             : 
    1006             :         // If c did not combine, then check if it is a starter.
    1007           0 :         if(cc==0) {
    1008             :             // Found a new starter.
    1009           0 :             if((compositionsList=getCompositionsListForDecompYes(norm16))!=NULL) {
    1010             :                 // It may combine with something, prepare for it.
    1011           0 :                 if(U_IS_BMP(c)) {
    1012           0 :                     starterIsSupplementary=FALSE;
    1013           0 :                     starter=p-1;
    1014             :                 } else {
    1015           0 :                     starterIsSupplementary=TRUE;
    1016           0 :                     starter=p-2;
    1017             :                 }
    1018             :             }
    1019           0 :         } else if(onlyContiguous) {
    1020             :             // FCC: no discontiguous compositions; any intervening character blocks.
    1021           0 :             compositionsList=NULL;
    1022             :         }
    1023           0 :     }
    1024           0 :     buffer.setReorderingLimit(limit);
    1025             : }
    1026             : 
    1027             : UChar32
    1028           0 : Normalizer2Impl::composePair(UChar32 a, UChar32 b) const {
    1029           0 :     uint16_t norm16=getNorm16(a);  // maps an out-of-range 'a' to inert norm16=0
    1030             :     const uint16_t *list;
    1031           0 :     if(isInert(norm16)) {
    1032           0 :         return U_SENTINEL;
    1033           0 :     } else if(norm16<minYesNoMappingsOnly) {
    1034           0 :         if(isJamoL(norm16)) {
    1035           0 :             b-=Hangul::JAMO_V_BASE;
    1036           0 :             if(0<=b && b<Hangul::JAMO_V_COUNT) {
    1037             :                 return
    1038             :                     (Hangul::HANGUL_BASE+
    1039           0 :                      ((a-Hangul::JAMO_L_BASE)*Hangul::JAMO_V_COUNT+b)*
    1040           0 :                      Hangul::JAMO_T_COUNT);
    1041             :             } else {
    1042           0 :                 return U_SENTINEL;
    1043             :             }
    1044           0 :         } else if(isHangul(norm16)) {
    1045           0 :             b-=Hangul::JAMO_T_BASE;
    1046           0 :             if(Hangul::isHangulWithoutJamoT(a) && 0<b && b<Hangul::JAMO_T_COUNT) {  // not b==0!
    1047           0 :                 return a+b;
    1048             :             } else {
    1049           0 :                 return U_SENTINEL;
    1050             :             }
    1051             :         } else {
    1052             :             // 'a' has a compositions list in extraData
    1053           0 :             list=extraData+norm16;
    1054           0 :             if(norm16>minYesNo) {  // composite 'a' has both mapping & compositions list
    1055           0 :                 list+=  // mapping pointer
    1056           0 :                     1+  // +1 to skip the first unit with the mapping lenth
    1057           0 :                     (*list&MAPPING_LENGTH_MASK);  // + mapping length
    1058             :             }
    1059             :         }
    1060           0 :     } else if(norm16<minMaybeYes || MIN_NORMAL_MAYBE_YES<=norm16) {
    1061           0 :         return U_SENTINEL;
    1062             :     } else {
    1063           0 :         list=maybeYesCompositions+norm16-minMaybeYes;
    1064             :     }
    1065           0 :     if(b<0 || 0x10ffff<b) {  // combine(list, b) requires a valid code point b
    1066           0 :         return U_SENTINEL;
    1067             :     }
    1068             : #if U_SIGNED_RIGHT_SHIFT_IS_ARITHMETIC
    1069           0 :     return combine(list, b)>>1;
    1070             : #else
    1071             :     int32_t compositeAndFwd=combine(list, b);
    1072             :     return compositeAndFwd>=0 ? compositeAndFwd>>1 : U_SENTINEL;
    1073             : #endif
    1074             : }
    1075             : 
    1076             : // Very similar to composeQuickCheck(): Make the same changes in both places if relevant.
    1077             : // doCompose: normalize
    1078             : // !doCompose: isNormalized (buffer must be empty and initialized)
    1079             : UBool
    1080           0 : Normalizer2Impl::compose(const UChar *src, const UChar *limit,
    1081             :                          UBool onlyContiguous,
    1082             :                          UBool doCompose,
    1083             :                          ReorderingBuffer &buffer,
    1084             :                          UErrorCode &errorCode) const {
    1085             :     /*
    1086             :      * prevBoundary points to the last character before the current one
    1087             :      * that has a composition boundary before it with ccc==0 and quick check "yes".
    1088             :      * Keeping track of prevBoundary saves us looking for a composition boundary
    1089             :      * when we find a "no" or "maybe".
    1090             :      *
    1091             :      * When we back out from prevSrc back to prevBoundary,
    1092             :      * then we also remove those same characters (which had been simply copied
    1093             :      * or canonically-order-inserted) from the ReorderingBuffer.
    1094             :      * Therefore, at all times, the [prevBoundary..prevSrc[ source units
    1095             :      * must correspond 1:1 to destination units at the end of the destination buffer.
    1096             :      */
    1097           0 :     const UChar *prevBoundary=src;
    1098           0 :     UChar32 minNoMaybeCP=minCompNoMaybeCP;
    1099           0 :     if(limit==NULL) {
    1100           0 :         src=copyLowPrefixFromNulTerminated(src, minNoMaybeCP,
    1101             :                                            doCompose ? &buffer : NULL,
    1102           0 :                                            errorCode);
    1103           0 :         if(U_FAILURE(errorCode)) {
    1104           0 :             return FALSE;
    1105             :         }
    1106           0 :         if(prevBoundary<src) {
    1107             :             // Set prevBoundary to the last character in the prefix.
    1108           0 :             prevBoundary=src-1;
    1109             :         }
    1110           0 :         limit=u_strchr(src, 0);
    1111             :     }
    1112             : 
    1113             :     const UChar *prevSrc;
    1114           0 :     UChar32 c=0;
    1115           0 :     uint16_t norm16=0;
    1116             : 
    1117             :     // only for isNormalized
    1118           0 :     uint8_t prevCC=0;
    1119             : 
    1120             :     for(;;) {
    1121             :         // count code units below the minimum or with irrelevant data for the quick check
    1122           0 :         for(prevSrc=src; src!=limit;) {
    1123           0 :             if( (c=*src)<minNoMaybeCP ||
    1124           0 :                 isCompYesAndZeroCC(norm16=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(normTrie, c))
    1125             :             ) {
    1126           0 :                 ++src;
    1127           0 :             } else if(!U16_IS_SURROGATE(c)) {
    1128           0 :                 break;
    1129             :             } else {
    1130             :                 UChar c2;
    1131           0 :                 if(U16_IS_SURROGATE_LEAD(c)) {
    1132           0 :                     if((src+1)!=limit && U16_IS_TRAIL(c2=src[1])) {
    1133           0 :                         c=U16_GET_SUPPLEMENTARY(c, c2);
    1134             :                     }
    1135             :                 } else /* trail surrogate */ {
    1136           0 :                     if(prevSrc<src && U16_IS_LEAD(c2=*(src-1))) {
    1137           0 :                         --src;
    1138           0 :                         c=U16_GET_SUPPLEMENTARY(c2, c);
    1139             :                     }
    1140             :                 }
    1141           0 :                 if(isCompYesAndZeroCC(norm16=getNorm16(c))) {
    1142           0 :                     src+=U16_LENGTH(c);
    1143             :                 } else {
    1144           0 :                     break;
    1145             :                 }
    1146             :             }
    1147             :         }
    1148             :         // copy these code units all at once
    1149           0 :         if(src!=prevSrc) {
    1150           0 :             if(doCompose) {
    1151           0 :                 if(!buffer.appendZeroCC(prevSrc, src, errorCode)) {
    1152           0 :                     break;
    1153             :                 }
    1154             :             } else {
    1155           0 :                 prevCC=0;
    1156             :             }
    1157           0 :             if(src==limit) {
    1158           0 :                 break;
    1159             :             }
    1160             :             // Set prevBoundary to the last character in the quick check loop.
    1161           0 :             prevBoundary=src-1;
    1162           0 :             if( U16_IS_TRAIL(*prevBoundary) && prevSrc<prevBoundary &&
    1163           0 :                 U16_IS_LEAD(*(prevBoundary-1))
    1164             :             ) {
    1165           0 :                 --prevBoundary;
    1166             :             }
    1167             :             // The start of the current character (c).
    1168           0 :             prevSrc=src;
    1169           0 :         } else if(src==limit) {
    1170           0 :             break;
    1171             :         }
    1172             : 
    1173           0 :         src+=U16_LENGTH(c);
    1174             :         /*
    1175             :          * isCompYesAndZeroCC(norm16) is false, that is, norm16>=minNoNo.
    1176             :          * c is either a "noNo" (has a mapping) or a "maybeYes" (combines backward)
    1177             :          * or has ccc!=0.
    1178             :          * Check for Jamo V/T, then for regular characters.
    1179             :          * c is not a Hangul syllable or Jamo L because those have "yes" properties.
    1180             :          */
    1181           0 :         if(isJamoVT(norm16) && prevBoundary!=prevSrc) {
    1182           0 :             UChar prev=*(prevSrc-1);
    1183           0 :             UBool needToDecompose=FALSE;
    1184           0 :             if(c<Hangul::JAMO_T_BASE) {
    1185             :                 // c is a Jamo Vowel, compose with previous Jamo L and following Jamo T.
    1186           0 :                 prev=(UChar)(prev-Hangul::JAMO_L_BASE);
    1187           0 :                 if(prev<Hangul::JAMO_L_COUNT) {
    1188           0 :                     if(!doCompose) {
    1189           0 :                         return FALSE;
    1190             :                     }
    1191             :                     UChar syllable=(UChar)
    1192           0 :                         (Hangul::HANGUL_BASE+
    1193           0 :                          (prev*Hangul::JAMO_V_COUNT+(c-Hangul::JAMO_V_BASE))*
    1194           0 :                          Hangul::JAMO_T_COUNT);
    1195             :                     UChar t;
    1196           0 :                     if(src!=limit && (t=(UChar)(*src-Hangul::JAMO_T_BASE))<Hangul::JAMO_T_COUNT) {
    1197           0 :                         ++src;
    1198           0 :                         syllable+=t;  // The next character was a Jamo T.
    1199           0 :                         prevBoundary=src;
    1200           0 :                         buffer.setLastChar(syllable);
    1201           0 :                         continue;
    1202             :                     }
    1203             :                     // If we see L+V+x where x!=T then we drop to the slow path,
    1204             :                     // decompose and recompose.
    1205             :                     // This is to deal with NFKC finding normal L and V but a
    1206             :                     // compatibility variant of a T. We need to either fully compose that
    1207             :                     // combination here (which would complicate the code and may not work
    1208             :                     // with strange custom data) or use the slow path -- or else our replacing
    1209             :                     // two input characters (L+V) with one output character (LV syllable)
    1210             :                     // would violate the invariant that [prevBoundary..prevSrc[ has the same
    1211             :                     // length as what we appended to the buffer since prevBoundary.
    1212           0 :                     needToDecompose=TRUE;
    1213             :                 }
    1214           0 :             } else if(Hangul::isHangulWithoutJamoT(prev)) {
    1215             :                 // c is a Jamo Trailing consonant,
    1216             :                 // compose with previous Hangul LV that does not contain a Jamo T.
    1217           0 :                 if(!doCompose) {
    1218           0 :                     return FALSE;
    1219             :                 }
    1220           0 :                 buffer.setLastChar((UChar)(prev+c-Hangul::JAMO_T_BASE));
    1221           0 :                 prevBoundary=src;
    1222           0 :                 continue;
    1223             :             }
    1224           0 :             if(!needToDecompose) {
    1225             :                 // The Jamo V/T did not compose into a Hangul syllable.
    1226           0 :                 if(doCompose) {
    1227           0 :                     if(!buffer.appendBMP((UChar)c, 0, errorCode)) {
    1228           0 :                         break;
    1229             :                     }
    1230             :                 } else {
    1231           0 :                     prevCC=0;
    1232             :                 }
    1233           0 :                 continue;
    1234             :             }
    1235             :         }
    1236             :         /*
    1237             :          * Source buffer pointers:
    1238             :          *
    1239             :          *  all done      quick check   current char  not yet
    1240             :          *                "yes" but     (c)           processed
    1241             :          *                may combine
    1242             :          *                forward
    1243             :          * [-------------[-------------[-------------[-------------[
    1244             :          * |             |             |             |             |
    1245             :          * orig. src     prevBoundary  prevSrc       src           limit
    1246             :          *
    1247             :          *
    1248             :          * Destination buffer pointers inside the ReorderingBuffer:
    1249             :          *
    1250             :          *  all done      might take    not filled yet
    1251             :          *                characters for
    1252             :          *                reordering
    1253             :          * [-------------[-------------[-------------[
    1254             :          * |             |             |             |
    1255             :          * start         reorderStart  limit         |
    1256             :          *                             +remainingCap.+
    1257             :          */
    1258           0 :         if(norm16>=MIN_YES_YES_WITH_CC) {
    1259           0 :             uint8_t cc=(uint8_t)norm16;  // cc!=0
    1260           0 :             if( onlyContiguous &&  // FCC
    1261           0 :                 (doCompose ? buffer.getLastCC() : prevCC)==0 &&
    1262           0 :                 prevBoundary<prevSrc &&
    1263             :                 // buffer.getLastCC()==0 && prevBoundary<prevSrc tell us that
    1264             :                 // [prevBoundary..prevSrc[ (which is exactly one character under these conditions)
    1265             :                 // passed the quick check "yes && ccc==0" test.
    1266             :                 // Check whether the last character was a "yesYes" or a "yesNo".
    1267             :                 // If a "yesNo", then we get its trailing ccc from its
    1268             :                 // mapping and check for canonical order.
    1269             :                 // All other cases are ok.
    1270           0 :                 getTrailCCFromCompYesAndZeroCC(prevBoundary, prevSrc)>cc
    1271             :             ) {
    1272             :                 // Fails FCD test, need to decompose and contiguously recompose.
    1273           0 :                 if(!doCompose) {
    1274           0 :                     return FALSE;
    1275             :                 }
    1276           0 :             } else if(doCompose) {
    1277           0 :                 if(!buffer.append(c, cc, errorCode)) {
    1278           0 :                     break;
    1279             :                 }
    1280           0 :                 continue;
    1281           0 :             } else if(prevCC<=cc) {
    1282           0 :                 prevCC=cc;
    1283           0 :                 continue;
    1284             :             } else {
    1285           0 :                 return FALSE;
    1286             :             }
    1287           0 :         } else if(!doCompose && !isMaybeOrNonZeroCC(norm16)) {
    1288           0 :             return FALSE;
    1289             :         }
    1290             : 
    1291             :         /*
    1292             :          * Find appropriate boundaries around this character,
    1293             :          * decompose the source text from between the boundaries,
    1294             :          * and recompose it.
    1295             :          *
    1296             :          * We may need to remove the last few characters from the ReorderingBuffer
    1297             :          * to account for source text that was copied or appended
    1298             :          * but needs to take part in the recomposition.
    1299             :          */
    1300             : 
    1301             :         /*
    1302             :          * Find the last composition boundary in [prevBoundary..src[.
    1303             :          * It is either the decomposition of the current character (at prevSrc),
    1304             :          * or prevBoundary.
    1305             :          */
    1306           0 :         if(hasCompBoundaryBefore(c, norm16)) {
    1307           0 :             prevBoundary=prevSrc;
    1308           0 :         } else if(doCompose) {
    1309           0 :             buffer.removeSuffix((int32_t)(prevSrc-prevBoundary));
    1310             :         }
    1311             : 
    1312             :         // Find the next composition boundary in [src..limit[ -
    1313             :         // modifies src to point to the next starter.
    1314           0 :         src=(UChar *)findNextCompBoundary(src, limit);
    1315             : 
    1316             :         // Decompose [prevBoundary..src[ into the buffer and then recompose that part of it.
    1317           0 :         int32_t recomposeStartIndex=buffer.length();
    1318           0 :         if(!decomposeShort(prevBoundary, src, buffer, errorCode)) {
    1319           0 :             break;
    1320             :         }
    1321           0 :         recompose(buffer, recomposeStartIndex, onlyContiguous);
    1322           0 :         if(!doCompose) {
    1323           0 :             if(!buffer.equals(prevBoundary, src)) {
    1324           0 :                 return FALSE;
    1325             :             }
    1326           0 :             buffer.remove();
    1327           0 :             prevCC=0;
    1328             :         }
    1329             : 
    1330             :         // Move to the next starter. We never need to look back before this point again.
    1331           0 :         prevBoundary=src;
    1332           0 :     }
    1333           0 :     return TRUE;
    1334             : }
    1335             : 
    1336             : // Very similar to compose(): Make the same changes in both places if relevant.
    1337             : // pQCResult==NULL: spanQuickCheckYes
    1338             : // pQCResult!=NULL: quickCheck (*pQCResult must be UNORM_YES)
    1339             : const UChar *
    1340           0 : Normalizer2Impl::composeQuickCheck(const UChar *src, const UChar *limit,
    1341             :                                    UBool onlyContiguous,
    1342             :                                    UNormalizationCheckResult *pQCResult) const {
    1343             :     /*
    1344             :      * prevBoundary points to the last character before the current one
    1345             :      * that has a composition boundary before it with ccc==0 and quick check "yes".
    1346             :      */
    1347           0 :     const UChar *prevBoundary=src;
    1348           0 :     UChar32 minNoMaybeCP=minCompNoMaybeCP;
    1349           0 :     if(limit==NULL) {
    1350           0 :         UErrorCode errorCode=U_ZERO_ERROR;
    1351           0 :         src=copyLowPrefixFromNulTerminated(src, minNoMaybeCP, NULL, errorCode);
    1352           0 :         if(prevBoundary<src) {
    1353             :             // Set prevBoundary to the last character in the prefix.
    1354           0 :             prevBoundary=src-1;
    1355             :         }
    1356           0 :         limit=u_strchr(src, 0);
    1357             :     }
    1358             : 
    1359             :     const UChar *prevSrc;
    1360           0 :     UChar32 c=0;
    1361           0 :     uint16_t norm16=0;
    1362           0 :     uint8_t prevCC=0;
    1363             : 
    1364             :     for(;;) {
    1365             :         // count code units below the minimum or with irrelevant data for the quick check
    1366           0 :         for(prevSrc=src;;) {
    1367           0 :             if(src==limit) {
    1368           0 :                 return src;
    1369             :             }
    1370           0 :             if( (c=*src)<minNoMaybeCP ||
    1371           0 :                 isCompYesAndZeroCC(norm16=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(normTrie, c))
    1372             :             ) {
    1373           0 :                 ++src;
    1374           0 :             } else if(!U16_IS_SURROGATE(c)) {
    1375           0 :                 break;
    1376             :             } else {
    1377             :                 UChar c2;
    1378           0 :                 if(U16_IS_SURROGATE_LEAD(c)) {
    1379           0 :                     if((src+1)!=limit && U16_IS_TRAIL(c2=src[1])) {
    1380           0 :                         c=U16_GET_SUPPLEMENTARY(c, c2);
    1381             :                     }
    1382             :                 } else /* trail surrogate */ {
    1383           0 :                     if(prevSrc<src && U16_IS_LEAD(c2=*(src-1))) {
    1384           0 :                         --src;
    1385           0 :                         c=U16_GET_SUPPLEMENTARY(c2, c);
    1386             :                     }
    1387             :                 }
    1388           0 :                 if(isCompYesAndZeroCC(norm16=getNorm16(c))) {
    1389           0 :                     src+=U16_LENGTH(c);
    1390             :                 } else {
    1391           0 :                     break;
    1392             :                 }
    1393             :             }
    1394           0 :         }
    1395           0 :         if(src!=prevSrc) {
    1396             :             // Set prevBoundary to the last character in the quick check loop.
    1397           0 :             prevBoundary=src-1;
    1398           0 :             if( U16_IS_TRAIL(*prevBoundary) && prevSrc<prevBoundary &&
    1399           0 :                 U16_IS_LEAD(*(prevBoundary-1))
    1400             :             ) {
    1401           0 :                 --prevBoundary;
    1402             :             }
    1403           0 :             prevCC=0;
    1404             :             // The start of the current character (c).
    1405           0 :             prevSrc=src;
    1406             :         }
    1407             : 
    1408           0 :         src+=U16_LENGTH(c);
    1409             :         /*
    1410             :          * isCompYesAndZeroCC(norm16) is false, that is, norm16>=minNoNo.
    1411             :          * c is either a "noNo" (has a mapping) or a "maybeYes" (combines backward)
    1412             :          * or has ccc!=0.
    1413             :          */
    1414           0 :         if(isMaybeOrNonZeroCC(norm16)) {
    1415           0 :             uint8_t cc=getCCFromYesOrMaybe(norm16);
    1416           0 :             if( onlyContiguous &&  // FCC
    1417           0 :                 cc!=0 &&
    1418           0 :                 prevCC==0 &&
    1419           0 :                 prevBoundary<prevSrc &&
    1420             :                 // prevCC==0 && prevBoundary<prevSrc tell us that
    1421             :                 // [prevBoundary..prevSrc[ (which is exactly one character under these conditions)
    1422             :                 // passed the quick check "yes && ccc==0" test.
    1423             :                 // Check whether the last character was a "yesYes" or a "yesNo".
    1424             :                 // If a "yesNo", then we get its trailing ccc from its
    1425             :                 // mapping and check for canonical order.
    1426             :                 // All other cases are ok.
    1427           0 :                 getTrailCCFromCompYesAndZeroCC(prevBoundary, prevSrc)>cc
    1428             :             ) {
    1429             :                 // Fails FCD test.
    1430           0 :             } else if(prevCC<=cc || cc==0) {
    1431           0 :                 prevCC=cc;
    1432           0 :                 if(norm16<MIN_YES_YES_WITH_CC) {
    1433           0 :                     if(pQCResult!=NULL) {
    1434           0 :                         *pQCResult=UNORM_MAYBE;
    1435             :                     } else {
    1436           0 :                         return prevBoundary;
    1437             :                     }
    1438             :                 }
    1439           0 :                 continue;
    1440             :             }
    1441             :         }
    1442           0 :         if(pQCResult!=NULL) {
    1443           0 :             *pQCResult=UNORM_NO;
    1444             :         }
    1445           0 :         return prevBoundary;
    1446           0 :     }
    1447             : }
    1448             : 
    1449           0 : void Normalizer2Impl::composeAndAppend(const UChar *src, const UChar *limit,
    1450             :                                        UBool doCompose,
    1451             :                                        UBool onlyContiguous,
    1452             :                                        UnicodeString &safeMiddle,
    1453             :                                        ReorderingBuffer &buffer,
    1454             :                                        UErrorCode &errorCode) const {
    1455           0 :     if(!buffer.isEmpty()) {
    1456           0 :         const UChar *firstStarterInSrc=findNextCompBoundary(src, limit);
    1457           0 :         if(src!=firstStarterInSrc) {
    1458           0 :             const UChar *lastStarterInDest=findPreviousCompBoundary(buffer.getStart(),
    1459           0 :                                                                     buffer.getLimit());
    1460           0 :             int32_t destSuffixLength=(int32_t)(buffer.getLimit()-lastStarterInDest);
    1461           0 :             UnicodeString middle(lastStarterInDest, destSuffixLength);
    1462           0 :             buffer.removeSuffix(destSuffixLength);
    1463           0 :             safeMiddle=middle;
    1464           0 :             middle.append(src, (int32_t)(firstStarterInSrc-src));
    1465           0 :             const UChar *middleStart=middle.getBuffer();
    1466           0 :             compose(middleStart, middleStart+middle.length(), onlyContiguous,
    1467           0 :                     TRUE, buffer, errorCode);
    1468           0 :             if(U_FAILURE(errorCode)) {
    1469           0 :                 return;
    1470             :             }
    1471           0 :             src=firstStarterInSrc;
    1472             :         }
    1473             :     }
    1474           0 :     if(doCompose) {
    1475           0 :         compose(src, limit, onlyContiguous, TRUE, buffer, errorCode);
    1476             :     } else {
    1477           0 :         if(limit==NULL) {  // appendZeroCC() needs limit!=NULL
    1478           0 :             limit=u_strchr(src, 0);
    1479             :         }
    1480           0 :         buffer.appendZeroCC(src, limit, errorCode);
    1481             :     }
    1482             : }
    1483             : 
    1484             : /**
    1485             :  * Does c have a composition boundary before it?
    1486             :  * True if its decomposition begins with a character that has
    1487             :  * ccc=0 && NFC_QC=Yes (isCompYesAndZeroCC()).
    1488             :  * As a shortcut, this is true if c itself has ccc=0 && NFC_QC=Yes
    1489             :  * (isCompYesAndZeroCC()) so we need not decompose.
    1490             :  */
    1491           0 : UBool Normalizer2Impl::hasCompBoundaryBefore(UChar32 c, uint16_t norm16) const {
    1492             :     for(;;) {
    1493           0 :         if(isCompYesAndZeroCC(norm16)) {
    1494           0 :             return TRUE;
    1495           0 :         } else if(isMaybeOrNonZeroCC(norm16)) {
    1496           0 :             return FALSE;
    1497           0 :         } else if(isDecompNoAlgorithmic(norm16)) {
    1498           0 :             c=mapAlgorithmic(c, norm16);
    1499           0 :             norm16=getNorm16(c);
    1500             :         } else {
    1501             :             // c decomposes, get everything from the variable-length extra data
    1502           0 :             const uint16_t *mapping=getMapping(norm16);
    1503           0 :             uint16_t firstUnit=*mapping;
    1504           0 :             if((firstUnit&MAPPING_LENGTH_MASK)==0) {
    1505           0 :                 return FALSE;
    1506             :             }
    1507           0 :             if((firstUnit&MAPPING_HAS_CCC_LCCC_WORD) && (*(mapping-1)&0xff00)) {
    1508           0 :                 return FALSE;  // non-zero leadCC
    1509             :             }
    1510           0 :             int32_t i=1;  // skip over the firstUnit
    1511             :             UChar32 c;
    1512           0 :             U16_NEXT_UNSAFE(mapping, i, c);
    1513           0 :             return isCompYesAndZeroCC(getNorm16(c));
    1514             :         }
    1515           0 :     }
    1516             : }
    1517             : 
    1518           0 : UBool Normalizer2Impl::hasCompBoundaryAfter(UChar32 c, UBool onlyContiguous, UBool testInert) const {
    1519             :     for(;;) {
    1520           0 :         uint16_t norm16=getNorm16(c);
    1521           0 :         if(isInert(norm16)) {
    1522           0 :             return TRUE;
    1523           0 :         } else if(norm16<=minYesNo) {
    1524             :             // Hangul: norm16==minYesNo
    1525             :             // Hangul LVT has a boundary after it.
    1526             :             // Hangul LV and non-inert yesYes characters combine forward.
    1527           0 :             return isHangul(norm16) && !Hangul::isHangulWithoutJamoT((UChar)c);
    1528           0 :         } else if(norm16>= (testInert ? minNoNo : minMaybeYes)) {
    1529           0 :             return FALSE;
    1530           0 :         } else if(isDecompNoAlgorithmic(norm16)) {
    1531           0 :             c=mapAlgorithmic(c, norm16);
    1532             :         } else {
    1533             :             // c decomposes, get everything from the variable-length extra data.
    1534             :             // If testInert, then c must be a yesNo character which has lccc=0,
    1535             :             // otherwise it could be a noNo.
    1536           0 :             const uint16_t *mapping=getMapping(norm16);
    1537           0 :             uint16_t firstUnit=*mapping;
    1538             :             // TRUE if
    1539             :             //   not MAPPING_NO_COMP_BOUNDARY_AFTER
    1540             :             //     (which is set if
    1541             :             //       c is not deleted, and
    1542             :             //       it and its decomposition do not combine forward, and it has a starter)
    1543             :             //   and if FCC then trailCC<=1
    1544             :             return
    1545           0 :                 (firstUnit&MAPPING_NO_COMP_BOUNDARY_AFTER)==0 &&
    1546           0 :                 (!onlyContiguous || firstUnit<=0x1ff);
    1547             :         }
    1548           0 :     }
    1549             : }
    1550             : 
    1551           0 : const UChar *Normalizer2Impl::findPreviousCompBoundary(const UChar *start, const UChar *p) const {
    1552           0 :     BackwardUTrie2StringIterator iter(normTrie, start, p);
    1553             :     uint16_t norm16;
    1554           0 :     do {
    1555           0 :         norm16=iter.previous16();
    1556           0 :     } while(!hasCompBoundaryBefore(iter.codePoint, norm16));
    1557             :     // We could also test hasCompBoundaryAfter() and return iter.codePointLimit,
    1558             :     // but that's probably not worth the extra cost.
    1559           0 :     return iter.codePointStart;
    1560             : }
    1561             : 
    1562           0 : const UChar *Normalizer2Impl::findNextCompBoundary(const UChar *p, const UChar *limit) const {
    1563           0 :     ForwardUTrie2StringIterator iter(normTrie, p, limit);
    1564             :     uint16_t norm16;
    1565           0 :     do {
    1566           0 :         norm16=iter.next16();
    1567           0 :     } while(!hasCompBoundaryBefore(iter.codePoint, norm16));
    1568           0 :     return iter.codePointStart;
    1569             : }
    1570             : 
    1571             : // Note: normalizer2impl.cpp r30982 (2011-nov-27)
    1572             : // still had getFCDTrie() which built and cached an FCD trie.
    1573             : // That provided faster access to FCD data than getFCD16FromNormData()
    1574             : // but required synchronization and consumed some 10kB of heap memory
    1575             : // in any process that uses FCD (e.g., via collation).
    1576             : // tccc180[] and smallFCD[] are intended to help with any loss of performance,
    1577             : // at least for Latin & CJK.
    1578             : 
    1579             : // Gets the FCD value from the regular normalization data.
    1580        1137 : uint16_t Normalizer2Impl::getFCD16FromNormData(UChar32 c) const {
    1581             :     // Only loops for 1:1 algorithmic mappings.
    1582             :     for(;;) {
    1583        1137 :         uint16_t norm16=getNorm16(c);
    1584        1137 :         if(norm16<=minYesNo) {
    1585             :             // no decomposition or Hangul syllable, all zeros
    1586         170 :             return 0;
    1587         967 :         } else if(norm16>=MIN_NORMAL_MAYBE_YES) {
    1588             :             // combining mark
    1589           0 :             norm16&=0xff;
    1590           0 :             return norm16|(norm16<<8);
    1591         967 :         } else if(norm16>=minMaybeYes) {
    1592           0 :             return 0;
    1593         967 :         } else if(isDecompNoAlgorithmic(norm16)) {
    1594         177 :             c=mapAlgorithmic(c, norm16);
    1595             :         } else {
    1596             :             // c decomposes, get everything from the variable-length extra data
    1597         790 :             const uint16_t *mapping=getMapping(norm16);
    1598         790 :             uint16_t firstUnit=*mapping;
    1599         790 :             if((firstUnit&MAPPING_LENGTH_MASK)==0) {
    1600             :                 // A character that is deleted (maps to an empty string) must
    1601             :                 // get the worst-case lccc and tccc values because arbitrary
    1602             :                 // characters on both sides will become adjacent.
    1603           3 :                 return 0x1ff;
    1604             :             } else {
    1605         787 :                 norm16=firstUnit>>8;  // tccc
    1606         787 :                 if(firstUnit&MAPPING_HAS_CCC_LCCC_WORD) {
    1607           0 :                     norm16|=*(mapping-1)&0xff00;  // lccc
    1608             :                 }
    1609         787 :                 return norm16;
    1610             :             }
    1611             :         }
    1612         177 :     }
    1613             : }
    1614             : 
    1615             : // Dual functionality:
    1616             : // buffer!=NULL: normalize
    1617             : // buffer==NULL: isNormalized/quickCheck/spanQuickCheckYes
    1618             : const UChar *
    1619           0 : Normalizer2Impl::makeFCD(const UChar *src, const UChar *limit,
    1620             :                          ReorderingBuffer *buffer,
    1621             :                          UErrorCode &errorCode) const {
    1622             :     // Tracks the last FCD-safe boundary, before lccc=0 or after properly-ordered tccc<=1.
    1623             :     // Similar to the prevBoundary in the compose() implementation.
    1624           0 :     const UChar *prevBoundary=src;
    1625           0 :     int32_t prevFCD16=0;
    1626           0 :     if(limit==NULL) {
    1627           0 :         src=copyLowPrefixFromNulTerminated(src, MIN_CCC_LCCC_CP, buffer, errorCode);
    1628           0 :         if(U_FAILURE(errorCode)) {
    1629           0 :             return src;
    1630             :         }
    1631           0 :         if(prevBoundary<src) {
    1632           0 :             prevBoundary=src;
    1633             :             // We know that the previous character's lccc==0.
    1634             :             // Fetching the fcd16 value was deferred for this below-U+0300 code point.
    1635           0 :             prevFCD16=getFCD16(*(src-1));
    1636           0 :             if(prevFCD16>1) {
    1637           0 :                 --prevBoundary;
    1638             :             }
    1639             :         }
    1640           0 :         limit=u_strchr(src, 0);
    1641             :     }
    1642             : 
    1643             :     // Note: In this function we use buffer->appendZeroCC() because we track
    1644             :     // the lead and trail combining classes here, rather than leaving it to
    1645             :     // the ReorderingBuffer.
    1646             :     // The exception is the call to decomposeShort() which uses the buffer
    1647             :     // in the normal way.
    1648             : 
    1649             :     const UChar *prevSrc;
    1650           0 :     UChar32 c=0;
    1651           0 :     uint16_t fcd16=0;
    1652             : 
    1653             :     for(;;) {
    1654             :         // count code units with lccc==0
    1655           0 :         for(prevSrc=src; src!=limit;) {
    1656           0 :             if((c=*src)<MIN_CCC_LCCC_CP) {
    1657           0 :                 prevFCD16=~c;
    1658           0 :                 ++src;
    1659           0 :             } else if(!singleLeadMightHaveNonZeroFCD16(c)) {
    1660           0 :                 prevFCD16=0;
    1661           0 :                 ++src;
    1662             :             } else {
    1663           0 :                 if(U16_IS_SURROGATE(c)) {
    1664             :                     UChar c2;
    1665           0 :                     if(U16_IS_SURROGATE_LEAD(c)) {
    1666           0 :                         if((src+1)!=limit && U16_IS_TRAIL(c2=src[1])) {
    1667           0 :                             c=U16_GET_SUPPLEMENTARY(c, c2);
    1668             :                         }
    1669             :                     } else /* trail surrogate */ {
    1670           0 :                         if(prevSrc<src && U16_IS_LEAD(c2=*(src-1))) {
    1671           0 :                             --src;
    1672           0 :                             c=U16_GET_SUPPLEMENTARY(c2, c);
    1673             :                         }
    1674             :                     }
    1675             :                 }
    1676           0 :                 if((fcd16=getFCD16FromNormData(c))<=0xff) {
    1677           0 :                     prevFCD16=fcd16;
    1678           0 :                     src+=U16_LENGTH(c);
    1679             :                 } else {
    1680           0 :                     break;
    1681             :                 }
    1682             :             }
    1683             :         }
    1684             :         // copy these code units all at once
    1685           0 :         if(src!=prevSrc) {
    1686           0 :             if(buffer!=NULL && !buffer->appendZeroCC(prevSrc, src, errorCode)) {
    1687           0 :                 break;
    1688             :             }
    1689           0 :             if(src==limit) {
    1690           0 :                 break;
    1691             :             }
    1692           0 :             prevBoundary=src;
    1693             :             // We know that the previous character's lccc==0.
    1694           0 :             if(prevFCD16<0) {
    1695             :                 // Fetching the fcd16 value was deferred for this below-U+0300 code point.
    1696           0 :                 UChar32 prev=~prevFCD16;
    1697           0 :                 prevFCD16= prev<0x180 ? tccc180[prev] : getFCD16FromNormData(prev);
    1698           0 :                 if(prevFCD16>1) {
    1699           0 :                     --prevBoundary;
    1700             :                 }
    1701             :             } else {
    1702           0 :                 const UChar *p=src-1;
    1703           0 :                 if(U16_IS_TRAIL(*p) && prevSrc<p && U16_IS_LEAD(*(p-1))) {
    1704           0 :                     --p;
    1705             :                     // Need to fetch the previous character's FCD value because
    1706             :                     // prevFCD16 was just for the trail surrogate code point.
    1707           0 :                     prevFCD16=getFCD16FromNormData(U16_GET_SUPPLEMENTARY(p[0], p[1]));
    1708             :                     // Still known to have lccc==0 because its lead surrogate unit had lccc==0.
    1709             :                 }
    1710           0 :                 if(prevFCD16>1) {
    1711           0 :                     prevBoundary=p;
    1712             :                 }
    1713             :             }
    1714             :             // The start of the current character (c).
    1715           0 :             prevSrc=src;
    1716           0 :         } else if(src==limit) {
    1717           0 :             break;
    1718             :         }
    1719             : 
    1720           0 :         src+=U16_LENGTH(c);
    1721             :         // The current character (c) at [prevSrc..src[ has a non-zero lead combining class.
    1722             :         // Check for proper order, and decompose locally if necessary.
    1723           0 :         if((prevFCD16&0xff)<=(fcd16>>8)) {
    1724             :             // proper order: prev tccc <= current lccc
    1725           0 :             if((fcd16&0xff)<=1) {
    1726           0 :                 prevBoundary=src;
    1727             :             }
    1728           0 :             if(buffer!=NULL && !buffer->appendZeroCC(c, errorCode)) {
    1729           0 :                 break;
    1730             :             }
    1731           0 :             prevFCD16=fcd16;
    1732           0 :             continue;
    1733           0 :         } else if(buffer==NULL) {
    1734           0 :             return prevBoundary;  // quick check "no"
    1735             :         } else {
    1736             :             /*
    1737             :              * Back out the part of the source that we copied or appended
    1738             :              * already but is now going to be decomposed.
    1739             :              * prevSrc is set to after what was copied/appended.
    1740             :              */
    1741           0 :             buffer->removeSuffix((int32_t)(prevSrc-prevBoundary));
    1742             :             /*
    1743             :              * Find the part of the source that needs to be decomposed,
    1744             :              * up to the next safe boundary.
    1745             :              */
    1746           0 :             src=findNextFCDBoundary(src, limit);
    1747             :             /*
    1748             :              * The source text does not fulfill the conditions for FCD.
    1749             :              * Decompose and reorder a limited piece of the text.
    1750             :              */
    1751           0 :             if(!decomposeShort(prevBoundary, src, *buffer, errorCode)) {
    1752           0 :                 break;
    1753             :             }
    1754           0 :             prevBoundary=src;
    1755           0 :             prevFCD16=0;
    1756             :         }
    1757           0 :     }
    1758           0 :     return src;
    1759             : }
    1760             : 
    1761           0 : void Normalizer2Impl::makeFCDAndAppend(const UChar *src, const UChar *limit,
    1762             :                                        UBool doMakeFCD,
    1763             :                                        UnicodeString &safeMiddle,
    1764             :                                        ReorderingBuffer &buffer,
    1765             :                                        UErrorCode &errorCode) const {
    1766           0 :     if(!buffer.isEmpty()) {
    1767           0 :         const UChar *firstBoundaryInSrc=findNextFCDBoundary(src, limit);
    1768           0 :         if(src!=firstBoundaryInSrc) {
    1769           0 :             const UChar *lastBoundaryInDest=findPreviousFCDBoundary(buffer.getStart(),
    1770           0 :                                                                     buffer.getLimit());
    1771           0 :             int32_t destSuffixLength=(int32_t)(buffer.getLimit()-lastBoundaryInDest);
    1772           0 :             UnicodeString middle(lastBoundaryInDest, destSuffixLength);
    1773           0 :             buffer.removeSuffix(destSuffixLength);
    1774           0 :             safeMiddle=middle;
    1775           0 :             middle.append(src, (int32_t)(firstBoundaryInSrc-src));
    1776           0 :             const UChar *middleStart=middle.getBuffer();
    1777           0 :             makeFCD(middleStart, middleStart+middle.length(), &buffer, errorCode);
    1778           0 :             if(U_FAILURE(errorCode)) {
    1779           0 :                 return;
    1780             :             }
    1781           0 :             src=firstBoundaryInSrc;
    1782             :         }
    1783             :     }
    1784           0 :     if(doMakeFCD) {
    1785           0 :         makeFCD(src, limit, &buffer, errorCode);
    1786             :     } else {
    1787           0 :         if(limit==NULL) {  // appendZeroCC() needs limit!=NULL
    1788           0 :             limit=u_strchr(src, 0);
    1789             :         }
    1790           0 :         buffer.appendZeroCC(src, limit, errorCode);
    1791             :     }
    1792             : }
    1793             : 
    1794           0 : const UChar *Normalizer2Impl::findPreviousFCDBoundary(const UChar *start, const UChar *p) const {
    1795           0 :     while(start<p && previousFCD16(start, p)>0xff) {}
    1796           0 :     return p;
    1797             : }
    1798             : 
    1799           0 : const UChar *Normalizer2Impl::findNextFCDBoundary(const UChar *p, const UChar *limit) const {
    1800           0 :     while(p<limit) {
    1801           0 :         const UChar *codePointStart=p;
    1802           0 :         if(nextFCD16(p, limit)<=0xff) {
    1803           0 :             return codePointStart;
    1804             :         }
    1805             :     }
    1806           0 :     return p;
    1807             : }
    1808             : 
    1809             : // CanonicalIterator data -------------------------------------------------- ***
    1810             : 
    1811           0 : CanonIterData::CanonIterData(UErrorCode &errorCode) :
    1812           0 :         trie(utrie2_open(0, 0, &errorCode)),
    1813           0 :         canonStartSets(uprv_deleteUObject, NULL, errorCode) {}
    1814             : 
    1815           0 : CanonIterData::~CanonIterData() {
    1816           0 :     utrie2_close(trie);
    1817           0 : }
    1818             : 
    1819           0 : void CanonIterData::addToStartSet(UChar32 origin, UChar32 decompLead, UErrorCode &errorCode) {
    1820           0 :     uint32_t canonValue=utrie2_get32(trie, decompLead);
    1821           0 :     if((canonValue&(CANON_HAS_SET|CANON_VALUE_MASK))==0 && origin!=0) {
    1822             :         // origin is the first character whose decomposition starts with
    1823             :         // the character for which we are setting the value.
    1824           0 :         utrie2_set32(trie, decompLead, canonValue|origin, &errorCode);
    1825             :     } else {
    1826             :         // origin is not the first character, or it is U+0000.
    1827             :         UnicodeSet *set;
    1828           0 :         if((canonValue&CANON_HAS_SET)==0) {
    1829           0 :             set=new UnicodeSet;
    1830           0 :             if(set==NULL) {
    1831           0 :                 errorCode=U_MEMORY_ALLOCATION_ERROR;
    1832           0 :                 return;
    1833             :             }
    1834           0 :             UChar32 firstOrigin=(UChar32)(canonValue&CANON_VALUE_MASK);
    1835           0 :             canonValue=(canonValue&~CANON_VALUE_MASK)|CANON_HAS_SET|(uint32_t)canonStartSets.size();
    1836           0 :             utrie2_set32(trie, decompLead, canonValue, &errorCode);
    1837           0 :             canonStartSets.addElement(set, errorCode);
    1838           0 :             if(firstOrigin!=0) {
    1839           0 :                 set->add(firstOrigin);
    1840             :             }
    1841             :         } else {
    1842           0 :             set=(UnicodeSet *)canonStartSets[(int32_t)(canonValue&CANON_VALUE_MASK)];
    1843             :         }
    1844           0 :         set->add(origin);
    1845             :     }
    1846             : }
    1847             : 
    1848             : U_CDECL_BEGIN
    1849             : 
    1850             : // Call Normalizer2Impl::makeCanonIterDataFromNorm16() for a range of same-norm16 characters.
    1851             : //     context: the Normalizer2Impl
    1852             : static UBool U_CALLCONV
    1853           0 : enumCIDRangeHandler(const void *context, UChar32 start, UChar32 end, uint32_t value) {
    1854           0 :     UErrorCode errorCode = U_ZERO_ERROR;
    1855           0 :     if (value != 0) {
    1856           0 :         Normalizer2Impl *impl = (Normalizer2Impl *)context;
    1857           0 :         impl->makeCanonIterDataFromNorm16(
    1858           0 :             start, end, (uint16_t)value, *impl->fCanonIterData, errorCode);
    1859             :     }
    1860           0 :     return U_SUCCESS(errorCode);
    1861             : }
    1862             : 
    1863             : 
    1864             : 
    1865             : // UInitOnce instantiation function for CanonIterData
    1866             : 
    1867             : static void U_CALLCONV 
    1868           0 : initCanonIterData(Normalizer2Impl *impl, UErrorCode &errorCode) {
    1869           0 :     U_ASSERT(impl->fCanonIterData == NULL);
    1870           0 :     impl->fCanonIterData = new CanonIterData(errorCode);
    1871           0 :     if (impl->fCanonIterData == NULL) {
    1872           0 :         errorCode=U_MEMORY_ALLOCATION_ERROR;
    1873             :     }
    1874           0 :     if (U_SUCCESS(errorCode)) {
    1875           0 :         utrie2_enum(impl->getNormTrie(), NULL, enumCIDRangeHandler, impl);
    1876           0 :         utrie2_freeze(impl->fCanonIterData->trie, UTRIE2_32_VALUE_BITS, &errorCode);
    1877             :     }
    1878           0 :     if (U_FAILURE(errorCode)) {
    1879           0 :         delete impl->fCanonIterData;
    1880           0 :         impl->fCanonIterData = NULL;
    1881             :     }
    1882           0 : }
    1883             : 
    1884             : U_CDECL_END
    1885             : 
    1886           0 : void Normalizer2Impl::makeCanonIterDataFromNorm16(UChar32 start, UChar32 end, uint16_t norm16,
    1887             :                                                   CanonIterData &newData,
    1888             :                                                   UErrorCode &errorCode) const {
    1889           0 :     if(norm16==0 || (minYesNo<=norm16 && norm16<minNoNo)) {
    1890             :         // Inert, or 2-way mapping (including Hangul syllable).
    1891             :         // We do not write a canonStartSet for any yesNo character.
    1892             :         // Composites from 2-way mappings are added at runtime from the
    1893             :         // starter's compositions list, and the other characters in
    1894             :         // 2-way mappings get CANON_NOT_SEGMENT_STARTER set because they are
    1895             :         // "maybe" characters.
    1896           0 :         return;
    1897             :     }
    1898           0 :     for(UChar32 c=start; c<=end; ++c) {
    1899           0 :         uint32_t oldValue=utrie2_get32(newData.trie, c);
    1900           0 :         uint32_t newValue=oldValue;
    1901           0 :         if(norm16>=minMaybeYes) {
    1902             :             // not a segment starter if it occurs in a decomposition or has cc!=0
    1903           0 :             newValue|=CANON_NOT_SEGMENT_STARTER;
    1904           0 :             if(norm16<MIN_NORMAL_MAYBE_YES) {
    1905           0 :                 newValue|=CANON_HAS_COMPOSITIONS;
    1906             :             }
    1907           0 :         } else if(norm16<minYesNo) {
    1908           0 :             newValue|=CANON_HAS_COMPOSITIONS;
    1909             :         } else {
    1910             :             // c has a one-way decomposition
    1911           0 :             UChar32 c2=c;
    1912           0 :             uint16_t norm16_2=norm16;
    1913           0 :             while(limitNoNo<=norm16_2 && norm16_2<minMaybeYes) {
    1914           0 :                 c2=mapAlgorithmic(c2, norm16_2);
    1915           0 :                 norm16_2=getNorm16(c2);
    1916             :             }
    1917           0 :             if(minYesNo<=norm16_2 && norm16_2<limitNoNo) {
    1918             :                 // c decomposes, get everything from the variable-length extra data
    1919           0 :                 const uint16_t *mapping=getMapping(norm16_2);
    1920           0 :                 uint16_t firstUnit=*mapping;
    1921           0 :                 int32_t length=firstUnit&MAPPING_LENGTH_MASK;
    1922           0 :                 if((firstUnit&MAPPING_HAS_CCC_LCCC_WORD)!=0) {
    1923           0 :                     if(c==c2 && (*(mapping-1)&0xff)!=0) {
    1924           0 :                         newValue|=CANON_NOT_SEGMENT_STARTER;  // original c has cc!=0
    1925             :                     }
    1926             :                 }
    1927             :                 // Skip empty mappings (no characters in the decomposition).
    1928           0 :                 if(length!=0) {
    1929           0 :                     ++mapping;  // skip over the firstUnit
    1930             :                     // add c to first code point's start set
    1931           0 :                     int32_t i=0;
    1932           0 :                     U16_NEXT_UNSAFE(mapping, i, c2);
    1933           0 :                     newData.addToStartSet(c, c2, errorCode);
    1934             :                     // Set CANON_NOT_SEGMENT_STARTER for each remaining code point of a
    1935             :                     // one-way mapping. A 2-way mapping is possible here after
    1936             :                     // intermediate algorithmic mapping.
    1937           0 :                     if(norm16_2>=minNoNo) {
    1938           0 :                         while(i<length) {
    1939           0 :                             U16_NEXT_UNSAFE(mapping, i, c2);
    1940           0 :                             uint32_t c2Value=utrie2_get32(newData.trie, c2);
    1941           0 :                             if((c2Value&CANON_NOT_SEGMENT_STARTER)==0) {
    1942           0 :                                 utrie2_set32(newData.trie, c2, c2Value|CANON_NOT_SEGMENT_STARTER,
    1943           0 :                                              &errorCode);
    1944             :                             }
    1945             :                         }
    1946             :                     }
    1947           0 :                 }
    1948             :             } else {
    1949             :                 // c decomposed to c2 algorithmically; c has cc==0
    1950           0 :                 newData.addToStartSet(c, c2, errorCode);
    1951             :             }
    1952             :         }
    1953           0 :         if(newValue!=oldValue) {
    1954           0 :             utrie2_set32(newData.trie, c, newValue, &errorCode);
    1955             :         }
    1956             :     }
    1957             : }
    1958             : 
    1959           0 : UBool Normalizer2Impl::ensureCanonIterData(UErrorCode &errorCode) const {
    1960             :     // Logically const: Synchronized instantiation.
    1961           0 :     Normalizer2Impl *me=const_cast<Normalizer2Impl *>(this);
    1962           0 :     umtx_initOnce(me->fCanonIterDataInitOnce, &initCanonIterData, me, errorCode);
    1963           0 :     return U_SUCCESS(errorCode);
    1964             : }
    1965             : 
    1966           0 : int32_t Normalizer2Impl::getCanonValue(UChar32 c) const {
    1967           0 :     return (int32_t)utrie2_get32(fCanonIterData->trie, c);
    1968             : }
    1969             : 
    1970           0 : const UnicodeSet &Normalizer2Impl::getCanonStartSet(int32_t n) const {
    1971           0 :     return *(const UnicodeSet *)fCanonIterData->canonStartSets[n];
    1972             : }
    1973             : 
    1974           0 : UBool Normalizer2Impl::isCanonSegmentStarter(UChar32 c) const {
    1975           0 :     return getCanonValue(c)>=0;
    1976             : }
    1977             : 
    1978           0 : UBool Normalizer2Impl::getCanonStartSet(UChar32 c, UnicodeSet &set) const {
    1979           0 :     int32_t canonValue=getCanonValue(c)&~CANON_NOT_SEGMENT_STARTER;
    1980           0 :     if(canonValue==0) {
    1981           0 :         return FALSE;
    1982             :     }
    1983           0 :     set.clear();
    1984           0 :     int32_t value=canonValue&CANON_VALUE_MASK;
    1985           0 :     if((canonValue&CANON_HAS_SET)!=0) {
    1986           0 :         set.addAll(getCanonStartSet(value));
    1987           0 :     } else if(value!=0) {
    1988           0 :         set.add(value);
    1989             :     }
    1990           0 :     if((canonValue&CANON_HAS_COMPOSITIONS)!=0) {
    1991           0 :         uint16_t norm16=getNorm16(c);
    1992           0 :         if(norm16==JAMO_L) {
    1993             :             UChar32 syllable=
    1994           0 :                 (UChar32)(Hangul::HANGUL_BASE+(c-Hangul::JAMO_L_BASE)*Hangul::JAMO_VT_COUNT);
    1995           0 :             set.add(syllable, syllable+Hangul::JAMO_VT_COUNT-1);
    1996             :         } else {
    1997           0 :             addComposites(getCompositionsList(norm16), set);
    1998             :         }
    1999             :     }
    2000           0 :     return TRUE;
    2001             : }
    2002             : 
    2003             : U_NAMESPACE_END
    2004             : 
    2005             : // Normalizer2 data swapping ----------------------------------------------- ***
    2006             : 
    2007             : U_NAMESPACE_USE
    2008             : 
    2009             : U_CAPI int32_t U_EXPORT2
    2010           0 : unorm2_swap(const UDataSwapper *ds,
    2011             :             const void *inData, int32_t length, void *outData,
    2012             :             UErrorCode *pErrorCode) {
    2013             :     const UDataInfo *pInfo;
    2014             :     int32_t headerSize;
    2015             : 
    2016             :     const uint8_t *inBytes;
    2017             :     uint8_t *outBytes;
    2018             : 
    2019             :     const int32_t *inIndexes;
    2020             :     int32_t indexes[Normalizer2Impl::IX_MIN_MAYBE_YES+1];
    2021             : 
    2022             :     int32_t i, offset, nextOffset, size;
    2023             : 
    2024             :     /* udata_swapDataHeader checks the arguments */
    2025           0 :     headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
    2026           0 :     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    2027           0 :         return 0;
    2028             :     }
    2029             : 
    2030             :     /* check data format and format version */
    2031           0 :     pInfo=(const UDataInfo *)((const char *)inData+4);
    2032           0 :     if(!(
    2033           0 :         pInfo->dataFormat[0]==0x4e &&   /* dataFormat="Nrm2" */
    2034           0 :         pInfo->dataFormat[1]==0x72 &&
    2035           0 :         pInfo->dataFormat[2]==0x6d &&
    2036           0 :         pInfo->dataFormat[3]==0x32 &&
    2037           0 :         (pInfo->formatVersion[0]==1 || pInfo->formatVersion[0]==2)
    2038             :     )) {
    2039           0 :         udata_printError(ds, "unorm2_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as Normalizer2 data\n",
    2040           0 :                          pInfo->dataFormat[0], pInfo->dataFormat[1],
    2041           0 :                          pInfo->dataFormat[2], pInfo->dataFormat[3],
    2042           0 :                          pInfo->formatVersion[0]);
    2043           0 :         *pErrorCode=U_UNSUPPORTED_ERROR;
    2044           0 :         return 0;
    2045             :     }
    2046             : 
    2047           0 :     inBytes=(const uint8_t *)inData+headerSize;
    2048           0 :     outBytes=(uint8_t *)outData+headerSize;
    2049             : 
    2050           0 :     inIndexes=(const int32_t *)inBytes;
    2051             : 
    2052           0 :     if(length>=0) {
    2053           0 :         length-=headerSize;
    2054           0 :         if(length<(int32_t)sizeof(indexes)) {
    2055             :             udata_printError(ds, "unorm2_swap(): too few bytes (%d after header) for Normalizer2 data\n",
    2056           0 :                              length);
    2057           0 :             *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    2058           0 :             return 0;
    2059             :         }
    2060             :     }
    2061             : 
    2062             :     /* read the first few indexes */
    2063           0 :     for(i=0; i<=Normalizer2Impl::IX_MIN_MAYBE_YES; ++i) {
    2064           0 :         indexes[i]=udata_readInt32(ds, inIndexes[i]);
    2065             :     }
    2066             : 
    2067             :     /* get the total length of the data */
    2068           0 :     size=indexes[Normalizer2Impl::IX_TOTAL_SIZE];
    2069             : 
    2070           0 :     if(length>=0) {
    2071           0 :         if(length<size) {
    2072             :             udata_printError(ds, "unorm2_swap(): too few bytes (%d after header) for all of Normalizer2 data\n",
    2073           0 :                              length);
    2074           0 :             *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    2075           0 :             return 0;
    2076             :         }
    2077             : 
    2078             :         /* copy the data for inaccessible bytes */
    2079           0 :         if(inBytes!=outBytes) {
    2080           0 :             uprv_memcpy(outBytes, inBytes, size);
    2081             :         }
    2082             : 
    2083           0 :         offset=0;
    2084             : 
    2085             :         /* swap the int32_t indexes[] */
    2086           0 :         nextOffset=indexes[Normalizer2Impl::IX_NORM_TRIE_OFFSET];
    2087           0 :         ds->swapArray32(ds, inBytes, nextOffset-offset, outBytes, pErrorCode);
    2088           0 :         offset=nextOffset;
    2089             : 
    2090             :         /* swap the UTrie2 */
    2091           0 :         nextOffset=indexes[Normalizer2Impl::IX_EXTRA_DATA_OFFSET];
    2092           0 :         utrie2_swap(ds, inBytes+offset, nextOffset-offset, outBytes+offset, pErrorCode);
    2093           0 :         offset=nextOffset;
    2094             : 
    2095             :         /* swap the uint16_t extraData[] */
    2096           0 :         nextOffset=indexes[Normalizer2Impl::IX_SMALL_FCD_OFFSET];
    2097           0 :         ds->swapArray16(ds, inBytes+offset, nextOffset-offset, outBytes+offset, pErrorCode);
    2098           0 :         offset=nextOffset;
    2099             : 
    2100             :         /* no need to swap the uint8_t smallFCD[] (new in formatVersion 2) */
    2101           0 :         nextOffset=indexes[Normalizer2Impl::IX_SMALL_FCD_OFFSET+1];
    2102           0 :         offset=nextOffset;
    2103             : 
    2104           0 :         U_ASSERT(offset==size);
    2105             :     }
    2106             : 
    2107           0 :     return headerSize+size;
    2108             : }
    2109             : 
    2110             : #endif  // !UCONFIG_NO_NORMALIZATION

Generated by: LCOV version 1.13