LCOV - code coverage report
Current view: top level - intl/icu/source/common - ubidi.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1355 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 52 0.0 %
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) 1999-2015, International Business Machines
       7             : *   Corporation and others.  All Rights Reserved.
       8             : *
       9             : ******************************************************************************
      10             : *   file name:  ubidi.c
      11             : *   encoding:   UTF-8
      12             : *   tab size:   8 (not used)
      13             : *   indentation:4
      14             : *
      15             : *   created on: 1999jul27
      16             : *   created by: Markus W. Scherer, updated by Matitiahu Allouche
      17             : *
      18             : */
      19             : 
      20             : #include "cmemory.h"
      21             : #include "unicode/utypes.h"
      22             : #include "unicode/ustring.h"
      23             : #include "unicode/uchar.h"
      24             : #include "unicode/ubidi.h"
      25             : #include "unicode/utf16.h"
      26             : #include "ubidi_props.h"
      27             : #include "ubidiimp.h"
      28             : #include "uassert.h"
      29             : 
      30             : /*
      31             :  * General implementation notes:
      32             :  *
      33             :  * Throughout the implementation, there are comments like (W2) that refer to
      34             :  * rules of the BiDi algorithm, in this example to the second rule of the
      35             :  * resolution of weak types.
      36             :  *
      37             :  * For handling surrogate pairs, where two UChar's form one "abstract" (or UTF-32)
      38             :  * character according to UTF-16, the second UChar gets the directional property of
      39             :  * the entire character assigned, while the first one gets a BN, a boundary
      40             :  * neutral, type, which is ignored by most of the algorithm according to
      41             :  * rule (X9) and the implementation suggestions of the BiDi algorithm.
      42             :  *
      43             :  * Later, adjustWSLevels() will set the level for each BN to that of the
      44             :  * following character (UChar), which results in surrogate pairs getting the
      45             :  * same level on each of their surrogates.
      46             :  *
      47             :  * In a UTF-8 implementation, the same thing could be done: the last byte of
      48             :  * a multi-byte sequence would get the "real" property, while all previous
      49             :  * bytes of that sequence would get BN.
      50             :  *
      51             :  * It is not possible to assign all those parts of a character the same real
      52             :  * property because this would fail in the resolution of weak types with rules
      53             :  * that look at immediately surrounding types.
      54             :  *
      55             :  * As a related topic, this implementation does not remove Boundary Neutral
      56             :  * types from the input, but ignores them wherever this is relevant.
      57             :  * For example, the loop for the resolution of the weak types reads
      58             :  * types until it finds a non-BN.
      59             :  * Also, explicit embedding codes are neither changed into BN nor removed.
      60             :  * They are only treated the same way real BNs are.
      61             :  * As stated before, adjustWSLevels() takes care of them at the end.
      62             :  * For the purpose of conformance, the levels of all these codes
      63             :  * do not matter.
      64             :  *
      65             :  * Note that this implementation modifies the dirProps
      66             :  * after the initial setup, when applying X5c (replace FSI by LRI or RLI),
      67             :  * X6, N0 (replace paired brackets by L or R).
      68             :  *
      69             :  * In this implementation, the resolution of weak types (W1 to W6),
      70             :  * neutrals (N1 and N2), and the assignment of the resolved level (In)
      71             :  * are all done in one single loop, in resolveImplicitLevels().
      72             :  * Changes of dirProp values are done on the fly, without writing
      73             :  * them back to the dirProps array.
      74             :  *
      75             :  *
      76             :  * This implementation contains code that allows to bypass steps of the
      77             :  * algorithm that are not needed on the specific paragraph
      78             :  * in order to speed up the most common cases considerably,
      79             :  * like text that is entirely LTR, or RTL text without numbers.
      80             :  *
      81             :  * Most of this is done by setting a bit for each directional property
      82             :  * in a flags variable and later checking for whether there are
      83             :  * any LTR characters or any RTL characters, or both, whether
      84             :  * there are any explicit embedding codes, etc.
      85             :  *
      86             :  * If the (Xn) steps are performed, then the flags are re-evaluated,
      87             :  * because they will then not contain the embedding codes any more
      88             :  * and will be adjusted for override codes, so that subsequently
      89             :  * more bypassing may be possible than what the initial flags suggested.
      90             :  *
      91             :  * If the text is not mixed-directional, then the
      92             :  * algorithm steps for the weak type resolution are not performed,
      93             :  * and all levels are set to the paragraph level.
      94             :  *
      95             :  * If there are no explicit embedding codes, then the (Xn) steps
      96             :  * are not performed.
      97             :  *
      98             :  * If embedding levels are supplied as a parameter, then all
      99             :  * explicit embedding codes are ignored, and the (Xn) steps
     100             :  * are not performed.
     101             :  *
     102             :  * White Space types could get the level of the run they belong to,
     103             :  * and are checked with a test of (flags&MASK_EMBEDDING) to
     104             :  * consider if the paragraph direction should be considered in
     105             :  * the flags variable.
     106             :  *
     107             :  * If there are no White Space types in the paragraph, then
     108             :  * (L1) is not necessary in adjustWSLevels().
     109             :  */
     110             : 
     111             : /* to avoid some conditional statements, use tiny constant arrays */
     112             : static const Flags flagLR[2]={ DIRPROP_FLAG(L), DIRPROP_FLAG(R) };
     113             : static const Flags flagE[2]={ DIRPROP_FLAG(LRE), DIRPROP_FLAG(RLE) };
     114             : static const Flags flagO[2]={ DIRPROP_FLAG(LRO), DIRPROP_FLAG(RLO) };
     115             : 
     116             : #define DIRPROP_FLAG_LR(level) flagLR[(level)&1]
     117             : #define DIRPROP_FLAG_E(level)  flagE[(level)&1]
     118             : #define DIRPROP_FLAG_O(level)  flagO[(level)&1]
     119             : 
     120             : #define DIR_FROM_STRONG(strong) ((strong)==L ? L : R)
     121             : 
     122             : #define NO_OVERRIDE(level)  ((level)&~UBIDI_LEVEL_OVERRIDE)
     123             : 
     124             : /* UBiDi object management -------------------------------------------------- */
     125             : 
     126             : U_CAPI UBiDi * U_EXPORT2
     127           0 : ubidi_open(void)
     128             : {
     129           0 :     UErrorCode errorCode=U_ZERO_ERROR;
     130           0 :     return ubidi_openSized(0, 0, &errorCode);
     131             : }
     132             : 
     133             : U_CAPI UBiDi * U_EXPORT2
     134           0 : ubidi_openSized(int32_t maxLength, int32_t maxRunCount, UErrorCode *pErrorCode) {
     135             :     UBiDi *pBiDi;
     136             : 
     137             :     /* check the argument values */
     138           0 :     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
     139           0 :         return NULL;
     140           0 :     } else if(maxLength<0 || maxRunCount<0) {
     141           0 :         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
     142           0 :         return NULL;    /* invalid arguments */
     143             :     }
     144             : 
     145             :     /* allocate memory for the object */
     146           0 :     pBiDi=(UBiDi *)uprv_malloc(sizeof(UBiDi));
     147           0 :     if(pBiDi==NULL) {
     148           0 :         *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
     149           0 :         return NULL;
     150             :     }
     151             : 
     152             :     /* reset the object, all pointers NULL, all flags FALSE, all sizes 0 */
     153           0 :     uprv_memset(pBiDi, 0, sizeof(UBiDi));
     154             : 
     155             :     /* get BiDi properties */
     156           0 :     pBiDi->bdp=ubidi_getSingleton();
     157             : 
     158             :     /* allocate memory for arrays as requested */
     159           0 :     if(maxLength>0) {
     160           0 :         if( !getInitialDirPropsMemory(pBiDi, maxLength) ||
     161           0 :             !getInitialLevelsMemory(pBiDi, maxLength)
     162             :         ) {
     163           0 :             *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
     164             :         }
     165             :     } else {
     166           0 :         pBiDi->mayAllocateText=TRUE;
     167             :     }
     168             : 
     169           0 :     if(maxRunCount>0) {
     170           0 :         if(maxRunCount==1) {
     171             :             /* use simpleRuns[] */
     172           0 :             pBiDi->runsSize=sizeof(Run);
     173           0 :         } else if(!getInitialRunsMemory(pBiDi, maxRunCount)) {
     174           0 :             *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
     175             :         }
     176             :     } else {
     177           0 :         pBiDi->mayAllocateRuns=TRUE;
     178             :     }
     179             : 
     180           0 :     if(U_SUCCESS(*pErrorCode)) {
     181           0 :         return pBiDi;
     182             :     } else {
     183           0 :         ubidi_close(pBiDi);
     184           0 :         return NULL;
     185             :     }
     186             : }
     187             : 
     188             : /*
     189             :  * We are allowed to allocate memory if memory==NULL or
     190             :  * mayAllocate==TRUE for each array that we need.
     191             :  * We also try to grow memory as needed if we
     192             :  * allocate it.
     193             :  *
     194             :  * Assume sizeNeeded>0.
     195             :  * If *pMemory!=NULL, then assume *pSize>0.
     196             :  *
     197             :  * ### this realloc() may unnecessarily copy the old data,
     198             :  * which we know we don't need any more;
     199             :  * is this the best way to do this??
     200             :  */
     201             : U_CFUNC UBool
     202           0 : ubidi_getMemory(BidiMemoryForAllocation *bidiMem, int32_t *pSize, UBool mayAllocate, int32_t sizeNeeded) {
     203           0 :     void **pMemory = (void **)bidiMem;
     204             :     /* check for existing memory */
     205           0 :     if(*pMemory==NULL) {
     206             :         /* we need to allocate memory */
     207           0 :         if(mayAllocate && (*pMemory=uprv_malloc(sizeNeeded))!=NULL) {
     208           0 :             *pSize=sizeNeeded;
     209           0 :             return TRUE;
     210             :         } else {
     211           0 :             return FALSE;
     212             :         }
     213             :     } else {
     214           0 :         if(sizeNeeded<=*pSize) {
     215             :             /* there is already enough memory */
     216           0 :             return TRUE;
     217             :         }
     218           0 :         else if(!mayAllocate) {
     219             :             /* not enough memory, and we must not allocate */
     220           0 :             return FALSE;
     221             :         } else {
     222             :             /* we try to grow */
     223             :             void *memory;
     224             :             /* in most cases, we do not need the copy-old-data part of
     225             :              * realloc, but it is needed when adding runs using getRunsMemory()
     226             :              * in setParaRunsOnly()
     227             :              */
     228           0 :             if((memory=uprv_realloc(*pMemory, sizeNeeded))!=NULL) {
     229           0 :                 *pMemory=memory;
     230           0 :                 *pSize=sizeNeeded;
     231           0 :                 return TRUE;
     232             :             } else {
     233             :                 /* we failed to grow */
     234           0 :                 return FALSE;
     235             :             }
     236             :         }
     237             :     }
     238             : }
     239             : 
     240             : U_CAPI void U_EXPORT2
     241           0 : ubidi_close(UBiDi *pBiDi) {
     242           0 :     if(pBiDi!=NULL) {
     243           0 :         pBiDi->pParaBiDi=NULL;          /* in case one tries to reuse this block */
     244           0 :         if(pBiDi->dirPropsMemory!=NULL) {
     245           0 :             uprv_free(pBiDi->dirPropsMemory);
     246             :         }
     247           0 :         if(pBiDi->levelsMemory!=NULL) {
     248           0 :             uprv_free(pBiDi->levelsMemory);
     249             :         }
     250           0 :         if(pBiDi->openingsMemory!=NULL) {
     251           0 :             uprv_free(pBiDi->openingsMemory);
     252             :         }
     253           0 :         if(pBiDi->parasMemory!=NULL) {
     254           0 :             uprv_free(pBiDi->parasMemory);
     255             :         }
     256           0 :         if(pBiDi->runsMemory!=NULL) {
     257           0 :             uprv_free(pBiDi->runsMemory);
     258             :         }
     259           0 :         if(pBiDi->isolatesMemory!=NULL) {
     260           0 :             uprv_free(pBiDi->isolatesMemory);
     261             :         }
     262           0 :         if(pBiDi->insertPoints.points!=NULL) {
     263           0 :             uprv_free(pBiDi->insertPoints.points);
     264             :         }
     265             : 
     266           0 :         uprv_free(pBiDi);
     267             :     }
     268           0 : }
     269             : 
     270             : /* set to approximate "inverse BiDi" ---------------------------------------- */
     271             : 
     272             : U_CAPI void U_EXPORT2
     273           0 : ubidi_setInverse(UBiDi *pBiDi, UBool isInverse) {
     274           0 :     if(pBiDi!=NULL) {
     275           0 :         pBiDi->isInverse=isInverse;
     276           0 :         pBiDi->reorderingMode = isInverse ? UBIDI_REORDER_INVERSE_NUMBERS_AS_L
     277             :                                           : UBIDI_REORDER_DEFAULT;
     278             :     }
     279           0 : }
     280             : 
     281             : U_CAPI UBool U_EXPORT2
     282           0 : ubidi_isInverse(UBiDi *pBiDi) {
     283           0 :     if(pBiDi!=NULL) {
     284           0 :         return pBiDi->isInverse;
     285             :     } else {
     286           0 :         return FALSE;
     287             :     }
     288             : }
     289             : 
     290             : /* FOOD FOR THOUGHT: currently the reordering modes are a mixture of
     291             :  * algorithm for direct BiDi, algorithm for inverse BiDi and the bizarre
     292             :  * concept of RUNS_ONLY which is a double operation.
     293             :  * It could be advantageous to divide this into 3 concepts:
     294             :  * a) Operation: direct / inverse / RUNS_ONLY
     295             :  * b) Direct algorithm: default / NUMBERS_SPECIAL / GROUP_NUMBERS_WITH_R
     296             :  * c) Inverse algorithm: default / INVERSE_LIKE_DIRECT / NUMBERS_SPECIAL
     297             :  * This would allow combinations not possible today like RUNS_ONLY with
     298             :  * NUMBERS_SPECIAL.
     299             :  * Also allow to set INSERT_MARKS for the direct step of RUNS_ONLY and
     300             :  * REMOVE_CONTROLS for the inverse step.
     301             :  * Not all combinations would be supported, and probably not all do make sense.
     302             :  * This would need to document which ones are supported and what are the
     303             :  * fallbacks for unsupported combinations.
     304             :  */
     305             : U_CAPI void U_EXPORT2
     306           0 : ubidi_setReorderingMode(UBiDi *pBiDi, UBiDiReorderingMode reorderingMode) {
     307           0 :     if ((pBiDi!=NULL) && (reorderingMode >= UBIDI_REORDER_DEFAULT)
     308           0 :                         && (reorderingMode < UBIDI_REORDER_COUNT)) {
     309           0 :         pBiDi->reorderingMode = reorderingMode;
     310           0 :         pBiDi->isInverse = (UBool)(reorderingMode == UBIDI_REORDER_INVERSE_NUMBERS_AS_L);
     311             :     }
     312           0 : }
     313             : 
     314             : U_CAPI UBiDiReorderingMode U_EXPORT2
     315           0 : ubidi_getReorderingMode(UBiDi *pBiDi) {
     316           0 :     if (pBiDi!=NULL) {
     317           0 :         return pBiDi->reorderingMode;
     318             :     } else {
     319           0 :         return UBIDI_REORDER_DEFAULT;
     320             :     }
     321             : }
     322             : 
     323             : U_CAPI void U_EXPORT2
     324           0 : ubidi_setReorderingOptions(UBiDi *pBiDi, uint32_t reorderingOptions) {
     325           0 :     if (reorderingOptions & UBIDI_OPTION_REMOVE_CONTROLS) {
     326           0 :         reorderingOptions&=~UBIDI_OPTION_INSERT_MARKS;
     327             :     }
     328           0 :     if (pBiDi!=NULL) {
     329           0 :         pBiDi->reorderingOptions=reorderingOptions;
     330             :     }
     331           0 : }
     332             : 
     333             : U_CAPI uint32_t U_EXPORT2
     334           0 : ubidi_getReorderingOptions(UBiDi *pBiDi) {
     335           0 :     if (pBiDi!=NULL) {
     336           0 :         return pBiDi->reorderingOptions;
     337             :     } else {
     338           0 :         return 0;
     339             :     }
     340             : }
     341             : 
     342             : U_CAPI UBiDiDirection U_EXPORT2
     343           0 : ubidi_getBaseDirection(const UChar *text,
     344             : int32_t length){
     345             : 
     346             :     int32_t i;
     347             :     UChar32 uchar;
     348             :     UCharDirection dir;
     349             : 
     350           0 :     if( text==NULL || length<-1 ){
     351           0 :         return UBIDI_NEUTRAL;
     352             :     }
     353             : 
     354           0 :     if(length==-1) {
     355           0 :         length=u_strlen(text);
     356             :     }
     357             : 
     358           0 :     for( i = 0 ; i < length; ) {
     359             :         /* i is incremented by U16_NEXT */
     360           0 :         U16_NEXT(text, i, length, uchar);
     361           0 :         dir = u_charDirection(uchar);
     362           0 :         if( dir == U_LEFT_TO_RIGHT )
     363           0 :                 return UBIDI_LTR;
     364           0 :         if( dir == U_RIGHT_TO_LEFT || dir ==U_RIGHT_TO_LEFT_ARABIC )
     365           0 :                 return UBIDI_RTL;
     366             :     }
     367           0 :     return UBIDI_NEUTRAL;
     368             : }
     369             : 
     370             : /* perform (P2)..(P3) ------------------------------------------------------- */
     371             : 
     372             : /**
     373             :  * Returns the directionality of the first strong character
     374             :  * after the last B in prologue, if any.
     375             :  * Requires prologue!=null.
     376             :  */
     377             : static DirProp
     378           0 : firstL_R_AL(UBiDi *pBiDi) {
     379           0 :     const UChar *text=pBiDi->prologue;
     380           0 :     int32_t length=pBiDi->proLength;
     381             :     int32_t i;
     382             :     UChar32 uchar;
     383           0 :     DirProp dirProp, result=ON;
     384           0 :     for(i=0; i<length; ) {
     385             :         /* i is incremented by U16_NEXT */
     386           0 :         U16_NEXT(text, i, length, uchar);
     387           0 :         dirProp=(DirProp)ubidi_getCustomizedClass(pBiDi, uchar);
     388           0 :         if(result==ON) {
     389           0 :             if(dirProp==L || dirProp==R || dirProp==AL) {
     390           0 :                 result=dirProp;
     391             :             }
     392             :         } else {
     393           0 :             if(dirProp==B) {
     394           0 :                 result=ON;
     395             :             }
     396             :         }
     397             :     }
     398           0 :     return result;
     399             : }
     400             : 
     401             : /*
     402             :  * Check that there are enough entries in the array pointed to by pBiDi->paras
     403             :  */
     404             : static UBool
     405           0 : checkParaCount(UBiDi *pBiDi) {
     406           0 :     int32_t count=pBiDi->paraCount;
     407           0 :     if(pBiDi->paras==pBiDi->simpleParas) {
     408           0 :         if(count<=SIMPLE_PARAS_COUNT)
     409           0 :             return TRUE;
     410           0 :         if(!getInitialParasMemory(pBiDi, SIMPLE_PARAS_COUNT * 2))
     411           0 :             return FALSE;
     412           0 :         pBiDi->paras=pBiDi->parasMemory;
     413           0 :         uprv_memcpy(pBiDi->parasMemory, pBiDi->simpleParas, SIMPLE_PARAS_COUNT * sizeof(Para));
     414           0 :         return TRUE;
     415             :     }
     416           0 :     if(!getInitialParasMemory(pBiDi, count * 2))
     417           0 :         return FALSE;
     418           0 :     pBiDi->paras=pBiDi->parasMemory;
     419           0 :     return TRUE;
     420             : }
     421             : 
     422             : /*
     423             :  * Get the directional properties for the text, calculate the flags bit-set, and
     424             :  * determine the paragraph level if necessary (in pBiDi->paras[i].level).
     425             :  * FSI initiators are also resolved and their dirProp replaced with LRI or RLI.
     426             :  * When encountering an FSI, it is initially replaced with an LRI, which is the
     427             :  * default. Only if a strong R or AL is found within its scope will the LRI be
     428             :  * replaced by an RLI.
     429             :  */
     430             : static UBool
     431           0 : getDirProps(UBiDi *pBiDi) {
     432           0 :     const UChar *text=pBiDi->text;
     433           0 :     DirProp *dirProps=pBiDi->dirPropsMemory;    /* pBiDi->dirProps is const */
     434             : 
     435           0 :     int32_t i=0, originalLength=pBiDi->originalLength;
     436           0 :     Flags flags=0;      /* collect all directionalities in the text */
     437             :     UChar32 uchar;
     438           0 :     DirProp dirProp=0, defaultParaLevel=0;  /* initialize to avoid compiler warnings */
     439           0 :     UBool isDefaultLevel=IS_DEFAULT_LEVEL(pBiDi->paraLevel);
     440             :     /* for inverse BiDi, the default para level is set to RTL if there is a
     441             :        strong R or AL character at either end of the text                            */
     442           0 :     UBool isDefaultLevelInverse=isDefaultLevel && (UBool)
     443           0 :             (pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_LIKE_DIRECT ||
     444           0 :              pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL);
     445           0 :     int32_t lastArabicPos=-1;
     446           0 :     int32_t controlCount=0;
     447           0 :     UBool removeBiDiControls = (UBool)(pBiDi->reorderingOptions &
     448           0 :                                        UBIDI_OPTION_REMOVE_CONTROLS);
     449             : 
     450             :     enum State {
     451             :          NOT_SEEKING_STRONG,            /* 0: not contextual paraLevel, not after FSI */
     452             :          SEEKING_STRONG_FOR_PARA,       /* 1: looking for first strong char in para */
     453             :          SEEKING_STRONG_FOR_FSI,        /* 2: looking for first strong after FSI */
     454             :          LOOKING_FOR_PDI                /* 3: found strong after FSI, looking for PDI */
     455             :     };
     456             :     State state;
     457           0 :     DirProp lastStrong=ON;              /* for default level & inverse BiDi */
     458             :     /* The following stacks are used to manage isolate sequences. Those
     459             :        sequences may be nested, but obviously never more deeply than the
     460             :        maximum explicit embedding level.
     461             :        lastStack is the index of the last used entry in the stack. A value of -1
     462             :        means that there is no open isolate sequence.
     463             :        lastStack is reset to -1 on paragraph boundaries. */
     464             :     /* The following stack contains the position of the initiator of
     465             :        each open isolate sequence */
     466             :     int32_t isolateStartStack[UBIDI_MAX_EXPLICIT_LEVEL+1];
     467             :     /* The following stack contains the last known state before
     468             :        encountering the initiator of an isolate sequence */
     469             :     State  previousStateStack[UBIDI_MAX_EXPLICIT_LEVEL+1];
     470           0 :     int32_t stackLast=-1;
     471             : 
     472           0 :     if(pBiDi->reorderingOptions & UBIDI_OPTION_STREAMING)
     473           0 :         pBiDi->length=0;
     474           0 :     defaultParaLevel=pBiDi->paraLevel&1;
     475           0 :     if(isDefaultLevel) {
     476           0 :         pBiDi->paras[0].level=defaultParaLevel;
     477           0 :         lastStrong=defaultParaLevel;
     478           0 :         if(pBiDi->proLength>0 &&                    /* there is a prologue */
     479             :            (dirProp=firstL_R_AL(pBiDi))!=ON) {  /* with a strong character */
     480           0 :             if(dirProp==L)
     481           0 :                 pBiDi->paras[0].level=0;    /* set the default para level */
     482             :             else
     483           0 :                 pBiDi->paras[0].level=1;    /* set the default para level */
     484           0 :             state=NOT_SEEKING_STRONG;
     485             :         } else {
     486           0 :             state=SEEKING_STRONG_FOR_PARA;
     487             :         }
     488             :     } else {
     489           0 :         pBiDi->paras[0].level=pBiDi->paraLevel;
     490           0 :         state=NOT_SEEKING_STRONG;
     491             :     }
     492             :     /* count paragraphs and determine the paragraph level (P2..P3) */
     493             :     /*
     494             :      * see comment in ubidi.h:
     495             :      * the UBIDI_DEFAULT_XXX values are designed so that
     496             :      * their bit 0 alone yields the intended default
     497             :      */
     498           0 :     for( /* i=0 above */ ; i<originalLength; ) {
     499             :         /* i is incremented by U16_NEXT */
     500           0 :         U16_NEXT(text, i, originalLength, uchar);
     501           0 :         flags|=DIRPROP_FLAG(dirProp=(DirProp)ubidi_getCustomizedClass(pBiDi, uchar));
     502           0 :         dirProps[i-1]=dirProp;
     503           0 :         if(uchar>0xffff) {  /* set the lead surrogate's property to BN */
     504           0 :             flags|=DIRPROP_FLAG(BN);
     505           0 :             dirProps[i-2]=BN;
     506             :         }
     507           0 :         if(removeBiDiControls && IS_BIDI_CONTROL_CHAR(uchar))
     508           0 :             controlCount++;
     509           0 :         if(dirProp==L) {
     510           0 :             if(state==SEEKING_STRONG_FOR_PARA) {
     511           0 :                 pBiDi->paras[pBiDi->paraCount-1].level=0;
     512           0 :                 state=NOT_SEEKING_STRONG;
     513             :             }
     514           0 :             else if(state==SEEKING_STRONG_FOR_FSI) {
     515           0 :                 if(stackLast<=UBIDI_MAX_EXPLICIT_LEVEL) {
     516             :                     /* no need for next statement, already set by default */
     517             :                     /* dirProps[isolateStartStack[stackLast]]=LRI; */
     518           0 :                     flags|=DIRPROP_FLAG(LRI);
     519             :                 }
     520           0 :                 state=LOOKING_FOR_PDI;
     521             :             }
     522           0 :             lastStrong=L;
     523           0 :             continue;
     524             :         }
     525           0 :         if(dirProp==R || dirProp==AL) {
     526           0 :             if(state==SEEKING_STRONG_FOR_PARA) {
     527           0 :                 pBiDi->paras[pBiDi->paraCount-1].level=1;
     528           0 :                 state=NOT_SEEKING_STRONG;
     529             :             }
     530           0 :             else if(state==SEEKING_STRONG_FOR_FSI) {
     531           0 :                 if(stackLast<=UBIDI_MAX_EXPLICIT_LEVEL) {
     532           0 :                     dirProps[isolateStartStack[stackLast]]=RLI;
     533           0 :                     flags|=DIRPROP_FLAG(RLI);
     534             :                 }
     535           0 :                 state=LOOKING_FOR_PDI;
     536             :             }
     537           0 :             lastStrong=R;
     538           0 :             if(dirProp==AL)
     539           0 :                 lastArabicPos=i-1;
     540           0 :             continue;
     541             :         }
     542           0 :         if(dirProp>=FSI && dirProp<=RLI) {  /* FSI, LRI or RLI */
     543           0 :             stackLast++;
     544           0 :             if(stackLast<=UBIDI_MAX_EXPLICIT_LEVEL) {
     545           0 :                 isolateStartStack[stackLast]=i-1;
     546           0 :                 previousStateStack[stackLast]=state;
     547             :             }
     548           0 :             if(dirProp==FSI) {
     549           0 :                 dirProps[i-1]=LRI;      /* default if no strong char */
     550           0 :                 state=SEEKING_STRONG_FOR_FSI;
     551             :             }
     552             :             else
     553           0 :                 state=LOOKING_FOR_PDI;
     554           0 :             continue;
     555             :         }
     556           0 :         if(dirProp==PDI) {
     557           0 :             if(state==SEEKING_STRONG_FOR_FSI) {
     558           0 :                 if(stackLast<=UBIDI_MAX_EXPLICIT_LEVEL) {
     559             :                     /* no need for next statement, already set by default */
     560             :                     /* dirProps[isolateStartStack[stackLast]]=LRI; */
     561           0 :                     flags|=DIRPROP_FLAG(LRI);
     562             :                 }
     563             :             }
     564           0 :             if(stackLast>=0) {
     565           0 :                 if(stackLast<=UBIDI_MAX_EXPLICIT_LEVEL)
     566           0 :                     state=previousStateStack[stackLast];
     567           0 :                 stackLast--;
     568             :             }
     569           0 :             continue;
     570             :         }
     571           0 :         if(dirProp==B) {
     572           0 :             if(i<originalLength && uchar==CR && text[i]==LF) /* do nothing on the CR */
     573           0 :                 continue;
     574           0 :             pBiDi->paras[pBiDi->paraCount-1].limit=i;
     575           0 :             if(isDefaultLevelInverse && lastStrong==R)
     576           0 :                 pBiDi->paras[pBiDi->paraCount-1].level=1;
     577           0 :             if(pBiDi->reorderingOptions & UBIDI_OPTION_STREAMING) {
     578             :                 /* When streaming, we only process whole paragraphs
     579             :                    thus some updates are only done on paragraph boundaries */
     580           0 :                 pBiDi->length=i;        /* i is index to next character */
     581           0 :                 pBiDi->controlCount=controlCount;
     582             :             }
     583           0 :             if(i<originalLength) {              /* B not last char in text */
     584           0 :                 pBiDi->paraCount++;
     585           0 :                 if(checkParaCount(pBiDi)==FALSE)    /* not enough memory for a new para entry */
     586           0 :                     return FALSE;
     587           0 :                 if(isDefaultLevel) {
     588           0 :                     pBiDi->paras[pBiDi->paraCount-1].level=defaultParaLevel;
     589           0 :                     state=SEEKING_STRONG_FOR_PARA;
     590           0 :                     lastStrong=defaultParaLevel;
     591             :                 } else {
     592           0 :                     pBiDi->paras[pBiDi->paraCount-1].level=pBiDi->paraLevel;
     593           0 :                     state=NOT_SEEKING_STRONG;
     594             :                 }
     595           0 :                 stackLast=-1;
     596             :             }
     597           0 :             continue;
     598             :         }
     599             :     }
     600             :     /* Ignore still open isolate sequences with overflow */
     601           0 :     if(stackLast>UBIDI_MAX_EXPLICIT_LEVEL) {
     602           0 :         stackLast=UBIDI_MAX_EXPLICIT_LEVEL;
     603           0 :         state=SEEKING_STRONG_FOR_FSI;   /* to be on the safe side */
     604             :     }
     605             :     /* Resolve direction of still unresolved open FSI sequences */
     606           0 :     while(stackLast>=0) {
     607           0 :         if(state==SEEKING_STRONG_FOR_FSI) {
     608             :             /* no need for next statement, already set by default */
     609             :             /* dirProps[isolateStartStack[stackLast]]=LRI; */
     610           0 :             flags|=DIRPROP_FLAG(LRI);
     611           0 :             break;
     612             :         }
     613           0 :         state=previousStateStack[stackLast];
     614           0 :         stackLast--;
     615             :     }
     616             :     /* When streaming, ignore text after the last paragraph separator */
     617           0 :     if(pBiDi->reorderingOptions & UBIDI_OPTION_STREAMING) {
     618           0 :         if(pBiDi->length<originalLength)
     619           0 :             pBiDi->paraCount--;
     620             :     } else {
     621           0 :         pBiDi->paras[pBiDi->paraCount-1].limit=originalLength;
     622           0 :         pBiDi->controlCount=controlCount;
     623             :     }
     624             :     /* For inverse bidi, default para direction is RTL if there is
     625             :        a strong R or AL at either end of the paragraph */
     626           0 :     if(isDefaultLevelInverse && lastStrong==R) {
     627           0 :         pBiDi->paras[pBiDi->paraCount-1].level=1;
     628             :     }
     629           0 :     if(isDefaultLevel) {
     630           0 :         pBiDi->paraLevel=pBiDi->paras[0].level;
     631             :     }
     632             :     /* The following is needed to resolve the text direction for default level
     633             :        paragraphs containing no strong character */
     634           0 :     for(i=0; i<pBiDi->paraCount; i++)
     635           0 :         flags|=DIRPROP_FLAG_LR(pBiDi->paras[i].level);
     636             : 
     637           0 :     if(pBiDi->orderParagraphsLTR && (flags&DIRPROP_FLAG(B))) {
     638           0 :         flags|=DIRPROP_FLAG(L);
     639             :     }
     640           0 :     pBiDi->flags=flags;
     641           0 :     pBiDi->lastArabicPos=lastArabicPos;
     642           0 :     return TRUE;
     643             : }
     644             : 
     645             : /* determine the paragraph level at position index */
     646             : U_CFUNC UBiDiLevel
     647           0 : ubidi_getParaLevelAtIndex(const UBiDi *pBiDi, int32_t pindex) {
     648             :     int32_t i;
     649           0 :     for(i=0; i<pBiDi->paraCount; i++)
     650           0 :         if(pindex<pBiDi->paras[i].limit)
     651           0 :             break;
     652           0 :     if(i>=pBiDi->paraCount)
     653           0 :         i=pBiDi->paraCount-1;
     654           0 :     return (UBiDiLevel)(pBiDi->paras[i].level);
     655             : }
     656             : 
     657             : /* Functions for handling paired brackets ----------------------------------- */
     658             : 
     659             : /* In the isoRuns array, the first entry is used for text outside of any
     660             :    isolate sequence.  Higher entries are used for each more deeply nested
     661             :    isolate sequence. isoRunLast is the index of the last used entry.  The
     662             :    openings array is used to note the data of opening brackets not yet
     663             :    matched by a closing bracket, or matched but still susceptible to change
     664             :    level.
     665             :    Each isoRun entry contains the index of the first and
     666             :    one-after-last openings entries for pending opening brackets it
     667             :    contains.  The next openings entry to use is the one-after-last of the
     668             :    most deeply nested isoRun entry.
     669             :    isoRun entries also contain their current embedding level and the last
     670             :    encountered strong character, since these will be needed to resolve
     671             :    the level of paired brackets.  */
     672             : 
     673             : static void
     674           0 : bracketInit(UBiDi *pBiDi, BracketData *bd) {
     675           0 :     bd->pBiDi=pBiDi;
     676           0 :     bd->isoRunLast=0;
     677           0 :     bd->isoRuns[0].start=0;
     678           0 :     bd->isoRuns[0].limit=0;
     679           0 :     bd->isoRuns[0].level=GET_PARALEVEL(pBiDi, 0);
     680           0 :     UBiDiLevel t = GET_PARALEVEL(pBiDi, 0) & 1;
     681           0 :     bd->isoRuns[0].lastStrong = bd->isoRuns[0].lastBase = t;
     682           0 :     bd->isoRuns[0].contextDir = (UBiDiDirection)t;
     683           0 :     bd->isoRuns[0].contextPos=0;
     684           0 :     if(pBiDi->openingsMemory) {
     685           0 :         bd->openings=pBiDi->openingsMemory;
     686           0 :         bd->openingsCount=pBiDi->openingsSize / sizeof(Opening);
     687             :     } else {
     688           0 :         bd->openings=bd->simpleOpenings;
     689           0 :         bd->openingsCount=SIMPLE_OPENINGS_COUNT;
     690             :     }
     691           0 :     bd->isNumbersSpecial=bd->pBiDi->reorderingMode==UBIDI_REORDER_NUMBERS_SPECIAL ||
     692           0 :                          bd->pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL;
     693           0 : }
     694             : 
     695             : /* paragraph boundary */
     696             : static void
     697           0 : bracketProcessB(BracketData *bd, UBiDiLevel level) {
     698           0 :     bd->isoRunLast=0;
     699           0 :     bd->isoRuns[0].limit=0;
     700           0 :     bd->isoRuns[0].level=level;
     701           0 :     bd->isoRuns[0].lastStrong=bd->isoRuns[0].lastBase=level&1;
     702           0 :     bd->isoRuns[0].contextDir=(UBiDiDirection)(level&1);
     703           0 :     bd->isoRuns[0].contextPos=0;
     704           0 : }
     705             : 
     706             : /* LRE, LRO, RLE, RLO, PDF */
     707             : static void
     708           0 : bracketProcessBoundary(BracketData *bd, int32_t lastCcPos,
     709             :                        UBiDiLevel contextLevel, UBiDiLevel embeddingLevel) {
     710           0 :     IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
     711           0 :     DirProp *dirProps=bd->pBiDi->dirProps;
     712           0 :     if(DIRPROP_FLAG(dirProps[lastCcPos])&MASK_ISO)  /* after an isolate */
     713           0 :         return;
     714           0 :     if(NO_OVERRIDE(embeddingLevel)>NO_OVERRIDE(contextLevel))   /* not a PDF */
     715           0 :         contextLevel=embeddingLevel;
     716           0 :     pLastIsoRun->limit=pLastIsoRun->start;
     717           0 :     pLastIsoRun->level=embeddingLevel;
     718           0 :     pLastIsoRun->lastStrong=pLastIsoRun->lastBase=contextLevel&1;
     719           0 :     pLastIsoRun->contextDir=(UBiDiDirection)(contextLevel&1);
     720           0 :     pLastIsoRun->contextPos=(UBiDiDirection)lastCcPos;
     721             : }
     722             : 
     723             : /* LRI or RLI */
     724             : static void
     725           0 : bracketProcessLRI_RLI(BracketData *bd, UBiDiLevel level) {
     726           0 :     IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
     727             :     int16_t lastLimit;
     728           0 :     pLastIsoRun->lastBase=ON;
     729           0 :     lastLimit=pLastIsoRun->limit;
     730           0 :     bd->isoRunLast++;
     731           0 :     pLastIsoRun++;
     732           0 :     pLastIsoRun->start=pLastIsoRun->limit=lastLimit;
     733           0 :     pLastIsoRun->level=level;
     734           0 :     pLastIsoRun->lastStrong=pLastIsoRun->lastBase=level&1;
     735           0 :     pLastIsoRun->contextDir=(UBiDiDirection)(level&1);
     736           0 :     pLastIsoRun->contextPos=0;
     737           0 : }
     738             : 
     739             : /* PDI */
     740             : static void
     741           0 : bracketProcessPDI(BracketData *bd) {
     742             :     IsoRun *pLastIsoRun;
     743           0 :     bd->isoRunLast--;
     744           0 :     pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
     745           0 :     pLastIsoRun->lastBase=ON;
     746           0 : }
     747             : 
     748             : /* newly found opening bracket: create an openings entry */
     749             : static UBool                            /* return TRUE if success */
     750           0 : bracketAddOpening(BracketData *bd, UChar match, int32_t position) {
     751           0 :     IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
     752             :     Opening *pOpening;
     753           0 :     if(pLastIsoRun->limit>=bd->openingsCount) {  /* no available new entry */
     754           0 :         UBiDi *pBiDi=bd->pBiDi;
     755           0 :         if(!getInitialOpeningsMemory(pBiDi, pLastIsoRun->limit * 2))
     756           0 :             return FALSE;
     757           0 :         if(bd->openings==bd->simpleOpenings)
     758           0 :             uprv_memcpy(pBiDi->openingsMemory, bd->simpleOpenings,
     759           0 :                         SIMPLE_OPENINGS_COUNT * sizeof(Opening));
     760           0 :         bd->openings=pBiDi->openingsMemory;     /* may have changed */
     761           0 :         bd->openingsCount=pBiDi->openingsSize / sizeof(Opening);
     762             :     }
     763           0 :     pOpening=&bd->openings[pLastIsoRun->limit];
     764           0 :     pOpening->position=position;
     765           0 :     pOpening->match=match;
     766           0 :     pOpening->contextDir=pLastIsoRun->contextDir;
     767           0 :     pOpening->contextPos=pLastIsoRun->contextPos;
     768           0 :     pOpening->flags=0;
     769           0 :     pLastIsoRun->limit++;
     770           0 :     return TRUE;
     771             : }
     772             : 
     773             : /* change N0c1 to N0c2 when a preceding bracket is assigned the embedding level */
     774             : static void
     775           0 : fixN0c(BracketData *bd, int32_t openingIndex, int32_t newPropPosition, DirProp newProp) {
     776             :     /* This function calls itself recursively */
     777           0 :     IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
     778             :     Opening *qOpening;
     779           0 :     DirProp *dirProps=bd->pBiDi->dirProps;
     780             :     int32_t k, openingPosition, closingPosition;
     781           0 :     for(k=openingIndex+1, qOpening=&bd->openings[k]; k<pLastIsoRun->limit; k++, qOpening++) {
     782           0 :         if(qOpening->match>=0)      /* not an N0c match */
     783           0 :             continue;
     784           0 :         if(newPropPosition<qOpening->contextPos)
     785           0 :             break;
     786           0 :         if(newPropPosition>=qOpening->position)
     787           0 :             continue;
     788           0 :         if(newProp==qOpening->contextDir)
     789           0 :             break;
     790           0 :         openingPosition=qOpening->position;
     791           0 :         dirProps[openingPosition]=newProp;
     792           0 :         closingPosition=-(qOpening->match);
     793           0 :         dirProps[closingPosition]=newProp;
     794           0 :         qOpening->match=0;                      /* prevent further changes */
     795           0 :         fixN0c(bd, k, openingPosition, newProp);
     796           0 :         fixN0c(bd, k, closingPosition, newProp);
     797             :     }
     798           0 : }
     799             : 
     800             : /* process closing bracket */
     801             : static DirProp              /* return L or R if N0b or N0c, ON if N0d */
     802           0 : bracketProcessClosing(BracketData *bd, int32_t openIdx, int32_t position) {
     803           0 :     IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
     804             :     Opening *pOpening, *qOpening;
     805             :     UBiDiDirection direction;
     806             :     UBool stable;
     807             :     DirProp newProp;
     808           0 :     pOpening=&bd->openings[openIdx];
     809           0 :     direction=(UBiDiDirection)(pLastIsoRun->level&1);
     810           0 :     stable=TRUE;            /* assume stable until proved otherwise */
     811             : 
     812             :     /* The stable flag is set when brackets are paired and their
     813             :        level is resolved and cannot be changed by what will be
     814             :        found later in the source string.
     815             :        An unstable match can occur only when applying N0c, where
     816             :        the resolved level depends on the preceding context, and
     817             :        this context may be affected by text occurring later.
     818             :        Example: RTL paragraph containing:  abc[(latin) HEBREW]
     819             :        When the closing parenthesis is encountered, it appears
     820             :        that N0c1 must be applied since 'abc' sets an opposite
     821             :        direction context and both parentheses receive level 2.
     822             :        However, when the closing square bracket is processed,
     823             :        N0b applies because of 'HEBREW' being included within the
     824             :        brackets, thus the square brackets are treated like R and
     825             :        receive level 1. However, this changes the preceding
     826             :        context of the opening parenthesis, and it now appears
     827             :        that N0c2 must be applied to the parentheses rather than
     828             :        N0c1. */
     829             : 
     830           0 :     if((direction==0 && pOpening->flags&FOUND_L) ||
     831           0 :        (direction==1 && pOpening->flags&FOUND_R)) { /* N0b */
     832           0 :         newProp=direction;
     833             :     }
     834           0 :     else if(pOpening->flags&(FOUND_L|FOUND_R)) {    /* N0c */
     835             :         /* it is stable if there is no containing pair or in
     836             :            conditions too complicated and not worth checking */
     837           0 :         stable=(openIdx==pLastIsoRun->start);
     838           0 :         if(direction!=pOpening->contextDir)
     839           0 :             newProp=pOpening->contextDir;           /* N0c1 */
     840             :         else
     841           0 :             newProp=direction;                      /* N0c2 */
     842             :     } else {
     843             :         /* forget this and any brackets nested within this pair */
     844           0 :         pLastIsoRun->limit=openIdx;
     845           0 :         return ON;                                  /* N0d */
     846             :     }
     847           0 :     bd->pBiDi->dirProps[pOpening->position]=newProp;
     848           0 :     bd->pBiDi->dirProps[position]=newProp;
     849             :     /* Update nested N0c pairs that may be affected */
     850           0 :     fixN0c(bd, openIdx, pOpening->position, newProp);
     851           0 :     if(stable) {
     852           0 :         pLastIsoRun->limit=openIdx; /* forget any brackets nested within this pair */
     853             :         /* remove lower located synonyms if any */
     854           0 :         while(pLastIsoRun->limit>pLastIsoRun->start &&
     855           0 :               bd->openings[pLastIsoRun->limit-1].position==pOpening->position)
     856           0 :             pLastIsoRun->limit--;
     857             :     } else {
     858             :         int32_t k;
     859           0 :         pOpening->match=-position;
     860             :         /* neutralize lower located synonyms if any */
     861           0 :         k=openIdx-1;
     862           0 :         while(k>=pLastIsoRun->start &&
     863           0 :               bd->openings[k].position==pOpening->position)
     864           0 :             bd->openings[k--].match=0;
     865             :         /* neutralize any unmatched opening between the current pair;
     866             :            this will also neutralize higher located synonyms if any */
     867           0 :         for(k=openIdx+1; k<pLastIsoRun->limit; k++) {
     868           0 :             qOpening=&bd->openings[k];
     869           0 :             if(qOpening->position>=position)
     870           0 :                 break;
     871           0 :             if(qOpening->match>0)
     872           0 :                 qOpening->match=0;
     873             :         }
     874             :     }
     875           0 :     return newProp;
     876             : }
     877             : 
     878             : /* handle strong characters, digits and candidates for closing brackets */
     879             : static UBool                            /* return TRUE if success */
     880           0 : bracketProcessChar(BracketData *bd, int32_t position) {
     881           0 :     IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
     882             :     DirProp *dirProps, dirProp, newProp;
     883             :     UBiDiLevel level;
     884           0 :     dirProps=bd->pBiDi->dirProps;
     885           0 :     dirProp=dirProps[position];
     886           0 :     if(dirProp==ON) {
     887             :         UChar c, match;
     888             :         int32_t idx;
     889             :         /* First see if it is a matching closing bracket. Hopefully, this is
     890             :            more efficient than checking if it is a closing bracket at all */
     891           0 :         c=bd->pBiDi->text[position];
     892           0 :         for(idx=pLastIsoRun->limit-1; idx>=pLastIsoRun->start; idx--) {
     893           0 :             if(bd->openings[idx].match!=c)
     894           0 :                 continue;
     895             :             /* We have a match */
     896           0 :             newProp=bracketProcessClosing(bd, idx, position);
     897           0 :             if(newProp==ON) {           /* N0d */
     898           0 :                 c=0;        /* prevent handling as an opening */
     899           0 :                 break;
     900             :             }
     901           0 :             pLastIsoRun->lastBase=ON;
     902           0 :             pLastIsoRun->contextDir=(UBiDiDirection)newProp;
     903           0 :             pLastIsoRun->contextPos=position;
     904           0 :             level=bd->pBiDi->levels[position];
     905           0 :             if(level&UBIDI_LEVEL_OVERRIDE) {    /* X4, X5 */
     906             :                 uint16_t flag;
     907             :                 int32_t i;
     908           0 :                 newProp=level&1;
     909           0 :                 pLastIsoRun->lastStrong=newProp;
     910           0 :                 flag=DIRPROP_FLAG(newProp);
     911           0 :                 for(i=pLastIsoRun->start; i<idx; i++)
     912           0 :                     bd->openings[i].flags|=flag;
     913             :                 /* matching brackets are not overridden by LRO/RLO */
     914           0 :                 bd->pBiDi->levels[position]&=~UBIDI_LEVEL_OVERRIDE;
     915             :             }
     916             :             /* matching brackets are not overridden by LRO/RLO */
     917           0 :             bd->pBiDi->levels[bd->openings[idx].position]&=~UBIDI_LEVEL_OVERRIDE;
     918           0 :             return TRUE;
     919             :         }
     920             :         /* We get here only if the ON character is not a matching closing
     921             :            bracket or it is a case of N0d */
     922             :         /* Now see if it is an opening bracket */
     923           0 :         if(c)
     924           0 :             match=u_getBidiPairedBracket(c);    /* get the matching char */
     925             :         else
     926           0 :             match=0;
     927           0 :         if(match!=c &&                  /* has a matching char */
     928           0 :            ubidi_getPairedBracketType(bd->pBiDi->bdp, c)==U_BPT_OPEN) { /* opening bracket */
     929             :             /* special case: process synonyms
     930             :                create an opening entry for each synonym */
     931           0 :             if(match==0x232A) {     /* RIGHT-POINTING ANGLE BRACKET */
     932           0 :                 if(!bracketAddOpening(bd, 0x3009, position))
     933           0 :                     return FALSE;
     934             :             }
     935           0 :             else if(match==0x3009) {         /* RIGHT ANGLE BRACKET */
     936           0 :                 if(!bracketAddOpening(bd, 0x232A, position))
     937           0 :                     return FALSE;
     938             :             }
     939           0 :             if(!bracketAddOpening(bd, match, position))
     940           0 :                 return FALSE;
     941             :         }
     942             :     }
     943           0 :     level=bd->pBiDi->levels[position];
     944           0 :     if(level&UBIDI_LEVEL_OVERRIDE) {    /* X4, X5 */
     945           0 :         newProp=level&1;
     946           0 :         if(dirProp!=S && dirProp!=WS && dirProp!=ON)
     947           0 :             dirProps[position]=newProp;
     948           0 :         pLastIsoRun->lastBase=newProp;
     949           0 :         pLastIsoRun->lastStrong=newProp;
     950           0 :         pLastIsoRun->contextDir=(UBiDiDirection)newProp;
     951           0 :         pLastIsoRun->contextPos=position;
     952             :     }
     953           0 :     else if(dirProp<=R || dirProp==AL) {
     954           0 :         newProp=DIR_FROM_STRONG(dirProp);
     955           0 :         pLastIsoRun->lastBase=dirProp;
     956           0 :         pLastIsoRun->lastStrong=dirProp;
     957           0 :         pLastIsoRun->contextDir=(UBiDiDirection)newProp;
     958           0 :         pLastIsoRun->contextPos=position;
     959             :     }
     960           0 :     else if(dirProp==EN) {
     961           0 :         pLastIsoRun->lastBase=EN;
     962           0 :         if(pLastIsoRun->lastStrong==L) {
     963           0 :             newProp=L;                  /* W7 */
     964           0 :             if(!bd->isNumbersSpecial)
     965           0 :                 dirProps[position]=ENL;
     966           0 :             pLastIsoRun->contextDir=(UBiDiDirection)L;
     967           0 :             pLastIsoRun->contextPos=position;
     968             :         }
     969             :         else {
     970           0 :             newProp=R;                  /* N0 */
     971           0 :             if(pLastIsoRun->lastStrong==AL)
     972           0 :                 dirProps[position]=AN;  /* W2 */
     973             :             else
     974           0 :                 dirProps[position]=ENR;
     975           0 :             pLastIsoRun->contextDir=(UBiDiDirection)R;
     976           0 :             pLastIsoRun->contextPos=position;
     977             :         }
     978             :     }
     979           0 :     else if(dirProp==AN) {
     980           0 :         newProp=R;                      /* N0 */
     981           0 :         pLastIsoRun->lastBase=AN;
     982           0 :         pLastIsoRun->contextDir=(UBiDiDirection)R;
     983           0 :         pLastIsoRun->contextPos=position;
     984             :     }
     985           0 :     else if(dirProp==NSM) {
     986             :         /* if the last real char was ON, change NSM to ON so that it
     987             :            will stay ON even if the last real char is a bracket which
     988             :            may be changed to L or R */
     989           0 :         newProp=pLastIsoRun->lastBase;
     990           0 :         if(newProp==ON)
     991           0 :             dirProps[position]=newProp;
     992             :     }
     993             :     else {
     994           0 :         newProp=dirProp;
     995           0 :         pLastIsoRun->lastBase=dirProp;
     996             :     }
     997           0 :     if(newProp<=R || newProp==AL) {
     998             :         int32_t i;
     999           0 :         uint16_t flag=DIRPROP_FLAG(DIR_FROM_STRONG(newProp));
    1000           0 :         for(i=pLastIsoRun->start; i<pLastIsoRun->limit; i++)
    1001           0 :             if(position>bd->openings[i].position)
    1002           0 :                 bd->openings[i].flags|=flag;
    1003             :     }
    1004           0 :     return TRUE;
    1005             : }
    1006             : 
    1007             : /* perform (X1)..(X9) ------------------------------------------------------- */
    1008             : 
    1009             : /* determine if the text is mixed-directional or single-directional */
    1010             : static UBiDiDirection
    1011           0 : directionFromFlags(UBiDi *pBiDi) {
    1012           0 :     Flags flags=pBiDi->flags;
    1013             :     /* if the text contains AN and neutrals, then some neutrals may become RTL */
    1014           0 :     if(!(flags&MASK_RTL || ((flags&DIRPROP_FLAG(AN)) && (flags&MASK_POSSIBLE_N)))) {
    1015           0 :         return UBIDI_LTR;
    1016           0 :     } else if(!(flags&MASK_LTR)) {
    1017           0 :         return UBIDI_RTL;
    1018             :     } else {
    1019           0 :         return UBIDI_MIXED;
    1020             :     }
    1021             : }
    1022             : 
    1023             : /*
    1024             :  * Resolve the explicit levels as specified by explicit embedding codes.
    1025             :  * Recalculate the flags to have them reflect the real properties
    1026             :  * after taking the explicit embeddings into account.
    1027             :  *
    1028             :  * The BiDi algorithm is designed to result in the same behavior whether embedding
    1029             :  * levels are externally specified (from "styled text", supposedly the preferred
    1030             :  * method) or set by explicit embedding codes (LRx, RLx, PDF, FSI, PDI) in the plain text.
    1031             :  * That is why (X9) instructs to remove all not-isolate explicit codes (and BN).
    1032             :  * However, in a real implementation, the removal of these codes and their index
    1033             :  * positions in the plain text is undesirable since it would result in
    1034             :  * reallocated, reindexed text.
    1035             :  * Instead, this implementation leaves the codes in there and just ignores them
    1036             :  * in the subsequent processing.
    1037             :  * In order to get the same reordering behavior, positions with a BN or a not-isolate
    1038             :  * explicit embedding code just get the same level assigned as the last "real"
    1039             :  * character.
    1040             :  *
    1041             :  * Some implementations, not this one, then overwrite some of these
    1042             :  * directionality properties at "real" same-level-run boundaries by
    1043             :  * L or R codes so that the resolution of weak types can be performed on the
    1044             :  * entire paragraph at once instead of having to parse it once more and
    1045             :  * perform that resolution on same-level-runs.
    1046             :  * This limits the scope of the implicit rules in effectively
    1047             :  * the same way as the run limits.
    1048             :  *
    1049             :  * Instead, this implementation does not modify these codes, except for
    1050             :  * paired brackets whose properties (ON) may be replaced by L or R.
    1051             :  * On one hand, the paragraph has to be scanned for same-level-runs, but
    1052             :  * on the other hand, this saves another loop to reset these codes,
    1053             :  * or saves making and modifying a copy of dirProps[].
    1054             :  *
    1055             :  *
    1056             :  * Note that (Pn) and (Xn) changed significantly from version 4 of the BiDi algorithm.
    1057             :  *
    1058             :  *
    1059             :  * Handling the stack of explicit levels (Xn):
    1060             :  *
    1061             :  * With the BiDi stack of explicit levels, as pushed with each
    1062             :  * LRE, RLE, LRO, RLO, LRI, RLI and FSI and popped with each PDF and PDI,
    1063             :  * the explicit level must never exceed UBIDI_MAX_EXPLICIT_LEVEL.
    1064             :  *
    1065             :  * In order to have a correct push-pop semantics even in the case of overflows,
    1066             :  * overflow counters and a valid isolate counter are used as described in UAX#9
    1067             :  * section 3.3.2 "Explicit Levels and Directions".
    1068             :  *
    1069             :  * This implementation assumes that UBIDI_MAX_EXPLICIT_LEVEL is odd.
    1070             :  *
    1071             :  * Returns normally the direction; -1 if there was a memory shortage
    1072             :  *
    1073             :  */
    1074             : static UBiDiDirection
    1075           0 : resolveExplicitLevels(UBiDi *pBiDi, UErrorCode *pErrorCode) {
    1076           0 :     DirProp *dirProps=pBiDi->dirProps;
    1077           0 :     UBiDiLevel *levels=pBiDi->levels;
    1078           0 :     const UChar *text=pBiDi->text;
    1079             : 
    1080           0 :     int32_t i=0, length=pBiDi->length;
    1081           0 :     Flags flags=pBiDi->flags;       /* collect all directionalities in the text */
    1082             :     DirProp dirProp;
    1083           0 :     UBiDiLevel level=GET_PARALEVEL(pBiDi, 0);
    1084             :     UBiDiDirection direction;
    1085           0 :     pBiDi->isolateCount=0;
    1086             : 
    1087           0 :     if(U_FAILURE(*pErrorCode)) { return UBIDI_LTR; }
    1088             : 
    1089             :     /* determine if the text is mixed-directional or single-directional */
    1090           0 :     direction=directionFromFlags(pBiDi);
    1091             : 
    1092             :     /* we may not need to resolve any explicit levels */
    1093           0 :     if((direction!=UBIDI_MIXED)) {
    1094             :         /* not mixed directionality: levels don't matter - trailingWSStart will be 0 */
    1095           0 :         return direction;
    1096             :     }
    1097           0 :     if(pBiDi->reorderingMode > UBIDI_REORDER_LAST_LOGICAL_TO_VISUAL) {
    1098             :         /* inverse BiDi: mixed, but all characters are at the same embedding level */
    1099             :         /* set all levels to the paragraph level */
    1100             :         int32_t paraIndex, start, limit;
    1101           0 :         for(paraIndex=0; paraIndex<pBiDi->paraCount; paraIndex++) {
    1102           0 :             if(paraIndex==0)
    1103           0 :                 start=0;
    1104             :             else
    1105           0 :                 start=pBiDi->paras[paraIndex-1].limit;
    1106           0 :             limit=pBiDi->paras[paraIndex].limit;
    1107           0 :             level=pBiDi->paras[paraIndex].level;
    1108           0 :             for(i=start; i<limit; i++)
    1109           0 :                 levels[i]=level;
    1110             :         }
    1111           0 :         return direction;   /* no bracket matching for inverse BiDi */
    1112             :     }
    1113           0 :     if(!(flags&(MASK_EXPLICIT|MASK_ISO))) {
    1114             :         /* no embeddings, set all levels to the paragraph level */
    1115             :         /* we still have to perform bracket matching */
    1116             :         int32_t paraIndex, start, limit;
    1117             :         BracketData bracketData;
    1118           0 :         bracketInit(pBiDi, &bracketData);
    1119           0 :         for(paraIndex=0; paraIndex<pBiDi->paraCount; paraIndex++) {
    1120           0 :             if(paraIndex==0)
    1121           0 :                 start=0;
    1122             :             else
    1123           0 :                 start=pBiDi->paras[paraIndex-1].limit;
    1124           0 :             limit=pBiDi->paras[paraIndex].limit;
    1125           0 :             level=pBiDi->paras[paraIndex].level;
    1126           0 :             for(i=start; i<limit; i++) {
    1127           0 :                 levels[i]=level;
    1128           0 :                 dirProp=dirProps[i];
    1129           0 :                 if(dirProp==BN)
    1130           0 :                     continue;
    1131           0 :                 if(dirProp==B) {
    1132           0 :                     if((i+1)<length) {
    1133           0 :                         if(text[i]==CR && text[i+1]==LF)
    1134           0 :                             continue;   /* skip CR when followed by LF */
    1135           0 :                         bracketProcessB(&bracketData, level);
    1136             :                     }
    1137           0 :                     continue;
    1138             :                 }
    1139           0 :                 if(!bracketProcessChar(&bracketData, i)) {
    1140           0 :                     *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
    1141           0 :                     return UBIDI_LTR;
    1142             :                 }
    1143             :             }
    1144             :         }
    1145           0 :         return direction;
    1146             :     }
    1147             :     {
    1148             :         /* continue to perform (Xn) */
    1149             : 
    1150             :         /* (X1) level is set for all codes, embeddingLevel keeps track of the push/pop operations */
    1151             :         /* both variables may carry the UBIDI_LEVEL_OVERRIDE flag to indicate the override status */
    1152           0 :         UBiDiLevel embeddingLevel=level, newLevel;
    1153           0 :         UBiDiLevel previousLevel=level;     /* previous level for regular (not CC) characters */
    1154           0 :         int32_t lastCcPos=0;                /* index of last effective LRx,RLx, PDx */
    1155             : 
    1156             :         /* The following stack remembers the embedding level and the ISOLATE flag of level runs.
    1157             :            stackLast points to its current entry. */
    1158             :         uint16_t stack[UBIDI_MAX_EXPLICIT_LEVEL+2];   /* we never push anything >=UBIDI_MAX_EXPLICIT_LEVEL
    1159             :                                                         but we need one more entry as base */
    1160           0 :         uint32_t stackLast=0;
    1161           0 :         int32_t overflowIsolateCount=0;
    1162           0 :         int32_t overflowEmbeddingCount=0;
    1163           0 :         int32_t validIsolateCount=0;
    1164             :         BracketData bracketData;
    1165           0 :         bracketInit(pBiDi, &bracketData);
    1166           0 :         stack[0]=level;     /* initialize base entry to para level, no override, no isolate */
    1167             : 
    1168             :         /* recalculate the flags */
    1169           0 :         flags=0;
    1170             : 
    1171           0 :         for(i=0; i<length; ++i) {
    1172           0 :             dirProp=dirProps[i];
    1173           0 :             switch(dirProp) {
    1174             :             case LRE:
    1175             :             case RLE:
    1176             :             case LRO:
    1177             :             case RLO:
    1178             :                 /* (X2, X3, X4, X5) */
    1179           0 :                 flags|=DIRPROP_FLAG(BN);
    1180           0 :                 levels[i]=previousLevel;
    1181           0 :                 if (dirProp==LRE || dirProp==LRO)
    1182             :                     /* least greater even level */
    1183           0 :                     newLevel=(UBiDiLevel)((embeddingLevel+2)&~(UBIDI_LEVEL_OVERRIDE|1));
    1184             :                 else
    1185             :                     /* least greater odd level */
    1186           0 :                     newLevel=(UBiDiLevel)((NO_OVERRIDE(embeddingLevel)+1)|1);
    1187           0 :                 if(newLevel<=UBIDI_MAX_EXPLICIT_LEVEL && overflowIsolateCount==0 &&
    1188             :                                                          overflowEmbeddingCount==0) {
    1189           0 :                     lastCcPos=i;
    1190           0 :                     embeddingLevel=newLevel;
    1191           0 :                     if(dirProp==LRO || dirProp==RLO)
    1192           0 :                         embeddingLevel|=UBIDI_LEVEL_OVERRIDE;
    1193           0 :                     stackLast++;
    1194           0 :                     stack[stackLast]=embeddingLevel;
    1195             :                     /* we don't need to set UBIDI_LEVEL_OVERRIDE off for LRE and RLE
    1196             :                        since this has already been done for newLevel which is
    1197             :                        the source for embeddingLevel.
    1198             :                      */
    1199             :                 } else {
    1200           0 :                     if(overflowIsolateCount==0)
    1201           0 :                         overflowEmbeddingCount++;
    1202             :                 }
    1203           0 :                 break;
    1204             :             case PDF:
    1205             :                 /* (X7) */
    1206           0 :                 flags|=DIRPROP_FLAG(BN);
    1207           0 :                 levels[i]=previousLevel;
    1208             :                 /* handle all the overflow cases first */
    1209           0 :                 if(overflowIsolateCount) {
    1210           0 :                     break;
    1211             :                 }
    1212           0 :                 if(overflowEmbeddingCount) {
    1213           0 :                     overflowEmbeddingCount--;
    1214           0 :                     break;
    1215             :                 }
    1216           0 :                 if(stackLast>0 && stack[stackLast]<ISOLATE) {   /* not an isolate entry */
    1217           0 :                     lastCcPos=i;
    1218           0 :                     stackLast--;
    1219           0 :                     embeddingLevel=(UBiDiLevel)stack[stackLast];
    1220             :                 }
    1221           0 :                 break;
    1222             :             case LRI:
    1223             :             case RLI:
    1224           0 :                 flags|=(DIRPROP_FLAG(ON)|DIRPROP_FLAG_LR(embeddingLevel));
    1225           0 :                 levels[i]=NO_OVERRIDE(embeddingLevel);
    1226           0 :                 if(NO_OVERRIDE(embeddingLevel)!=NO_OVERRIDE(previousLevel)) {
    1227           0 :                     bracketProcessBoundary(&bracketData, lastCcPos,
    1228           0 :                                            previousLevel, embeddingLevel);
    1229           0 :                     flags|=DIRPROP_FLAG_MULTI_RUNS;
    1230             :                 }
    1231           0 :                 previousLevel=embeddingLevel;
    1232             :                 /* (X5a, X5b) */
    1233           0 :                 if(dirProp==LRI)
    1234             :                     /* least greater even level */
    1235           0 :                     newLevel=(UBiDiLevel)((embeddingLevel+2)&~(UBIDI_LEVEL_OVERRIDE|1));
    1236             :                 else
    1237             :                     /* least greater odd level */
    1238           0 :                     newLevel=(UBiDiLevel)((NO_OVERRIDE(embeddingLevel)+1)|1);
    1239           0 :                 if(newLevel<=UBIDI_MAX_EXPLICIT_LEVEL && overflowIsolateCount==0 &&
    1240             :                                                          overflowEmbeddingCount==0) {
    1241           0 :                     flags|=DIRPROP_FLAG(dirProp);
    1242           0 :                     lastCcPos=i;
    1243           0 :                     validIsolateCount++;
    1244           0 :                     if(validIsolateCount>pBiDi->isolateCount)
    1245           0 :                         pBiDi->isolateCount=validIsolateCount;
    1246           0 :                     embeddingLevel=newLevel;
    1247             :                     /* we can increment stackLast without checking because newLevel
    1248             :                        will exceed UBIDI_MAX_EXPLICIT_LEVEL before stackLast overflows */
    1249           0 :                     stackLast++;
    1250           0 :                     stack[stackLast]=embeddingLevel+ISOLATE;
    1251           0 :                     bracketProcessLRI_RLI(&bracketData, embeddingLevel);
    1252             :                 } else {
    1253             :                     /* make it WS so that it is handled by adjustWSLevels() */
    1254           0 :                     dirProps[i]=WS;
    1255           0 :                     overflowIsolateCount++;
    1256             :                 }
    1257           0 :                 break;
    1258             :             case PDI:
    1259           0 :                 if(NO_OVERRIDE(embeddingLevel)!=NO_OVERRIDE(previousLevel)) {
    1260           0 :                     bracketProcessBoundary(&bracketData, lastCcPos,
    1261           0 :                                            previousLevel, embeddingLevel);
    1262           0 :                     flags|=DIRPROP_FLAG_MULTI_RUNS;
    1263             :                 }
    1264             :                 /* (X6a) */
    1265           0 :                 if(overflowIsolateCount) {
    1266           0 :                     overflowIsolateCount--;
    1267             :                     /* make it WS so that it is handled by adjustWSLevels() */
    1268           0 :                     dirProps[i]=WS;
    1269             :                 }
    1270           0 :                 else if(validIsolateCount) {
    1271           0 :                     flags|=DIRPROP_FLAG(PDI);
    1272           0 :                     lastCcPos=i;
    1273           0 :                     overflowEmbeddingCount=0;
    1274           0 :                     while(stack[stackLast]<ISOLATE) /* pop embedding entries */
    1275           0 :                         stackLast--;                /* until the last isolate entry */
    1276           0 :                     stackLast--;                    /* pop also the last isolate entry */
    1277           0 :                     validIsolateCount--;
    1278           0 :                     bracketProcessPDI(&bracketData);
    1279             :                 } else
    1280             :                     /* make it WS so that it is handled by adjustWSLevels() */
    1281           0 :                     dirProps[i]=WS;
    1282           0 :                 embeddingLevel=(UBiDiLevel)stack[stackLast]&~ISOLATE;
    1283           0 :                 flags|=(DIRPROP_FLAG(ON)|DIRPROP_FLAG_LR(embeddingLevel));
    1284           0 :                 previousLevel=embeddingLevel;
    1285           0 :                 levels[i]=NO_OVERRIDE(embeddingLevel);
    1286           0 :                 break;
    1287             :             case B:
    1288           0 :                 flags|=DIRPROP_FLAG(B);
    1289           0 :                 levels[i]=GET_PARALEVEL(pBiDi, i);
    1290           0 :                 if((i+1)<length) {
    1291           0 :                     if(text[i]==CR && text[i+1]==LF)
    1292           0 :                         break;          /* skip CR when followed by LF */
    1293           0 :                     overflowEmbeddingCount=overflowIsolateCount=0;
    1294           0 :                     validIsolateCount=0;
    1295           0 :                     stackLast=0;
    1296           0 :                     previousLevel=embeddingLevel=GET_PARALEVEL(pBiDi, i+1);
    1297           0 :                     stack[0]=embeddingLevel; /* initialize base entry to para level, no override, no isolate */
    1298           0 :                     bracketProcessB(&bracketData, embeddingLevel);
    1299             :                 }
    1300           0 :                 break;
    1301             :             case BN:
    1302             :                 /* BN, LRE, RLE, and PDF are supposed to be removed (X9) */
    1303             :                 /* they will get their levels set correctly in adjustWSLevels() */
    1304           0 :                 levels[i]=previousLevel;
    1305           0 :                 flags|=DIRPROP_FLAG(BN);
    1306           0 :                 break;
    1307             :             default:
    1308             :                 /* all other types are normal characters and get the "real" level */
    1309           0 :                 if(NO_OVERRIDE(embeddingLevel)!=NO_OVERRIDE(previousLevel)) {
    1310           0 :                     bracketProcessBoundary(&bracketData, lastCcPos,
    1311           0 :                                            previousLevel, embeddingLevel);
    1312           0 :                     flags|=DIRPROP_FLAG_MULTI_RUNS;
    1313           0 :                     if(embeddingLevel&UBIDI_LEVEL_OVERRIDE)
    1314           0 :                         flags|=DIRPROP_FLAG_O(embeddingLevel);
    1315             :                     else
    1316           0 :                         flags|=DIRPROP_FLAG_E(embeddingLevel);
    1317             :                 }
    1318           0 :                 previousLevel=embeddingLevel;
    1319           0 :                 levels[i]=embeddingLevel;
    1320           0 :                 if(!bracketProcessChar(&bracketData, i))
    1321           0 :                     return (UBiDiDirection)-1;
    1322             :                 /* the dirProp may have been changed in bracketProcessChar() */
    1323           0 :                 flags|=DIRPROP_FLAG(dirProps[i]);
    1324           0 :                 break;
    1325             :             }
    1326             :         }
    1327           0 :         if(flags&MASK_EMBEDDING)
    1328           0 :             flags|=DIRPROP_FLAG_LR(pBiDi->paraLevel);
    1329           0 :         if(pBiDi->orderParagraphsLTR && (flags&DIRPROP_FLAG(B)))
    1330           0 :             flags|=DIRPROP_FLAG(L);
    1331             :         /* again, determine if the text is mixed-directional or single-directional */
    1332           0 :         pBiDi->flags=flags;
    1333           0 :         direction=directionFromFlags(pBiDi);
    1334             :     }
    1335           0 :     return direction;
    1336             : }
    1337             : 
    1338             : /*
    1339             :  * Use a pre-specified embedding levels array:
    1340             :  *
    1341             :  * Adjust the directional properties for overrides (->LEVEL_OVERRIDE),
    1342             :  * ignore all explicit codes (X9),
    1343             :  * and check all the preset levels.
    1344             :  *
    1345             :  * Recalculate the flags to have them reflect the real properties
    1346             :  * after taking the explicit embeddings into account.
    1347             :  */
    1348             : static UBiDiDirection
    1349           0 : checkExplicitLevels(UBiDi *pBiDi, UErrorCode *pErrorCode) {
    1350           0 :     DirProp *dirProps=pBiDi->dirProps;
    1351           0 :     UBiDiLevel *levels=pBiDi->levels;
    1352           0 :     int32_t isolateCount=0;
    1353             : 
    1354           0 :     int32_t length=pBiDi->length;
    1355           0 :     Flags flags=0;  /* collect all directionalities in the text */
    1356           0 :     pBiDi->isolateCount=0;
    1357             : 
    1358           0 :     int32_t currentParaIndex = 0;
    1359           0 :     int32_t currentParaLimit = pBiDi->paras[0].limit;
    1360           0 :     int32_t currentParaLevel = pBiDi->paraLevel;
    1361             : 
    1362           0 :     for(int32_t i=0; i<length; ++i) {
    1363           0 :         UBiDiLevel level=levels[i];
    1364           0 :         DirProp dirProp=dirProps[i];
    1365           0 :         if(dirProp==LRI || dirProp==RLI) {
    1366           0 :             isolateCount++;
    1367           0 :             if(isolateCount>pBiDi->isolateCount)
    1368           0 :                 pBiDi->isolateCount=isolateCount;
    1369             :         }
    1370           0 :         else if(dirProp==PDI)
    1371           0 :             isolateCount--;
    1372           0 :         else if(dirProp==B)
    1373           0 :             isolateCount=0;
    1374             : 
    1375             :         // optimized version of  int32_t currentParaLevel = GET_PARALEVEL(pBiDi, i);
    1376           0 :         if (pBiDi->defaultParaLevel != 0 &&
    1377           0 :                 i == currentParaLimit && (currentParaIndex + 1) < pBiDi->paraCount) {
    1378           0 :             currentParaLevel = pBiDi->paras[++currentParaIndex].level;
    1379           0 :             currentParaLimit = pBiDi->paras[currentParaIndex].limit;
    1380             :         }
    1381             : 
    1382           0 :         UBiDiLevel overrideFlag = level & UBIDI_LEVEL_OVERRIDE;
    1383           0 :         level &= ~UBIDI_LEVEL_OVERRIDE;
    1384           0 :         if (level < currentParaLevel || UBIDI_MAX_EXPLICIT_LEVEL < level) {
    1385           0 :             if (level == 0) {
    1386           0 :                 if (dirProp == B) {
    1387             :                     // Paragraph separators are ok with explicit level 0.
    1388             :                     // Prevents reordering of paragraphs.
    1389             :                 } else {
    1390             :                     // Treat explicit level 0 as a wildcard for the paragraph level.
    1391             :                     // Avoid making the caller guess what the paragraph level would be.
    1392           0 :                     level = (UBiDiLevel)currentParaLevel;
    1393           0 :                     levels[i] = level | overrideFlag;
    1394             :                 }
    1395             :             } else {
    1396             :                 // 1 <= level < currentParaLevel or UBIDI_MAX_EXPLICIT_LEVEL < level
    1397             :                 /* level out of bounds */
    1398           0 :                 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    1399           0 :                 return UBIDI_LTR;
    1400             :             }
    1401             :         }
    1402           0 :         if (overrideFlag != 0) {
    1403             :             /* keep the override flag in levels[i] but adjust the flags */
    1404           0 :             flags|=DIRPROP_FLAG_O(level);
    1405             :         } else {
    1406             :             /* set the flags */
    1407           0 :             flags|=DIRPROP_FLAG_E(level)|DIRPROP_FLAG(dirProp);
    1408             :         }
    1409             :     }
    1410           0 :     if(flags&MASK_EMBEDDING)
    1411           0 :         flags|=DIRPROP_FLAG_LR(pBiDi->paraLevel);
    1412             :     /* determine if the text is mixed-directional or single-directional */
    1413           0 :     pBiDi->flags=flags;
    1414           0 :     return directionFromFlags(pBiDi);
    1415             : }
    1416             : 
    1417             : /******************************************************************
    1418             :  The Properties state machine table
    1419             : *******************************************************************
    1420             : 
    1421             :  All table cells are 8 bits:
    1422             :       bits 0..4:  next state
    1423             :       bits 5..7:  action to perform (if > 0)
    1424             : 
    1425             :  Cells may be of format "n" where n represents the next state
    1426             :  (except for the rightmost column).
    1427             :  Cells may also be of format "s(x,y)" where x represents an action
    1428             :  to perform and y represents the next state.
    1429             : 
    1430             : *******************************************************************
    1431             :  Definitions and type for properties state table
    1432             : *******************************************************************
    1433             : */
    1434             : #define IMPTABPROPS_COLUMNS 16
    1435             : #define IMPTABPROPS_RES (IMPTABPROPS_COLUMNS - 1)
    1436             : #define GET_STATEPROPS(cell) ((cell)&0x1f)
    1437             : #define GET_ACTIONPROPS(cell) ((cell)>>5)
    1438             : #define s(action, newState) ((uint8_t)(newState+(action<<5)))
    1439             : 
    1440             : static const uint8_t groupProp[] =          /* dirProp regrouped */
    1441             : {
    1442             : /*  L   R   EN  ES  ET  AN  CS  B   S   WS  ON  LRE LRO AL  RLE RLO PDF NSM BN  FSI LRI RLI PDI ENL ENR */
    1443             :     0,  1,  2,  7,  8,  3,  9,  6,  5,  4,  4,  10, 10, 12, 10, 10, 10, 11, 10, 4,  4,  4,  4,  13, 14
    1444             : };
    1445             : enum { DirProp_L=0, DirProp_R=1, DirProp_EN=2, DirProp_AN=3, DirProp_ON=4, DirProp_S=5, DirProp_B=6 }; /* reduced dirProp */
    1446             : 
    1447             : /******************************************************************
    1448             : 
    1449             :       PROPERTIES  STATE  TABLE
    1450             : 
    1451             :  In table impTabProps,
    1452             :       - the ON column regroups ON and WS, FSI, RLI, LRI and PDI
    1453             :       - the BN column regroups BN, LRE, RLE, LRO, RLO, PDF
    1454             :       - the Res column is the reduced property assigned to a run
    1455             : 
    1456             :  Action 1: process current run1, init new run1
    1457             :         2: init new run2
    1458             :         3: process run1, process run2, init new run1
    1459             :         4: process run1, set run1=run2, init new run2
    1460             : 
    1461             :  Notes:
    1462             :   1) This table is used in resolveImplicitLevels().
    1463             :   2) This table triggers actions when there is a change in the Bidi
    1464             :      property of incoming characters (action 1).
    1465             :   3) Most such property sequences are processed immediately (in
    1466             :      fact, passed to processPropertySeq().
    1467             :   4) However, numbers are assembled as one sequence. This means
    1468             :      that undefined situations (like CS following digits, until
    1469             :      it is known if the next char will be a digit) are held until
    1470             :      following chars define them.
    1471             :      Example: digits followed by CS, then comes another CS or ON;
    1472             :               the digits will be processed, then the CS assigned
    1473             :               as the start of an ON sequence (action 3).
    1474             :   5) There are cases where more than one sequence must be
    1475             :      processed, for instance digits followed by CS followed by L:
    1476             :      the digits must be processed as one sequence, and the CS
    1477             :      must be processed as an ON sequence, all this before starting
    1478             :      assembling chars for the opening L sequence.
    1479             : 
    1480             : 
    1481             : */
    1482             : static const uint8_t impTabProps[][IMPTABPROPS_COLUMNS] =
    1483             : {
    1484             : /*                        L ,     R ,    EN ,    AN ,    ON ,     S ,     B ,    ES ,    ET ,    CS ,    BN ,   NSM ,    AL ,   ENL ,   ENR , Res */
    1485             : /* 0 Init        */ {     1 ,     2 ,     4 ,     5 ,     7 ,    15 ,    17 ,     7 ,     9 ,     7 ,     0 ,     7 ,     3 ,    18 ,    21 , DirProp_ON },
    1486             : /* 1 L           */ {     1 , s(1,2), s(1,4), s(1,5), s(1,7),s(1,15),s(1,17), s(1,7), s(1,9), s(1,7),     1 ,     1 , s(1,3),s(1,18),s(1,21),  DirProp_L },
    1487             : /* 2 R           */ { s(1,1),     2 , s(1,4), s(1,5), s(1,7),s(1,15),s(1,17), s(1,7), s(1,9), s(1,7),     2 ,     2 , s(1,3),s(1,18),s(1,21),  DirProp_R },
    1488             : /* 3 AL          */ { s(1,1), s(1,2), s(1,6), s(1,6), s(1,8),s(1,16),s(1,17), s(1,8), s(1,8), s(1,8),     3 ,     3 ,     3 ,s(1,18),s(1,21),  DirProp_R },
    1489             : /* 4 EN          */ { s(1,1), s(1,2),     4 , s(1,5), s(1,7),s(1,15),s(1,17),s(2,10),    11 ,s(2,10),     4 ,     4 , s(1,3),    18 ,    21 , DirProp_EN },
    1490             : /* 5 AN          */ { s(1,1), s(1,2), s(1,4),     5 , s(1,7),s(1,15),s(1,17), s(1,7), s(1,9),s(2,12),     5 ,     5 , s(1,3),s(1,18),s(1,21), DirProp_AN },
    1491             : /* 6 AL:EN/AN    */ { s(1,1), s(1,2),     6 ,     6 , s(1,8),s(1,16),s(1,17), s(1,8), s(1,8),s(2,13),     6 ,     6 , s(1,3),    18 ,    21 , DirProp_AN },
    1492             : /* 7 ON          */ { s(1,1), s(1,2), s(1,4), s(1,5),     7 ,s(1,15),s(1,17),     7 ,s(2,14),     7 ,     7 ,     7 , s(1,3),s(1,18),s(1,21), DirProp_ON },
    1493             : /* 8 AL:ON       */ { s(1,1), s(1,2), s(1,6), s(1,6),     8 ,s(1,16),s(1,17),     8 ,     8 ,     8 ,     8 ,     8 , s(1,3),s(1,18),s(1,21), DirProp_ON },
    1494             : /* 9 ET          */ { s(1,1), s(1,2),     4 , s(1,5),     7 ,s(1,15),s(1,17),     7 ,     9 ,     7 ,     9 ,     9 , s(1,3),    18 ,    21 , DirProp_ON },
    1495             : /*10 EN+ES/CS    */ { s(3,1), s(3,2),     4 , s(3,5), s(4,7),s(3,15),s(3,17), s(4,7),s(4,14), s(4,7),    10 , s(4,7), s(3,3),    18 ,    21 , DirProp_EN },
    1496             : /*11 EN+ET       */ { s(1,1), s(1,2),     4 , s(1,5), s(1,7),s(1,15),s(1,17), s(1,7),    11 , s(1,7),    11 ,    11 , s(1,3),    18 ,    21 , DirProp_EN },
    1497             : /*12 AN+CS       */ { s(3,1), s(3,2), s(3,4),     5 , s(4,7),s(3,15),s(3,17), s(4,7),s(4,14), s(4,7),    12 , s(4,7), s(3,3),s(3,18),s(3,21), DirProp_AN },
    1498             : /*13 AL:EN/AN+CS */ { s(3,1), s(3,2),     6 ,     6 , s(4,8),s(3,16),s(3,17), s(4,8), s(4,8), s(4,8),    13 , s(4,8), s(3,3),    18 ,    21 , DirProp_AN },
    1499             : /*14 ON+ET       */ { s(1,1), s(1,2), s(4,4), s(1,5),     7 ,s(1,15),s(1,17),     7 ,    14 ,     7 ,    14 ,    14 , s(1,3),s(4,18),s(4,21), DirProp_ON },
    1500             : /*15 S           */ { s(1,1), s(1,2), s(1,4), s(1,5), s(1,7),    15 ,s(1,17), s(1,7), s(1,9), s(1,7),    15 , s(1,7), s(1,3),s(1,18),s(1,21),  DirProp_S },
    1501             : /*16 AL:S        */ { s(1,1), s(1,2), s(1,6), s(1,6), s(1,8),    16 ,s(1,17), s(1,8), s(1,8), s(1,8),    16 , s(1,8), s(1,3),s(1,18),s(1,21),  DirProp_S },
    1502             : /*17 B           */ { s(1,1), s(1,2), s(1,4), s(1,5), s(1,7),s(1,15),    17 , s(1,7), s(1,9), s(1,7),    17 , s(1,7), s(1,3),s(1,18),s(1,21),  DirProp_B },
    1503             : /*18 ENL         */ { s(1,1), s(1,2),    18 , s(1,5), s(1,7),s(1,15),s(1,17),s(2,19),    20 ,s(2,19),    18 ,    18 , s(1,3),    18 ,    21 ,  DirProp_L },
    1504             : /*19 ENL+ES/CS   */ { s(3,1), s(3,2),    18 , s(3,5), s(4,7),s(3,15),s(3,17), s(4,7),s(4,14), s(4,7),    19 , s(4,7), s(3,3),    18 ,    21 ,  DirProp_L },
    1505             : /*20 ENL+ET      */ { s(1,1), s(1,2),    18 , s(1,5), s(1,7),s(1,15),s(1,17), s(1,7),    20 , s(1,7),    20 ,    20 , s(1,3),    18 ,    21 ,  DirProp_L },
    1506             : /*21 ENR         */ { s(1,1), s(1,2),    21 , s(1,5), s(1,7),s(1,15),s(1,17),s(2,22),    23 ,s(2,22),    21 ,    21 , s(1,3),    18 ,    21 , DirProp_AN },
    1507             : /*22 ENR+ES/CS   */ { s(3,1), s(3,2),    21 , s(3,5), s(4,7),s(3,15),s(3,17), s(4,7),s(4,14), s(4,7),    22 , s(4,7), s(3,3),    18 ,    21 , DirProp_AN },
    1508             : /*23 ENR+ET      */ { s(1,1), s(1,2),    21 , s(1,5), s(1,7),s(1,15),s(1,17), s(1,7),    23 , s(1,7),    23 ,    23 , s(1,3),    18 ,    21 , DirProp_AN }
    1509             : };
    1510             : 
    1511             : /*  we must undef macro s because the levels tables have a different
    1512             :  *  structure (4 bits for action and 4 bits for next state.
    1513             :  */
    1514             : #undef s
    1515             : 
    1516             : /******************************************************************
    1517             :  The levels state machine tables
    1518             : *******************************************************************
    1519             : 
    1520             :  All table cells are 8 bits:
    1521             :       bits 0..3:  next state
    1522             :       bits 4..7:  action to perform (if > 0)
    1523             : 
    1524             :  Cells may be of format "n" where n represents the next state
    1525             :  (except for the rightmost column).
    1526             :  Cells may also be of format "s(x,y)" where x represents an action
    1527             :  to perform and y represents the next state.
    1528             : 
    1529             :  This format limits each table to 16 states each and to 15 actions.
    1530             : 
    1531             : *******************************************************************
    1532             :  Definitions and type for levels state tables
    1533             : *******************************************************************
    1534             : */
    1535             : #define IMPTABLEVELS_COLUMNS (DirProp_B + 2)
    1536             : #define IMPTABLEVELS_RES (IMPTABLEVELS_COLUMNS - 1)
    1537             : #define GET_STATE(cell) ((cell)&0x0f)
    1538             : #define GET_ACTION(cell) ((cell)>>4)
    1539             : #define s(action, newState) ((uint8_t)(newState+(action<<4)))
    1540             : 
    1541             : typedef uint8_t ImpTab[][IMPTABLEVELS_COLUMNS];
    1542             : typedef uint8_t ImpAct[];
    1543             : 
    1544             : /* FOOD FOR THOUGHT: each ImpTab should have its associated ImpAct,
    1545             :  * instead of having a pair of ImpTab and a pair of ImpAct.
    1546             :  */
    1547             : typedef struct ImpTabPair {
    1548             :     const void * pImpTab[2];
    1549             :     const void * pImpAct[2];
    1550             : } ImpTabPair;
    1551             : 
    1552             : /******************************************************************
    1553             : 
    1554             :       LEVELS  STATE  TABLES
    1555             : 
    1556             :  In all levels state tables,
    1557             :       - state 0 is the initial state
    1558             :       - the Res column is the increment to add to the text level
    1559             :         for this property sequence.
    1560             : 
    1561             :  The impAct arrays for each table of a pair map the local action
    1562             :  numbers of the table to the total list of actions. For instance,
    1563             :  action 2 in a given table corresponds to the action number which
    1564             :  appears in entry [2] of the impAct array for that table.
    1565             :  The first entry of all impAct arrays must be 0.
    1566             : 
    1567             :  Action 1: init conditional sequence
    1568             :         2: prepend conditional sequence to current sequence
    1569             :         3: set ON sequence to new level - 1
    1570             :         4: init EN/AN/ON sequence
    1571             :         5: fix EN/AN/ON sequence followed by R
    1572             :         6: set previous level sequence to level 2
    1573             : 
    1574             :  Notes:
    1575             :   1) These tables are used in processPropertySeq(). The input
    1576             :      is property sequences as determined by resolveImplicitLevels.
    1577             :   2) Most such property sequences are processed immediately
    1578             :      (levels are assigned).
    1579             :   3) However, some sequences cannot be assigned a final level till
    1580             :      one or more following sequences are received. For instance,
    1581             :      ON following an R sequence within an even-level paragraph.
    1582             :      If the following sequence is R, the ON sequence will be
    1583             :      assigned basic run level+1, and so will the R sequence.
    1584             :   4) S is generally handled like ON, since its level will be fixed
    1585             :      to paragraph level in adjustWSLevels().
    1586             : 
    1587             : */
    1588             : 
    1589             : static const ImpTab impTabL_DEFAULT =   /* Even paragraph level */
    1590             : /*  In this table, conditional sequences receive the lower possible level
    1591             :     until proven otherwise.
    1592             : */
    1593             : {
    1594             : /*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
    1595             : /* 0 : init       */ {     0 ,     1 ,     0 ,     2 ,     0 ,     0 ,     0 ,  0 },
    1596             : /* 1 : R          */ {     0 ,     1 ,     3 ,     3 , s(1,4), s(1,4),     0 ,  1 },
    1597             : /* 2 : AN         */ {     0 ,     1 ,     0 ,     2 , s(1,5), s(1,5),     0 ,  2 },
    1598             : /* 3 : R+EN/AN    */ {     0 ,     1 ,     3 ,     3 , s(1,4), s(1,4),     0 ,  2 },
    1599             : /* 4 : R+ON       */ {     0 , s(2,1), s(3,3), s(3,3),     4 ,     4 ,     0 ,  0 },
    1600             : /* 5 : AN+ON      */ {     0 , s(2,1),     0 , s(3,2),     5 ,     5 ,     0 ,  0 }
    1601             : };
    1602             : static const ImpTab impTabR_DEFAULT =   /* Odd  paragraph level */
    1603             : /*  In this table, conditional sequences receive the lower possible level
    1604             :     until proven otherwise.
    1605             : */
    1606             : {
    1607             : /*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
    1608             : /* 0 : init       */ {     1 ,     0 ,     2 ,     2 ,     0 ,     0 ,     0 ,  0 },
    1609             : /* 1 : L          */ {     1 ,     0 ,     1 ,     3 , s(1,4), s(1,4),     0 ,  1 },
    1610             : /* 2 : EN/AN      */ {     1 ,     0 ,     2 ,     2 ,     0 ,     0 ,     0 ,  1 },
    1611             : /* 3 : L+AN       */ {     1 ,     0 ,     1 ,     3 ,     5 ,     5 ,     0 ,  1 },
    1612             : /* 4 : L+ON       */ { s(2,1),     0 , s(2,1),     3 ,     4 ,     4 ,     0 ,  0 },
    1613             : /* 5 : L+AN+ON    */ {     1 ,     0 ,     1 ,     3 ,     5 ,     5 ,     0 ,  0 }
    1614             : };
    1615             : static const ImpAct impAct0 = {0,1,2,3,4};
    1616             : static const ImpTabPair impTab_DEFAULT = {{&impTabL_DEFAULT,
    1617             :                                            &impTabR_DEFAULT},
    1618             :                                           {&impAct0, &impAct0}};
    1619             : 
    1620             : static const ImpTab impTabL_NUMBERS_SPECIAL =   /* Even paragraph level */
    1621             : /*  In this table, conditional sequences receive the lower possible level
    1622             :     until proven otherwise.
    1623             : */
    1624             : {
    1625             : /*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
    1626             : /* 0 : init       */ {     0 ,     2 , s(1,1), s(1,1),     0 ,     0 ,     0 ,  0 },
    1627             : /* 1 : L+EN/AN    */ {     0 , s(4,2),     1 ,     1 ,     0 ,     0 ,     0 ,  0 },
    1628             : /* 2 : R          */ {     0 ,     2 ,     4 ,     4 , s(1,3), s(1,3),     0 ,  1 },
    1629             : /* 3 : R+ON       */ {     0 , s(2,2), s(3,4), s(3,4),     3 ,     3 ,     0 ,  0 },
    1630             : /* 4 : R+EN/AN    */ {     0 ,     2 ,     4 ,     4 , s(1,3), s(1,3),     0 ,  2 }
    1631             : };
    1632             : static const ImpTabPair impTab_NUMBERS_SPECIAL = {{&impTabL_NUMBERS_SPECIAL,
    1633             :                                                    &impTabR_DEFAULT},
    1634             :                                                   {&impAct0, &impAct0}};
    1635             : 
    1636             : static const ImpTab impTabL_GROUP_NUMBERS_WITH_R =
    1637             : /*  In this table, EN/AN+ON sequences receive levels as if associated with R
    1638             :     until proven that there is L or sor/eor on both sides. AN is handled like EN.
    1639             : */
    1640             : {
    1641             : /*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
    1642             : /* 0 init         */ {     0 ,     3 , s(1,1), s(1,1),     0 ,     0 ,     0 ,  0 },
    1643             : /* 1 EN/AN        */ { s(2,0),     3 ,     1 ,     1 ,     2 , s(2,0), s(2,0),  2 },
    1644             : /* 2 EN/AN+ON     */ { s(2,0),     3 ,     1 ,     1 ,     2 , s(2,0), s(2,0),  1 },
    1645             : /* 3 R            */ {     0 ,     3 ,     5 ,     5 , s(1,4),     0 ,     0 ,  1 },
    1646             : /* 4 R+ON         */ { s(2,0),     3 ,     5 ,     5 ,     4 , s(2,0), s(2,0),  1 },
    1647             : /* 5 R+EN/AN      */ {     0 ,     3 ,     5 ,     5 , s(1,4),     0 ,     0 ,  2 }
    1648             : };
    1649             : static const ImpTab impTabR_GROUP_NUMBERS_WITH_R =
    1650             : /*  In this table, EN/AN+ON sequences receive levels as if associated with R
    1651             :     until proven that there is L on both sides. AN is handled like EN.
    1652             : */
    1653             : {
    1654             : /*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
    1655             : /* 0 init         */ {     2 ,     0 ,     1 ,     1 ,     0 ,     0 ,     0 ,  0 },
    1656             : /* 1 EN/AN        */ {     2 ,     0 ,     1 ,     1 ,     0 ,     0 ,     0 ,  1 },
    1657             : /* 2 L            */ {     2 ,     0 , s(1,4), s(1,4), s(1,3),     0 ,     0 ,  1 },
    1658             : /* 3 L+ON         */ { s(2,2),     0 ,     4 ,     4 ,     3 ,     0 ,     0 ,  0 },
    1659             : /* 4 L+EN/AN      */ { s(2,2),     0 ,     4 ,     4 ,     3 ,     0 ,     0 ,  1 }
    1660             : };
    1661             : static const ImpTabPair impTab_GROUP_NUMBERS_WITH_R = {
    1662             :                         {&impTabL_GROUP_NUMBERS_WITH_R,
    1663             :                          &impTabR_GROUP_NUMBERS_WITH_R},
    1664             :                         {&impAct0, &impAct0}};
    1665             : 
    1666             : 
    1667             : static const ImpTab impTabL_INVERSE_NUMBERS_AS_L =
    1668             : /*  This table is identical to the Default LTR table except that EN and AN are
    1669             :     handled like L.
    1670             : */
    1671             : {
    1672             : /*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
    1673             : /* 0 : init       */ {     0 ,     1 ,     0 ,     0 ,     0 ,     0 ,     0 ,  0 },
    1674             : /* 1 : R          */ {     0 ,     1 ,     0 ,     0 , s(1,4), s(1,4),     0 ,  1 },
    1675             : /* 2 : AN         */ {     0 ,     1 ,     0 ,     0 , s(1,5), s(1,5),     0 ,  2 },
    1676             : /* 3 : R+EN/AN    */ {     0 ,     1 ,     0 ,     0 , s(1,4), s(1,4),     0 ,  2 },
    1677             : /* 4 : R+ON       */ { s(2,0),     1 , s(2,0), s(2,0),     4 ,     4 , s(2,0),  1 },
    1678             : /* 5 : AN+ON      */ { s(2,0),     1 , s(2,0), s(2,0),     5 ,     5 , s(2,0),  1 }
    1679             : };
    1680             : static const ImpTab impTabR_INVERSE_NUMBERS_AS_L =
    1681             : /*  This table is identical to the Default RTL table except that EN and AN are
    1682             :     handled like L.
    1683             : */
    1684             : {
    1685             : /*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
    1686             : /* 0 : init       */ {     1 ,     0 ,     1 ,     1 ,     0 ,     0 ,     0 ,  0 },
    1687             : /* 1 : L          */ {     1 ,     0 ,     1 ,     1 , s(1,4), s(1,4),     0 ,  1 },
    1688             : /* 2 : EN/AN      */ {     1 ,     0 ,     1 ,     1 ,     0 ,     0 ,     0 ,  1 },
    1689             : /* 3 : L+AN       */ {     1 ,     0 ,     1 ,     1 ,     5 ,     5 ,     0 ,  1 },
    1690             : /* 4 : L+ON       */ { s(2,1),     0 , s(2,1), s(2,1),     4 ,     4 ,     0 ,  0 },
    1691             : /* 5 : L+AN+ON    */ {     1 ,     0 ,     1 ,     1 ,     5 ,     5 ,     0 ,  0 }
    1692             : };
    1693             : static const ImpTabPair impTab_INVERSE_NUMBERS_AS_L = {
    1694             :                         {&impTabL_INVERSE_NUMBERS_AS_L,
    1695             :                          &impTabR_INVERSE_NUMBERS_AS_L},
    1696             :                         {&impAct0, &impAct0}};
    1697             : 
    1698             : static const ImpTab impTabR_INVERSE_LIKE_DIRECT =   /* Odd  paragraph level */
    1699             : /*  In this table, conditional sequences receive the lower possible level
    1700             :     until proven otherwise.
    1701             : */
    1702             : {
    1703             : /*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
    1704             : /* 0 : init       */ {     1 ,     0 ,     2 ,     2 ,     0 ,     0 ,     0 ,  0 },
    1705             : /* 1 : L          */ {     1 ,     0 ,     1 ,     2 , s(1,3), s(1,3),     0 ,  1 },
    1706             : /* 2 : EN/AN      */ {     1 ,     0 ,     2 ,     2 ,     0 ,     0 ,     0 ,  1 },
    1707             : /* 3 : L+ON       */ { s(2,1), s(3,0),     6 ,     4 ,     3 ,     3 , s(3,0),  0 },
    1708             : /* 4 : L+ON+AN    */ { s(2,1), s(3,0),     6 ,     4 ,     5 ,     5 , s(3,0),  3 },
    1709             : /* 5 : L+AN+ON    */ { s(2,1), s(3,0),     6 ,     4 ,     5 ,     5 , s(3,0),  2 },
    1710             : /* 6 : L+ON+EN    */ { s(2,1), s(3,0),     6 ,     4 ,     3 ,     3 , s(3,0),  1 }
    1711             : };
    1712             : static const ImpAct impAct1 = {0,1,13,14};
    1713             : /* FOOD FOR THOUGHT: in LTR table below, check case "JKL 123abc"
    1714             :  */
    1715             : static const ImpTabPair impTab_INVERSE_LIKE_DIRECT = {
    1716             :                         {&impTabL_DEFAULT,
    1717             :                          &impTabR_INVERSE_LIKE_DIRECT},
    1718             :                         {&impAct0, &impAct1}};
    1719             : 
    1720             : static const ImpTab impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS =
    1721             : /*  The case handled in this table is (visually):  R EN L
    1722             : */
    1723             : {
    1724             : /*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
    1725             : /* 0 : init       */ {     0 , s(6,3),     0 ,     1 ,     0 ,     0 ,     0 ,  0 },
    1726             : /* 1 : L+AN       */ {     0 , s(6,3),     0 ,     1 , s(1,2), s(3,0),     0 ,  4 },
    1727             : /* 2 : L+AN+ON    */ { s(2,0), s(6,3), s(2,0),     1 ,     2 , s(3,0), s(2,0),  3 },
    1728             : /* 3 : R          */ {     0 , s(6,3), s(5,5), s(5,6), s(1,4), s(3,0),     0 ,  3 },
    1729             : /* 4 : R+ON       */ { s(3,0), s(4,3), s(5,5), s(5,6),     4 , s(3,0), s(3,0),  3 },
    1730             : /* 5 : R+EN       */ { s(3,0), s(4,3),     5 , s(5,6), s(1,4), s(3,0), s(3,0),  4 },
    1731             : /* 6 : R+AN       */ { s(3,0), s(4,3), s(5,5),     6 , s(1,4), s(3,0), s(3,0),  4 }
    1732             : };
    1733             : static const ImpTab impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS =
    1734             : /*  The cases handled in this table are (visually):  R EN L
    1735             :                                                      R L AN L
    1736             : */
    1737             : {
    1738             : /*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
    1739             : /* 0 : init       */ { s(1,3),     0 ,     1 ,     1 ,     0 ,     0 ,     0 ,  0 },
    1740             : /* 1 : R+EN/AN    */ { s(2,3),     0 ,     1 ,     1 ,     2 , s(4,0),     0 ,  1 },
    1741             : /* 2 : R+EN/AN+ON */ { s(2,3),     0 ,     1 ,     1 ,     2 , s(4,0),     0 ,  0 },
    1742             : /* 3 : L          */ {     3 ,     0 ,     3 , s(3,6), s(1,4), s(4,0),     0 ,  1 },
    1743             : /* 4 : L+ON       */ { s(5,3), s(4,0),     5 , s(3,6),     4 , s(4,0), s(4,0),  0 },
    1744             : /* 5 : L+ON+EN    */ { s(5,3), s(4,0),     5 , s(3,6),     4 , s(4,0), s(4,0),  1 },
    1745             : /* 6 : L+AN       */ { s(5,3), s(4,0),     6 ,     6 ,     4 , s(4,0), s(4,0),  3 }
    1746             : };
    1747             : static const ImpAct impAct2 = {0,1,2,5,6,7,8};
    1748             : static const ImpAct impAct3 = {0,1,9,10,11,12};
    1749             : static const ImpTabPair impTab_INVERSE_LIKE_DIRECT_WITH_MARKS = {
    1750             :                         {&impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS,
    1751             :                          &impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS},
    1752             :                         {&impAct2, &impAct3}};
    1753             : 
    1754             : static const ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL = {
    1755             :                         {&impTabL_NUMBERS_SPECIAL,
    1756             :                          &impTabR_INVERSE_LIKE_DIRECT},
    1757             :                         {&impAct0, &impAct1}};
    1758             : 
    1759             : static const ImpTab impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS =
    1760             : /*  The case handled in this table is (visually):  R EN L
    1761             : */
    1762             : {
    1763             : /*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
    1764             : /* 0 : init       */ {     0 , s(6,2),     1 ,     1 ,     0 ,     0 ,     0 ,  0 },
    1765             : /* 1 : L+EN/AN    */ {     0 , s(6,2),     1 ,     1 ,     0 , s(3,0),     0 ,  4 },
    1766             : /* 2 : R          */ {     0 , s(6,2), s(5,4), s(5,4), s(1,3), s(3,0),     0 ,  3 },
    1767             : /* 3 : R+ON       */ { s(3,0), s(4,2), s(5,4), s(5,4),     3 , s(3,0), s(3,0),  3 },
    1768             : /* 4 : R+EN/AN    */ { s(3,0), s(4,2),     4 ,     4 , s(1,3), s(3,0), s(3,0),  4 }
    1769             : };
    1770             : static const ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS = {
    1771             :                         {&impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS,
    1772             :                          &impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS},
    1773             :                         {&impAct2, &impAct3}};
    1774             : 
    1775             : #undef s
    1776             : 
    1777             : typedef struct {
    1778             :     const ImpTab * pImpTab;             /* level table pointer          */
    1779             :     const ImpAct * pImpAct;             /* action map array             */
    1780             :     int32_t startON;                    /* start of ON sequence         */
    1781             :     int32_t startL2EN;                  /* start of level 2 sequence    */
    1782             :     int32_t lastStrongRTL;              /* index of last found R or AL  */
    1783             :     int32_t state;                      /* current state                */
    1784             :     int32_t runStart;                   /* start position of the run    */
    1785             :     UBiDiLevel runLevel;                /* run level before implicit solving */
    1786             : } LevState;
    1787             : 
    1788             : /*------------------------------------------------------------------------*/
    1789             : 
    1790             : static void
    1791           0 : addPoint(UBiDi *pBiDi, int32_t pos, int32_t flag)
    1792             :   /* param pos:     position where to insert
    1793             :      param flag:    one of LRM_BEFORE, LRM_AFTER, RLM_BEFORE, RLM_AFTER
    1794             :   */
    1795             : {
    1796             : #define FIRSTALLOC  10
    1797             :     Point point;
    1798           0 :     InsertPoints * pInsertPoints=&(pBiDi->insertPoints);
    1799             : 
    1800           0 :     if (pInsertPoints->capacity == 0)
    1801             :     {
    1802           0 :         pInsertPoints->points=static_cast<Point *>(uprv_malloc(sizeof(Point)*FIRSTALLOC));
    1803           0 :         if (pInsertPoints->points == NULL)
    1804             :         {
    1805           0 :             pInsertPoints->errorCode=U_MEMORY_ALLOCATION_ERROR;
    1806           0 :             return;
    1807             :         }
    1808           0 :         pInsertPoints->capacity=FIRSTALLOC;
    1809             :     }
    1810           0 :     if (pInsertPoints->size >= pInsertPoints->capacity) /* no room for new point */
    1811             :     {
    1812           0 :         Point * savePoints=pInsertPoints->points;
    1813           0 :         pInsertPoints->points=static_cast<Point *>(uprv_realloc(pInsertPoints->points,
    1814           0 :                                            pInsertPoints->capacity*2*sizeof(Point)));
    1815           0 :         if (pInsertPoints->points == NULL)
    1816             :         {
    1817           0 :             pInsertPoints->points=savePoints;
    1818           0 :             pInsertPoints->errorCode=U_MEMORY_ALLOCATION_ERROR;
    1819           0 :             return;
    1820             :         }
    1821           0 :         else  pInsertPoints->capacity*=2;
    1822             :     }
    1823           0 :     point.pos=pos;
    1824           0 :     point.flag=flag;
    1825           0 :     pInsertPoints->points[pInsertPoints->size]=point;
    1826           0 :     pInsertPoints->size++;
    1827             : #undef FIRSTALLOC
    1828             : }
    1829             : 
    1830             : static void
    1831           0 : setLevelsOutsideIsolates(UBiDi *pBiDi, int32_t start, int32_t limit, UBiDiLevel level)
    1832             : {
    1833           0 :     DirProp *dirProps=pBiDi->dirProps, dirProp;
    1834           0 :     UBiDiLevel *levels=pBiDi->levels;
    1835           0 :     int32_t isolateCount=0, k;
    1836           0 :     for(k=start; k<limit; k++) {
    1837           0 :         dirProp=dirProps[k];
    1838           0 :         if(dirProp==PDI)
    1839           0 :             isolateCount--;
    1840           0 :         if(isolateCount==0)
    1841           0 :             levels[k]=level;
    1842           0 :         if(dirProp==LRI || dirProp==RLI)
    1843           0 :             isolateCount++;
    1844             :     }
    1845           0 : }
    1846             : 
    1847             : /* perform rules (Wn), (Nn), and (In) on a run of the text ------------------ */
    1848             : 
    1849             : /*
    1850             :  * This implementation of the (Wn) rules applies all rules in one pass.
    1851             :  * In order to do so, it needs a look-ahead of typically 1 character
    1852             :  * (except for W5: sequences of ET) and keeps track of changes
    1853             :  * in a rule Wp that affect a later Wq (p<q).
    1854             :  *
    1855             :  * The (Nn) and (In) rules are also performed in that same single loop,
    1856             :  * but effectively one iteration behind for white space.
    1857             :  *
    1858             :  * Since all implicit rules are performed in one step, it is not necessary
    1859             :  * to actually store the intermediate directional properties in dirProps[].
    1860             :  */
    1861             : 
    1862             : static void
    1863           0 : processPropertySeq(UBiDi *pBiDi, LevState *pLevState, uint8_t _prop,
    1864             :                    int32_t start, int32_t limit) {
    1865             :     uint8_t cell, oldStateSeq, actionSeq;
    1866           0 :     const ImpTab * pImpTab=pLevState->pImpTab;
    1867           0 :     const ImpAct * pImpAct=pLevState->pImpAct;
    1868           0 :     UBiDiLevel * levels=pBiDi->levels;
    1869             :     UBiDiLevel level, addLevel;
    1870             :     InsertPoints * pInsertPoints;
    1871             :     int32_t start0, k;
    1872             : 
    1873           0 :     start0=start;                           /* save original start position */
    1874           0 :     oldStateSeq=(uint8_t)pLevState->state;
    1875           0 :     cell=(*pImpTab)[oldStateSeq][_prop];
    1876           0 :     pLevState->state=GET_STATE(cell);       /* isolate the new state */
    1877           0 :     actionSeq=(*pImpAct)[GET_ACTION(cell)]; /* isolate the action */
    1878           0 :     addLevel=(*pImpTab)[pLevState->state][IMPTABLEVELS_RES];
    1879             : 
    1880           0 :     if(actionSeq) {
    1881           0 :         switch(actionSeq) {
    1882             :         case 1:                         /* init ON seq */
    1883           0 :             pLevState->startON=start0;
    1884           0 :             break;
    1885             : 
    1886             :         case 2:                         /* prepend ON seq to current seq */
    1887           0 :             start=pLevState->startON;
    1888           0 :             break;
    1889             : 
    1890             :         case 3:                         /* EN/AN after R+ON */
    1891           0 :             level=pLevState->runLevel+1;
    1892           0 :             setLevelsOutsideIsolates(pBiDi, pLevState->startON, start0, level);
    1893           0 :             break;
    1894             : 
    1895             :         case 4:                         /* EN/AN before R for NUMBERS_SPECIAL */
    1896           0 :             level=pLevState->runLevel+2;
    1897           0 :             setLevelsOutsideIsolates(pBiDi, pLevState->startON, start0, level);
    1898           0 :             break;
    1899             : 
    1900             :         case 5:                         /* L or S after possible relevant EN/AN */
    1901             :             /* check if we had EN after R/AL */
    1902           0 :             if (pLevState->startL2EN >= 0) {
    1903           0 :                 addPoint(pBiDi, pLevState->startL2EN, LRM_BEFORE);
    1904             :             }
    1905           0 :             pLevState->startL2EN=-1;  /* not within previous if since could also be -2 */
    1906             :             /* check if we had any relevant EN/AN after R/AL */
    1907           0 :             pInsertPoints=&(pBiDi->insertPoints);
    1908           0 :             if ((pInsertPoints->capacity == 0) ||
    1909           0 :                 (pInsertPoints->size <= pInsertPoints->confirmed))
    1910             :             {
    1911             :                 /* nothing, just clean up */
    1912           0 :                 pLevState->lastStrongRTL=-1;
    1913             :                 /* check if we have a pending conditional segment */
    1914           0 :                 level=(*pImpTab)[oldStateSeq][IMPTABLEVELS_RES];
    1915           0 :                 if ((level & 1) && (pLevState->startON > 0)) {  /* after ON */
    1916           0 :                     start=pLevState->startON;   /* reset to basic run level */
    1917             :                 }
    1918           0 :                 if (_prop == DirProp_S)                /* add LRM before S */
    1919             :                 {
    1920           0 :                     addPoint(pBiDi, start0, LRM_BEFORE);
    1921           0 :                     pInsertPoints->confirmed=pInsertPoints->size;
    1922             :                 }
    1923           0 :                 break;
    1924             :             }
    1925             :             /* reset previous RTL cont to level for LTR text */
    1926           0 :             for (k=pLevState->lastStrongRTL+1; k<start0; k++)
    1927             :             {
    1928             :                 /* reset odd level, leave runLevel+2 as is */
    1929           0 :                 levels[k]=(levels[k] - 2) & ~1;
    1930             :             }
    1931             :             /* mark insert points as confirmed */
    1932           0 :             pInsertPoints->confirmed=pInsertPoints->size;
    1933           0 :             pLevState->lastStrongRTL=-1;
    1934           0 :             if (_prop == DirProp_S)            /* add LRM before S */
    1935             :             {
    1936           0 :                 addPoint(pBiDi, start0, LRM_BEFORE);
    1937           0 :                 pInsertPoints->confirmed=pInsertPoints->size;
    1938             :             }
    1939           0 :             break;
    1940             : 
    1941             :         case 6:                         /* R/AL after possible relevant EN/AN */
    1942             :             /* just clean up */
    1943           0 :             pInsertPoints=&(pBiDi->insertPoints);
    1944           0 :             if (pInsertPoints->capacity > 0)
    1945             :                 /* remove all non confirmed insert points */
    1946           0 :                 pInsertPoints->size=pInsertPoints->confirmed;
    1947           0 :             pLevState->startON=-1;
    1948           0 :             pLevState->startL2EN=-1;
    1949           0 :             pLevState->lastStrongRTL=limit - 1;
    1950           0 :             break;
    1951             : 
    1952             :         case 7:                         /* EN/AN after R/AL + possible cont */
    1953             :             /* check for real AN */
    1954           0 :             if ((_prop == DirProp_AN) && (pBiDi->dirProps[start0] == AN) &&
    1955           0 :                 (pBiDi->reorderingMode!=UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL))
    1956             :             {
    1957             :                 /* real AN */
    1958           0 :                 if (pLevState->startL2EN == -1) /* if no relevant EN already found */
    1959             :                 {
    1960             :                     /* just note the righmost digit as a strong RTL */
    1961           0 :                     pLevState->lastStrongRTL=limit - 1;
    1962           0 :                     break;
    1963             :                 }
    1964           0 :                 if (pLevState->startL2EN >= 0)  /* after EN, no AN */
    1965             :                 {
    1966           0 :                     addPoint(pBiDi, pLevState->startL2EN, LRM_BEFORE);
    1967           0 :                     pLevState->startL2EN=-2;
    1968             :                 }
    1969             :                 /* note AN */
    1970           0 :                 addPoint(pBiDi, start0, LRM_BEFORE);
    1971           0 :                 break;
    1972             :             }
    1973             :             /* if first EN/AN after R/AL */
    1974           0 :             if (pLevState->startL2EN == -1) {
    1975           0 :                 pLevState->startL2EN=start0;
    1976             :             }
    1977           0 :             break;
    1978             : 
    1979             :         case 8:                         /* note location of latest R/AL */
    1980           0 :             pLevState->lastStrongRTL=limit - 1;
    1981           0 :             pLevState->startON=-1;
    1982           0 :             break;
    1983             : 
    1984             :         case 9:                         /* L after R+ON/EN/AN */
    1985             :             /* include possible adjacent number on the left */
    1986           0 :             for (k=start0-1; k>=0 && !(levels[k]&1); k--);
    1987           0 :             if(k>=0) {
    1988           0 :                 addPoint(pBiDi, k, RLM_BEFORE);             /* add RLM before */
    1989           0 :                 pInsertPoints=&(pBiDi->insertPoints);
    1990           0 :                 pInsertPoints->confirmed=pInsertPoints->size;   /* confirm it */
    1991             :             }
    1992           0 :             pLevState->startON=start0;
    1993           0 :             break;
    1994             : 
    1995             :         case 10:                        /* AN after L */
    1996             :             /* AN numbers between L text on both sides may be trouble. */
    1997             :             /* tentatively bracket with LRMs; will be confirmed if followed by L */
    1998           0 :             addPoint(pBiDi, start0, LRM_BEFORE);    /* add LRM before */
    1999           0 :             addPoint(pBiDi, start0, LRM_AFTER);     /* add LRM after  */
    2000           0 :             break;
    2001             : 
    2002             :         case 11:                        /* R after L+ON/EN/AN */
    2003             :             /* false alert, infirm LRMs around previous AN */
    2004           0 :             pInsertPoints=&(pBiDi->insertPoints);
    2005           0 :             pInsertPoints->size=pInsertPoints->confirmed;
    2006           0 :             if (_prop == DirProp_S)            /* add RLM before S */
    2007             :             {
    2008           0 :                 addPoint(pBiDi, start0, RLM_BEFORE);
    2009           0 :                 pInsertPoints->confirmed=pInsertPoints->size;
    2010             :             }
    2011           0 :             break;
    2012             : 
    2013             :         case 12:                        /* L after L+ON/AN */
    2014           0 :             level=pLevState->runLevel + addLevel;
    2015           0 :             for(k=pLevState->startON; k<start0; k++) {
    2016           0 :                 if (levels[k]<level)
    2017           0 :                     levels[k]=level;
    2018             :             }
    2019           0 :             pInsertPoints=&(pBiDi->insertPoints);
    2020           0 :             pInsertPoints->confirmed=pInsertPoints->size;   /* confirm inserts */
    2021           0 :             pLevState->startON=start0;
    2022           0 :             break;
    2023             : 
    2024             :         case 13:                        /* L after L+ON+EN/AN/ON */
    2025           0 :             level=pLevState->runLevel;
    2026           0 :             for(k=start0-1; k>=pLevState->startON; k--) {
    2027           0 :                 if(levels[k]==level+3) {
    2028           0 :                     while(levels[k]==level+3) {
    2029           0 :                         levels[k--]-=2;
    2030             :                     }
    2031           0 :                     while(levels[k]==level) {
    2032           0 :                         k--;
    2033             :                     }
    2034             :                 }
    2035           0 :                 if(levels[k]==level+2) {
    2036           0 :                     levels[k]=level;
    2037           0 :                     continue;
    2038             :                 }
    2039           0 :                 levels[k]=level+1;
    2040             :             }
    2041           0 :             break;
    2042             : 
    2043             :         case 14:                        /* R after L+ON+EN/AN/ON */
    2044           0 :             level=pLevState->runLevel+1;
    2045           0 :             for(k=start0-1; k>=pLevState->startON; k--) {
    2046           0 :                 if(levels[k]>level) {
    2047           0 :                     levels[k]-=2;
    2048             :                 }
    2049             :             }
    2050           0 :             break;
    2051             : 
    2052             :         default:                        /* we should never get here */
    2053           0 :             U_ASSERT(FALSE);
    2054             :             break;
    2055             :         }
    2056             :     }
    2057           0 :     if((addLevel) || (start < start0)) {
    2058           0 :         level=pLevState->runLevel + addLevel;
    2059           0 :         if(start>=pLevState->runStart) {
    2060           0 :             for(k=start; k<limit; k++) {
    2061           0 :                 levels[k]=level;
    2062             :             }
    2063             :         } else {
    2064           0 :             setLevelsOutsideIsolates(pBiDi, start, limit, level);
    2065             :         }
    2066             :     }
    2067           0 : }
    2068             : 
    2069             : /**
    2070             :  * Returns the directionality of the last strong character at the end of the prologue, if any.
    2071             :  * Requires prologue!=null.
    2072             :  */
    2073             : static DirProp
    2074           0 : lastL_R_AL(UBiDi *pBiDi) {
    2075           0 :     const UChar *text=pBiDi->prologue;
    2076           0 :     int32_t length=pBiDi->proLength;
    2077             :     int32_t i;
    2078             :     UChar32 uchar;
    2079             :     DirProp dirProp;
    2080           0 :     for(i=length; i>0; ) {
    2081             :         /* i is decremented by U16_PREV */
    2082           0 :         U16_PREV(text, 0, i, uchar);
    2083           0 :         dirProp=(DirProp)ubidi_getCustomizedClass(pBiDi, uchar);
    2084           0 :         if(dirProp==L) {
    2085           0 :             return DirProp_L;
    2086             :         }
    2087           0 :         if(dirProp==R || dirProp==AL) {
    2088           0 :             return DirProp_R;
    2089             :         }
    2090           0 :         if(dirProp==B) {
    2091           0 :             return DirProp_ON;
    2092             :         }
    2093             :     }
    2094           0 :     return DirProp_ON;
    2095             : }
    2096             : 
    2097             : /**
    2098             :  * Returns the directionality of the first strong character, or digit, in the epilogue, if any.
    2099             :  * Requires epilogue!=null.
    2100             :  */
    2101             : static DirProp
    2102           0 : firstL_R_AL_EN_AN(UBiDi *pBiDi) {
    2103           0 :     const UChar *text=pBiDi->epilogue;
    2104           0 :     int32_t length=pBiDi->epiLength;
    2105             :     int32_t i;
    2106             :     UChar32 uchar;
    2107             :     DirProp dirProp;
    2108           0 :     for(i=0; i<length; ) {
    2109             :         /* i is incremented by U16_NEXT */
    2110           0 :         U16_NEXT(text, i, length, uchar);
    2111           0 :         dirProp=(DirProp)ubidi_getCustomizedClass(pBiDi, uchar);
    2112           0 :         if(dirProp==L) {
    2113           0 :             return DirProp_L;
    2114             :         }
    2115           0 :         if(dirProp==R || dirProp==AL) {
    2116           0 :             return DirProp_R;
    2117             :         }
    2118           0 :         if(dirProp==EN) {
    2119           0 :             return DirProp_EN;
    2120             :         }
    2121           0 :         if(dirProp==AN) {
    2122           0 :             return DirProp_AN;
    2123             :         }
    2124             :     }
    2125           0 :     return DirProp_ON;
    2126             : }
    2127             : 
    2128             : static void
    2129           0 : resolveImplicitLevels(UBiDi *pBiDi,
    2130             :                       int32_t start, int32_t limit,
    2131             :                       DirProp sor, DirProp eor) {
    2132           0 :     const DirProp *dirProps=pBiDi->dirProps;
    2133             :     DirProp dirProp;
    2134             :     LevState levState;
    2135             :     int32_t i, start1, start2;
    2136             :     uint16_t oldStateImp, stateImp, actionImp;
    2137             :     uint8_t gprop, resProp, cell;
    2138             :     UBool inverseRTL;
    2139           0 :     DirProp nextStrongProp=R;
    2140           0 :     int32_t nextStrongPos=-1;
    2141             : 
    2142             :     /* check for RTL inverse BiDi mode */
    2143             :     /* FOOD FOR THOUGHT: in case of RTL inverse BiDi, it would make sense to
    2144             :      * loop on the text characters from end to start.
    2145             :      * This would need a different properties state table (at least different
    2146             :      * actions) and different levels state tables (maybe very similar to the
    2147             :      * LTR corresponding ones.
    2148             :      */
    2149           0 :     inverseRTL=(UBool)
    2150           0 :         ((start<pBiDi->lastArabicPos) && (GET_PARALEVEL(pBiDi, start) & 1) &&
    2151           0 :          (pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_LIKE_DIRECT  ||
    2152           0 :           pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL));
    2153             : 
    2154             :     /* initialize for property and levels state tables */
    2155           0 :     levState.startL2EN=-1;              /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */
    2156           0 :     levState.lastStrongRTL=-1;          /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */
    2157           0 :     levState.runStart=start;
    2158           0 :     levState.runLevel=pBiDi->levels[start];
    2159           0 :     levState.pImpTab=(const ImpTab*)((pBiDi->pImpTabPair)->pImpTab)[levState.runLevel&1];
    2160           0 :     levState.pImpAct=(const ImpAct*)((pBiDi->pImpTabPair)->pImpAct)[levState.runLevel&1];
    2161           0 :     if(start==0 && pBiDi->proLength>0) {
    2162           0 :         DirProp lastStrong=lastL_R_AL(pBiDi);
    2163           0 :         if(lastStrong!=DirProp_ON) {
    2164           0 :             sor=lastStrong;
    2165             :         }
    2166             :     }
    2167             :     /* The isolates[] entries contain enough information to
    2168             :        resume the bidi algorithm in the same state as it was
    2169             :        when it was interrupted by an isolate sequence. */
    2170           0 :     if(dirProps[start]==PDI  && pBiDi->isolateCount >= 0) {
    2171           0 :         levState.startON=pBiDi->isolates[pBiDi->isolateCount].startON;
    2172           0 :         start1=pBiDi->isolates[pBiDi->isolateCount].start1;
    2173           0 :         stateImp=pBiDi->isolates[pBiDi->isolateCount].stateImp;
    2174           0 :         levState.state=pBiDi->isolates[pBiDi->isolateCount].state;
    2175           0 :         pBiDi->isolateCount--;
    2176             :     } else {
    2177           0 :         levState.startON=-1;
    2178           0 :         start1=start;
    2179           0 :         if(dirProps[start]==NSM)
    2180           0 :             stateImp = 1 + sor;
    2181             :         else
    2182           0 :             stateImp=0;
    2183           0 :         levState.state=0;
    2184           0 :         processPropertySeq(pBiDi, &levState, sor, start, start);
    2185             :     }
    2186           0 :     start2=start;                       /* to make Java compiler happy */
    2187             : 
    2188           0 :     for(i=start; i<=limit; i++) {
    2189           0 :         if(i>=limit) {
    2190             :             int32_t k;
    2191           0 :             for(k=limit-1; k>start&&(DIRPROP_FLAG(dirProps[k])&MASK_BN_EXPLICIT); k--);
    2192           0 :             dirProp=dirProps[k];
    2193           0 :             if(dirProp==LRI || dirProp==RLI)
    2194             :                 break;      /* no forced closing for sequence ending with LRI/RLI */
    2195           0 :             gprop=eor;
    2196             :         } else {
    2197             :             DirProp prop, prop1;
    2198           0 :             prop=dirProps[i];
    2199           0 :             if(prop==B) {
    2200           0 :                 pBiDi->isolateCount=-1; /* current isolates stack entry == none */
    2201             :             }
    2202           0 :             if(inverseRTL) {
    2203           0 :                 if(prop==AL) {
    2204             :                     /* AL before EN does not make it AN */
    2205           0 :                     prop=R;
    2206           0 :                 } else if(prop==EN) {
    2207           0 :                     if(nextStrongPos<=i) {
    2208             :                         /* look for next strong char (L/R/AL) */
    2209             :                         int32_t j;
    2210           0 :                         nextStrongProp=R;   /* set default */
    2211           0 :                         nextStrongPos=limit;
    2212           0 :                         for(j=i+1; j<limit; j++) {
    2213           0 :                             prop1=dirProps[j];
    2214           0 :                             if(prop1==L || prop1==R || prop1==AL) {
    2215           0 :                                 nextStrongProp=prop1;
    2216           0 :                                 nextStrongPos=j;
    2217           0 :                                 break;
    2218             :                             }
    2219             :                         }
    2220             :                     }
    2221           0 :                     if(nextStrongProp==AL) {
    2222           0 :                         prop=AN;
    2223             :                     }
    2224             :                 }
    2225             :             }
    2226           0 :             gprop=groupProp[prop];
    2227             :         }
    2228           0 :         oldStateImp=stateImp;
    2229           0 :         cell=impTabProps[oldStateImp][gprop];
    2230           0 :         stateImp=GET_STATEPROPS(cell);      /* isolate the new state */
    2231           0 :         actionImp=GET_ACTIONPROPS(cell);    /* isolate the action */
    2232           0 :         if((i==limit) && (actionImp==0)) {
    2233             :             /* there is an unprocessed sequence if its property == eor   */
    2234           0 :             actionImp=1;                    /* process the last sequence */
    2235             :         }
    2236           0 :         if(actionImp) {
    2237           0 :             resProp=impTabProps[oldStateImp][IMPTABPROPS_RES];
    2238           0 :             switch(actionImp) {
    2239             :             case 1:             /* process current seq1, init new seq1 */
    2240           0 :                 processPropertySeq(pBiDi, &levState, resProp, start1, i);
    2241           0 :                 start1=i;
    2242           0 :                 break;
    2243             :             case 2:             /* init new seq2 */
    2244           0 :                 start2=i;
    2245           0 :                 break;
    2246             :             case 3:             /* process seq1, process seq2, init new seq1 */
    2247           0 :                 processPropertySeq(pBiDi, &levState, resProp, start1, start2);
    2248           0 :                 processPropertySeq(pBiDi, &levState, DirProp_ON, start2, i);
    2249           0 :                 start1=i;
    2250           0 :                 break;
    2251             :             case 4:             /* process seq1, set seq1=seq2, init new seq2 */
    2252           0 :                 processPropertySeq(pBiDi, &levState, resProp, start1, start2);
    2253           0 :                 start1=start2;
    2254           0 :                 start2=i;
    2255           0 :                 break;
    2256             :             default:            /* we should never get here */
    2257           0 :                 U_ASSERT(FALSE);
    2258             :                 break;
    2259             :             }
    2260             :         }
    2261             :     }
    2262             : 
    2263             :     /* flush possible pending sequence, e.g. ON */
    2264           0 :     if(limit==pBiDi->length && pBiDi->epiLength>0) {
    2265           0 :         DirProp firstStrong=firstL_R_AL_EN_AN(pBiDi);
    2266           0 :         if(firstStrong!=DirProp_ON) {
    2267           0 :             eor=firstStrong;
    2268             :         }
    2269             :     }
    2270             : 
    2271             :     /* look for the last char not a BN or LRE/RLE/LRO/RLO/PDF */
    2272           0 :     for(i=limit-1; i>start&&(DIRPROP_FLAG(dirProps[i])&MASK_BN_EXPLICIT); i--);
    2273           0 :     dirProp=dirProps[i];
    2274           0 :     if((dirProp==LRI || dirProp==RLI) && limit<pBiDi->length) {
    2275           0 :         pBiDi->isolateCount++;
    2276           0 :         pBiDi->isolates[pBiDi->isolateCount].stateImp=stateImp;
    2277           0 :         pBiDi->isolates[pBiDi->isolateCount].state=levState.state;
    2278           0 :         pBiDi->isolates[pBiDi->isolateCount].start1=start1;
    2279           0 :         pBiDi->isolates[pBiDi->isolateCount].startON=levState.startON;
    2280             :     }
    2281             :     else
    2282           0 :         processPropertySeq(pBiDi, &levState, eor, limit, limit);
    2283           0 : }
    2284             : 
    2285             : /* perform (L1) and (X9) ---------------------------------------------------- */
    2286             : 
    2287             : /*
    2288             :  * Reset the embedding levels for some non-graphic characters (L1).
    2289             :  * This function also sets appropriate levels for BN, and
    2290             :  * explicit embedding types that are supposed to have been removed
    2291             :  * from the paragraph in (X9).
    2292             :  */
    2293             : static void
    2294           0 : adjustWSLevels(UBiDi *pBiDi) {
    2295           0 :     const DirProp *dirProps=pBiDi->dirProps;
    2296           0 :     UBiDiLevel *levels=pBiDi->levels;
    2297             :     int32_t i;
    2298             : 
    2299           0 :     if(pBiDi->flags&MASK_WS) {
    2300           0 :         UBool orderParagraphsLTR=pBiDi->orderParagraphsLTR;
    2301             :         Flags flag;
    2302             : 
    2303           0 :         i=pBiDi->trailingWSStart;
    2304           0 :         while(i>0) {
    2305             :             /* reset a sequence of WS/BN before eop and B/S to the paragraph paraLevel */
    2306           0 :             while(i>0 && (flag=DIRPROP_FLAG(dirProps[--i]))&MASK_WS) {
    2307           0 :                 if(orderParagraphsLTR&&(flag&DIRPROP_FLAG(B))) {
    2308           0 :                     levels[i]=0;
    2309             :                 } else {
    2310           0 :                     levels[i]=GET_PARALEVEL(pBiDi, i);
    2311             :                 }
    2312             :             }
    2313             : 
    2314             :             /* reset BN to the next character's paraLevel until B/S, which restarts above loop */
    2315             :             /* here, i+1 is guaranteed to be <length */
    2316           0 :             while(i>0) {
    2317           0 :                 flag=DIRPROP_FLAG(dirProps[--i]);
    2318           0 :                 if(flag&MASK_BN_EXPLICIT) {
    2319           0 :                     levels[i]=levels[i+1];
    2320           0 :                 } else if(orderParagraphsLTR&&(flag&DIRPROP_FLAG(B))) {
    2321           0 :                     levels[i]=0;
    2322           0 :                     break;
    2323           0 :                 } else if(flag&MASK_B_S) {
    2324           0 :                     levels[i]=GET_PARALEVEL(pBiDi, i);
    2325           0 :                     break;
    2326             :                 }
    2327             :             }
    2328             :         }
    2329             :     }
    2330           0 : }
    2331             : 
    2332             : U_CAPI void U_EXPORT2
    2333           0 : ubidi_setContext(UBiDi *pBiDi,
    2334             :                  const UChar *prologue, int32_t proLength,
    2335             :                  const UChar *epilogue, int32_t epiLength,
    2336             :                  UErrorCode *pErrorCode) {
    2337             :     /* check the argument values */
    2338           0 :     RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
    2339           0 :     if(pBiDi==NULL || proLength<-1 || epiLength<-1 ||
    2340           0 :        (prologue==NULL && proLength!=0) || (epilogue==NULL && epiLength!=0)) {
    2341           0 :         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    2342           0 :         return;
    2343             :     }
    2344             : 
    2345           0 :     if(proLength==-1) {
    2346           0 :         pBiDi->proLength=u_strlen(prologue);
    2347             :     } else {
    2348           0 :         pBiDi->proLength=proLength;
    2349             :     }
    2350           0 :     if(epiLength==-1) {
    2351           0 :         pBiDi->epiLength=u_strlen(epilogue);
    2352             :     } else {
    2353           0 :         pBiDi->epiLength=epiLength;
    2354             :     }
    2355           0 :     pBiDi->prologue=prologue;
    2356           0 :     pBiDi->epilogue=epilogue;
    2357             : }
    2358             : 
    2359             : static void
    2360           0 : setParaSuccess(UBiDi *pBiDi) {
    2361           0 :     pBiDi->proLength=0;                 /* forget the last context */
    2362           0 :     pBiDi->epiLength=0;
    2363           0 :     pBiDi->pParaBiDi=pBiDi;             /* mark successful setPara */
    2364           0 : }
    2365             : 
    2366             : #define BIDI_MIN(x, y)   ((x)<(y) ? (x) : (y))
    2367             : #define BIDI_ABS(x)      ((x)>=0  ? (x) : (-(x)))
    2368             : 
    2369             : static void
    2370           0 : setParaRunsOnly(UBiDi *pBiDi, const UChar *text, int32_t length,
    2371             :                 UBiDiLevel paraLevel, UErrorCode *pErrorCode) {
    2372           0 :     int32_t *runsOnlyMemory = NULL;
    2373             :     int32_t *visualMap;
    2374             :     UChar *visualText;
    2375             :     int32_t saveLength, saveTrailingWSStart;
    2376             :     const UBiDiLevel *levels;
    2377             :     UBiDiLevel *saveLevels;
    2378             :     UBiDiDirection saveDirection;
    2379             :     UBool saveMayAllocateText;
    2380             :     Run *runs;
    2381             :     int32_t visualLength, i, j, visualStart, logicalStart,
    2382             :             runCount, runLength, addedRuns, insertRemove,
    2383             :             start, limit, step, indexOddBit, logicalPos,
    2384             :             index0, index1;
    2385             :     uint32_t saveOptions;
    2386             : 
    2387           0 :     pBiDi->reorderingMode=UBIDI_REORDER_DEFAULT;
    2388           0 :     if(length==0) {
    2389           0 :         ubidi_setPara(pBiDi, text, length, paraLevel, NULL, pErrorCode);
    2390           0 :         goto cleanup3;
    2391             :     }
    2392             :     /* obtain memory for mapping table and visual text */
    2393           0 :     runsOnlyMemory=static_cast<int32_t *>(uprv_malloc(length*(sizeof(int32_t)+sizeof(UChar)+sizeof(UBiDiLevel))));
    2394           0 :     if(runsOnlyMemory==NULL) {
    2395           0 :         *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
    2396           0 :         goto cleanup3;
    2397             :     }
    2398           0 :     visualMap=runsOnlyMemory;
    2399           0 :     visualText=(UChar *)&visualMap[length];
    2400           0 :     saveLevels=(UBiDiLevel *)&visualText[length];
    2401           0 :     saveOptions=pBiDi->reorderingOptions;
    2402           0 :     if(saveOptions & UBIDI_OPTION_INSERT_MARKS) {
    2403           0 :         pBiDi->reorderingOptions&=~UBIDI_OPTION_INSERT_MARKS;
    2404           0 :         pBiDi->reorderingOptions|=UBIDI_OPTION_REMOVE_CONTROLS;
    2405             :     }
    2406           0 :     paraLevel&=1;                       /* accept only 0 or 1 */
    2407           0 :     ubidi_setPara(pBiDi, text, length, paraLevel, NULL, pErrorCode);
    2408           0 :     if(U_FAILURE(*pErrorCode)) {
    2409           0 :         goto cleanup3;
    2410             :     }
    2411             :     /* we cannot access directly pBiDi->levels since it is not yet set if
    2412             :      * direction is not MIXED
    2413             :      */
    2414           0 :     levels=ubidi_getLevels(pBiDi, pErrorCode);
    2415           0 :     uprv_memcpy(saveLevels, levels, (size_t)pBiDi->length*sizeof(UBiDiLevel));
    2416           0 :     saveTrailingWSStart=pBiDi->trailingWSStart;
    2417           0 :     saveLength=pBiDi->length;
    2418           0 :     saveDirection=pBiDi->direction;
    2419             : 
    2420             :     /* FOOD FOR THOUGHT: instead of writing the visual text, we could use
    2421             :      * the visual map and the dirProps array to drive the second call
    2422             :      * to ubidi_setPara (but must make provision for possible removal of
    2423             :      * BiDi controls.  Alternatively, only use the dirProps array via
    2424             :      * customized classifier callback.
    2425             :      */
    2426             :     visualLength=ubidi_writeReordered(pBiDi, visualText, length,
    2427           0 :                                       UBIDI_DO_MIRRORING, pErrorCode);
    2428           0 :     ubidi_getVisualMap(pBiDi, visualMap, pErrorCode);
    2429           0 :     if(U_FAILURE(*pErrorCode)) {
    2430           0 :         goto cleanup2;
    2431             :     }
    2432           0 :     pBiDi->reorderingOptions=saveOptions;
    2433             : 
    2434           0 :     pBiDi->reorderingMode=UBIDI_REORDER_INVERSE_LIKE_DIRECT;
    2435           0 :     paraLevel^=1;
    2436             :     /* Because what we did with reorderingOptions, visualText may be shorter
    2437             :      * than the original text. But we don't want the levels memory to be
    2438             :      * reallocated shorter than the original length, since we need to restore
    2439             :      * the levels as after the first call to ubidi_setpara() before returning.
    2440             :      * We will force mayAllocateText to FALSE before the second call to
    2441             :      * ubidi_setpara(), and will restore it afterwards.
    2442             :      */
    2443           0 :     saveMayAllocateText=pBiDi->mayAllocateText;
    2444           0 :     pBiDi->mayAllocateText=FALSE;
    2445           0 :     ubidi_setPara(pBiDi, visualText, visualLength, paraLevel, NULL, pErrorCode);
    2446           0 :     pBiDi->mayAllocateText=saveMayAllocateText;
    2447           0 :     ubidi_getRuns(pBiDi, pErrorCode);
    2448           0 :     if(U_FAILURE(*pErrorCode)) {
    2449           0 :         goto cleanup1;
    2450             :     }
    2451             :     /* check if some runs must be split, count how many splits */
    2452           0 :     addedRuns=0;
    2453           0 :     runCount=pBiDi->runCount;
    2454           0 :     runs=pBiDi->runs;
    2455           0 :     visualStart=0;
    2456           0 :     for(i=0; i<runCount; i++, visualStart+=runLength) {
    2457           0 :         runLength=runs[i].visualLimit-visualStart;
    2458           0 :         if(runLength<2) {
    2459           0 :             continue;
    2460             :         }
    2461           0 :         logicalStart=GET_INDEX(runs[i].logicalStart);
    2462           0 :         for(j=logicalStart+1; j<logicalStart+runLength; j++) {
    2463           0 :             index0=visualMap[j];
    2464           0 :             index1=visualMap[j-1];
    2465           0 :             if((BIDI_ABS(index0-index1)!=1) || (saveLevels[index0]!=saveLevels[index1])) {
    2466           0 :                 addedRuns++;
    2467             :             }
    2468             :         }
    2469             :     }
    2470           0 :     if(addedRuns) {
    2471           0 :         if(getRunsMemory(pBiDi, runCount+addedRuns)) {
    2472           0 :             if(runCount==1) {
    2473             :                 /* because we switch from UBiDi.simpleRuns to UBiDi.runs */
    2474           0 :                 pBiDi->runsMemory[0]=runs[0];
    2475             :             }
    2476           0 :             runs=pBiDi->runs=pBiDi->runsMemory;
    2477           0 :             pBiDi->runCount+=addedRuns;
    2478             :         } else {
    2479           0 :             goto cleanup1;
    2480             :         }
    2481             :     }
    2482             :     /* split runs which are not consecutive in source text */
    2483           0 :     for(i=runCount-1; i>=0; i--) {
    2484           0 :         runLength= i==0 ? runs[0].visualLimit :
    2485           0 :                           runs[i].visualLimit-runs[i-1].visualLimit;
    2486           0 :         logicalStart=runs[i].logicalStart;
    2487           0 :         indexOddBit=GET_ODD_BIT(logicalStart);
    2488           0 :         logicalStart=GET_INDEX(logicalStart);
    2489           0 :         if(runLength<2) {
    2490           0 :             if(addedRuns) {
    2491           0 :                 runs[i+addedRuns]=runs[i];
    2492             :             }
    2493           0 :             logicalPos=visualMap[logicalStart];
    2494           0 :             runs[i+addedRuns].logicalStart=MAKE_INDEX_ODD_PAIR(logicalPos,
    2495             :                                             saveLevels[logicalPos]^indexOddBit);
    2496           0 :             continue;
    2497             :         }
    2498           0 :         if(indexOddBit) {
    2499           0 :             start=logicalStart;
    2500           0 :             limit=logicalStart+runLength-1;
    2501           0 :             step=1;
    2502             :         } else {
    2503           0 :             start=logicalStart+runLength-1;
    2504           0 :             limit=logicalStart;
    2505           0 :             step=-1;
    2506             :         }
    2507           0 :         for(j=start; j!=limit; j+=step) {
    2508           0 :             index0=visualMap[j];
    2509           0 :             index1=visualMap[j+step];
    2510           0 :             if((BIDI_ABS(index0-index1)!=1) || (saveLevels[index0]!=saveLevels[index1])) {
    2511           0 :                 logicalPos=BIDI_MIN(visualMap[start], index0);
    2512           0 :                 runs[i+addedRuns].logicalStart=MAKE_INDEX_ODD_PAIR(logicalPos,
    2513             :                                             saveLevels[logicalPos]^indexOddBit);
    2514           0 :                 runs[i+addedRuns].visualLimit=runs[i].visualLimit;
    2515           0 :                 runs[i].visualLimit-=BIDI_ABS(j-start)+1;
    2516           0 :                 insertRemove=runs[i].insertRemove&(LRM_AFTER|RLM_AFTER);
    2517           0 :                 runs[i+addedRuns].insertRemove=insertRemove;
    2518           0 :                 runs[i].insertRemove&=~insertRemove;
    2519           0 :                 start=j+step;
    2520           0 :                 addedRuns--;
    2521             :             }
    2522             :         }
    2523           0 :         if(addedRuns) {
    2524           0 :             runs[i+addedRuns]=runs[i];
    2525             :         }
    2526           0 :         logicalPos=BIDI_MIN(visualMap[start], visualMap[limit]);
    2527           0 :         runs[i+addedRuns].logicalStart=MAKE_INDEX_ODD_PAIR(logicalPos,
    2528             :                                             saveLevels[logicalPos]^indexOddBit);
    2529             :     }
    2530             : 
    2531             :   cleanup1:
    2532             :     /* restore initial paraLevel */
    2533           0 :     pBiDi->paraLevel^=1;
    2534             :   cleanup2:
    2535             :     /* restore real text */
    2536           0 :     pBiDi->text=text;
    2537           0 :     pBiDi->length=saveLength;
    2538           0 :     pBiDi->originalLength=length;
    2539           0 :     pBiDi->direction=saveDirection;
    2540             :     /* the saved levels should never excess levelsSize, but we check anyway */
    2541           0 :     if(saveLength>pBiDi->levelsSize) {
    2542           0 :         saveLength=pBiDi->levelsSize;
    2543             :     }
    2544           0 :     uprv_memcpy(pBiDi->levels, saveLevels, (size_t)saveLength*sizeof(UBiDiLevel));
    2545           0 :     pBiDi->trailingWSStart=saveTrailingWSStart;
    2546           0 :     if(pBiDi->runCount>1) {
    2547           0 :         pBiDi->direction=UBIDI_MIXED;
    2548             :     }
    2549             :   cleanup3:
    2550             :     /* free memory for mapping table and visual text */
    2551           0 :     uprv_free(runsOnlyMemory);
    2552             : 
    2553           0 :     pBiDi->reorderingMode=UBIDI_REORDER_RUNS_ONLY;
    2554           0 : }
    2555             : 
    2556             : /* ubidi_setPara ------------------------------------------------------------ */
    2557             : 
    2558             : U_CAPI void U_EXPORT2
    2559           0 : ubidi_setPara(UBiDi *pBiDi, const UChar *text, int32_t length,
    2560             :               UBiDiLevel paraLevel, UBiDiLevel *embeddingLevels,
    2561             :               UErrorCode *pErrorCode) {
    2562             :     UBiDiDirection direction;
    2563             :     DirProp *dirProps;
    2564             : 
    2565             :     /* check the argument values */
    2566           0 :     RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
    2567           0 :     if(pBiDi==NULL || text==NULL || length<-1 ||
    2568           0 :        (paraLevel>UBIDI_MAX_EXPLICIT_LEVEL && paraLevel<UBIDI_DEFAULT_LTR)) {
    2569           0 :         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    2570           0 :         return;
    2571             :     }
    2572             : 
    2573           0 :     if(length==-1) {
    2574           0 :         length=u_strlen(text);
    2575             :     }
    2576             : 
    2577             :     /* special treatment for RUNS_ONLY mode */
    2578           0 :     if(pBiDi->reorderingMode==UBIDI_REORDER_RUNS_ONLY) {
    2579           0 :         setParaRunsOnly(pBiDi, text, length, paraLevel, pErrorCode);
    2580           0 :         return;
    2581             :     }
    2582             : 
    2583             :     /* initialize the UBiDi structure */
    2584           0 :     pBiDi->pParaBiDi=NULL;          /* mark unfinished setPara */
    2585           0 :     pBiDi->text=text;
    2586           0 :     pBiDi->length=pBiDi->originalLength=pBiDi->resultLength=length;
    2587           0 :     pBiDi->paraLevel=paraLevel;
    2588           0 :     pBiDi->direction=(UBiDiDirection)(paraLevel&1);
    2589           0 :     pBiDi->paraCount=1;
    2590             : 
    2591           0 :     pBiDi->dirProps=NULL;
    2592           0 :     pBiDi->levels=NULL;
    2593           0 :     pBiDi->runs=NULL;
    2594           0 :     pBiDi->insertPoints.size=0;         /* clean up from last call */
    2595           0 :     pBiDi->insertPoints.confirmed=0;    /* clean up from last call */
    2596             : 
    2597             :     /*
    2598             :      * Save the original paraLevel if contextual; otherwise, set to 0.
    2599             :      */
    2600           0 :     pBiDi->defaultParaLevel=IS_DEFAULT_LEVEL(paraLevel);
    2601             : 
    2602           0 :     if(length==0) {
    2603             :         /*
    2604             :          * For an empty paragraph, create a UBiDi object with the paraLevel and
    2605             :          * the flags and the direction set but without allocating zero-length arrays.
    2606             :          * There is nothing more to do.
    2607             :          */
    2608           0 :         if(IS_DEFAULT_LEVEL(paraLevel)) {
    2609           0 :             pBiDi->paraLevel&=1;
    2610           0 :             pBiDi->defaultParaLevel=0;
    2611             :         }
    2612           0 :         pBiDi->flags=DIRPROP_FLAG_LR(paraLevel);
    2613           0 :         pBiDi->runCount=0;
    2614           0 :         pBiDi->paraCount=0;
    2615           0 :         setParaSuccess(pBiDi);          /* mark successful setPara */
    2616           0 :         return;
    2617             :     }
    2618             : 
    2619           0 :     pBiDi->runCount=-1;
    2620             : 
    2621             :     /* allocate paras memory */
    2622           0 :     if(pBiDi->parasMemory)
    2623           0 :         pBiDi->paras=pBiDi->parasMemory;
    2624             :     else
    2625           0 :         pBiDi->paras=pBiDi->simpleParas;
    2626             : 
    2627             :     /*
    2628             :      * Get the directional properties,
    2629             :      * the flags bit-set, and
    2630             :      * determine the paragraph level if necessary.
    2631             :      */
    2632           0 :     if(getDirPropsMemory(pBiDi, length)) {
    2633           0 :         pBiDi->dirProps=pBiDi->dirPropsMemory;
    2634           0 :         if(!getDirProps(pBiDi)) {
    2635           0 :             *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
    2636           0 :             return;
    2637             :         }
    2638             :     } else {
    2639           0 :         *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
    2640           0 :         return;
    2641             :     }
    2642           0 :     dirProps=pBiDi->dirProps;
    2643             :     /* the processed length may have changed if UBIDI_OPTION_STREAMING */
    2644           0 :     length= pBiDi->length;
    2645           0 :     pBiDi->trailingWSStart=length;  /* the levels[] will reflect the WS run */
    2646             : 
    2647             :     /* are explicit levels specified? */
    2648           0 :     if(embeddingLevels==NULL) {
    2649             :         /* no: determine explicit levels according to the (Xn) rules */\
    2650           0 :         if(getLevelsMemory(pBiDi, length)) {
    2651           0 :             pBiDi->levels=pBiDi->levelsMemory;
    2652           0 :             direction=resolveExplicitLevels(pBiDi, pErrorCode);
    2653           0 :             if(U_FAILURE(*pErrorCode)) {
    2654           0 :                 return;
    2655             :             }
    2656             :         } else {
    2657           0 :             *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
    2658           0 :             return;
    2659             :         }
    2660             :     } else {
    2661             :         /* set BN for all explicit codes, check that all levels are 0 or paraLevel..UBIDI_MAX_EXPLICIT_LEVEL */
    2662           0 :         pBiDi->levels=embeddingLevels;
    2663           0 :         direction=checkExplicitLevels(pBiDi, pErrorCode);
    2664           0 :         if(U_FAILURE(*pErrorCode)) {
    2665           0 :             return;
    2666             :         }
    2667             :     }
    2668             : 
    2669             :     /* allocate isolate memory */
    2670           0 :     if(pBiDi->isolateCount<=SIMPLE_ISOLATES_COUNT)
    2671           0 :         pBiDi->isolates=pBiDi->simpleIsolates;
    2672             :     else
    2673           0 :         if((int32_t)(pBiDi->isolateCount*sizeof(Isolate))<=pBiDi->isolatesSize)
    2674           0 :             pBiDi->isolates=pBiDi->isolatesMemory;
    2675             :         else {
    2676           0 :             if(getInitialIsolatesMemory(pBiDi, pBiDi->isolateCount)) {
    2677           0 :                 pBiDi->isolates=pBiDi->isolatesMemory;
    2678             :             } else {
    2679           0 :                 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
    2680           0 :                 return;
    2681             :             }
    2682             :         }
    2683           0 :     pBiDi->isolateCount=-1;             /* current isolates stack entry == none */
    2684             : 
    2685             :     /*
    2686             :      * The steps after (X9) in the UBiDi algorithm are performed only if
    2687             :      * the paragraph text has mixed directionality!
    2688             :      */
    2689           0 :     pBiDi->direction=direction;
    2690           0 :     switch(direction) {
    2691             :     case UBIDI_LTR:
    2692             :         /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */
    2693           0 :         pBiDi->trailingWSStart=0;
    2694           0 :         break;
    2695             :     case UBIDI_RTL:
    2696             :         /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */
    2697           0 :         pBiDi->trailingWSStart=0;
    2698           0 :         break;
    2699             :     default:
    2700             :         /*
    2701             :          *  Choose the right implicit state table
    2702             :          */
    2703           0 :         switch(pBiDi->reorderingMode) {
    2704             :         case UBIDI_REORDER_DEFAULT:
    2705           0 :             pBiDi->pImpTabPair=&impTab_DEFAULT;
    2706           0 :             break;
    2707             :         case UBIDI_REORDER_NUMBERS_SPECIAL:
    2708           0 :             pBiDi->pImpTabPair=&impTab_NUMBERS_SPECIAL;
    2709           0 :             break;
    2710             :         case UBIDI_REORDER_GROUP_NUMBERS_WITH_R:
    2711           0 :             pBiDi->pImpTabPair=&impTab_GROUP_NUMBERS_WITH_R;
    2712           0 :             break;
    2713             :         case UBIDI_REORDER_INVERSE_NUMBERS_AS_L:
    2714           0 :             pBiDi->pImpTabPair=&impTab_INVERSE_NUMBERS_AS_L;
    2715           0 :             break;
    2716             :         case UBIDI_REORDER_INVERSE_LIKE_DIRECT:
    2717           0 :             if (pBiDi->reorderingOptions & UBIDI_OPTION_INSERT_MARKS) {
    2718           0 :                 pBiDi->pImpTabPair=&impTab_INVERSE_LIKE_DIRECT_WITH_MARKS;
    2719             :             } else {
    2720           0 :                 pBiDi->pImpTabPair=&impTab_INVERSE_LIKE_DIRECT;
    2721             :             }
    2722           0 :             break;
    2723             :         case UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL:
    2724           0 :             if (pBiDi->reorderingOptions & UBIDI_OPTION_INSERT_MARKS) {
    2725           0 :                 pBiDi->pImpTabPair=&impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS;
    2726             :             } else {
    2727           0 :                 pBiDi->pImpTabPair=&impTab_INVERSE_FOR_NUMBERS_SPECIAL;
    2728             :             }
    2729           0 :             break;
    2730             :         default:
    2731             :             /* we should never get here */
    2732           0 :             U_ASSERT(FALSE);
    2733             :             break;
    2734             :         }
    2735             :         /*
    2736             :          * If there are no external levels specified and there
    2737             :          * are no significant explicit level codes in the text,
    2738             :          * then we can treat the entire paragraph as one run.
    2739             :          * Otherwise, we need to perform the following rules on runs of
    2740             :          * the text with the same embedding levels. (X10)
    2741             :          * "Significant" explicit level codes are ones that actually
    2742             :          * affect non-BN characters.
    2743             :          * Examples for "insignificant" ones are empty embeddings
    2744             :          * LRE-PDF, LRE-RLE-PDF-PDF, etc.
    2745             :          */
    2746           0 :         if(embeddingLevels==NULL && pBiDi->paraCount<=1 &&
    2747           0 :                                    !(pBiDi->flags&DIRPROP_FLAG_MULTI_RUNS)) {
    2748           0 :             resolveImplicitLevels(pBiDi, 0, length,
    2749           0 :                                     GET_LR_FROM_LEVEL(GET_PARALEVEL(pBiDi, 0)),
    2750           0 :                                     GET_LR_FROM_LEVEL(GET_PARALEVEL(pBiDi, length-1)));
    2751             :         } else {
    2752             :             /* sor, eor: start and end types of same-level-run */
    2753           0 :             UBiDiLevel *levels=pBiDi->levels;
    2754           0 :             int32_t start, limit=0;
    2755             :             UBiDiLevel level, nextLevel;
    2756             :             DirProp sor, eor;
    2757             : 
    2758             :             /* determine the first sor and set eor to it because of the loop body (sor=eor there) */
    2759           0 :             level=GET_PARALEVEL(pBiDi, 0);
    2760           0 :             nextLevel=levels[0];
    2761           0 :             if(level<nextLevel) {
    2762           0 :                 eor=GET_LR_FROM_LEVEL(nextLevel);
    2763             :             } else {
    2764           0 :                 eor=GET_LR_FROM_LEVEL(level);
    2765             :             }
    2766             : 
    2767           0 :             do {
    2768             :                 /* determine start and limit of the run (end points just behind the run) */
    2769             : 
    2770             :                 /* the values for this run's start are the same as for the previous run's end */
    2771           0 :                 start=limit;
    2772           0 :                 level=nextLevel;
    2773           0 :                 if((start>0) && (dirProps[start-1]==B)) {
    2774             :                     /* except if this is a new paragraph, then set sor = para level */
    2775           0 :                     sor=GET_LR_FROM_LEVEL(GET_PARALEVEL(pBiDi, start));
    2776             :                 } else {
    2777           0 :                     sor=eor;
    2778             :                 }
    2779             : 
    2780             :                 /* search for the limit of this run */
    2781           0 :                 while((++limit<length) &&
    2782           0 :                       ((levels[limit]==level) ||
    2783           0 :                        (DIRPROP_FLAG(dirProps[limit])&MASK_BN_EXPLICIT))) {}
    2784             : 
    2785             :                 /* get the correct level of the next run */
    2786           0 :                 if(limit<length) {
    2787           0 :                     nextLevel=levels[limit];
    2788             :                 } else {
    2789           0 :                     nextLevel=GET_PARALEVEL(pBiDi, length-1);
    2790             :                 }
    2791             : 
    2792             :                 /* determine eor from max(level, nextLevel); sor is last run's eor */
    2793           0 :                 if(NO_OVERRIDE(level)<NO_OVERRIDE(nextLevel)) {
    2794           0 :                     eor=GET_LR_FROM_LEVEL(nextLevel);
    2795             :                 } else {
    2796           0 :                     eor=GET_LR_FROM_LEVEL(level);
    2797             :                 }
    2798             : 
    2799             :                 /* if the run consists of overridden directional types, then there
    2800             :                    are no implicit types to be resolved */
    2801           0 :                 if(!(level&UBIDI_LEVEL_OVERRIDE)) {
    2802           0 :                     resolveImplicitLevels(pBiDi, start, limit, sor, eor);
    2803             :                 } else {
    2804             :                     /* remove the UBIDI_LEVEL_OVERRIDE flags */
    2805           0 :                     do {
    2806           0 :                         levels[start++]&=~UBIDI_LEVEL_OVERRIDE;
    2807           0 :                     } while(start<limit);
    2808             :                 }
    2809           0 :             } while(limit<length);
    2810             :         }
    2811             :         /* check if we got any memory shortage while adding insert points */
    2812           0 :         if (U_FAILURE(pBiDi->insertPoints.errorCode))
    2813             :         {
    2814           0 :             *pErrorCode=pBiDi->insertPoints.errorCode;
    2815           0 :             return;
    2816             :         }
    2817             :         /* reset the embedding levels for some non-graphic characters (L1), (X9) */
    2818           0 :         adjustWSLevels(pBiDi);
    2819           0 :         break;
    2820             :     }
    2821             :     /* add RLM for inverse Bidi with contextual orientation resolving
    2822             :      * to RTL which would not round-trip otherwise
    2823             :      */
    2824           0 :     if((pBiDi->defaultParaLevel>0) &&
    2825           0 :        (pBiDi->reorderingOptions & UBIDI_OPTION_INSERT_MARKS) &&
    2826           0 :        ((pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_LIKE_DIRECT) ||
    2827           0 :         (pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL))) {
    2828             :         int32_t i, j, start, last;
    2829             :         UBiDiLevel level;
    2830             :         DirProp dirProp;
    2831           0 :         for(i=0; i<pBiDi->paraCount; i++) {
    2832           0 :             last=(pBiDi->paras[i].limit)-1;
    2833           0 :             level=pBiDi->paras[i].level;
    2834           0 :             if(level==0)
    2835           0 :                 continue;           /* LTR paragraph */
    2836           0 :             start= i==0 ? 0 : pBiDi->paras[i-1].limit;
    2837           0 :             for(j=last; j>=start; j--) {
    2838           0 :                 dirProp=dirProps[j];
    2839           0 :                 if(dirProp==L) {
    2840           0 :                     if(j<last) {
    2841           0 :                         while(dirProps[last]==B) {
    2842           0 :                             last--;
    2843             :                         }
    2844             :                     }
    2845           0 :                     addPoint(pBiDi, last, RLM_BEFORE);
    2846           0 :                     break;
    2847             :                 }
    2848           0 :                 if(DIRPROP_FLAG(dirProp) & MASK_R_AL) {
    2849           0 :                     break;
    2850             :                 }
    2851             :             }
    2852             :         }
    2853             :     }
    2854             : 
    2855           0 :     if(pBiDi->reorderingOptions & UBIDI_OPTION_REMOVE_CONTROLS) {
    2856           0 :         pBiDi->resultLength -= pBiDi->controlCount;
    2857             :     } else {
    2858           0 :         pBiDi->resultLength += pBiDi->insertPoints.size;
    2859             :     }
    2860           0 :     setParaSuccess(pBiDi);              /* mark successful setPara */
    2861             : }
    2862             : 
    2863             : U_CAPI void U_EXPORT2
    2864           0 : ubidi_orderParagraphsLTR(UBiDi *pBiDi, UBool orderParagraphsLTR) {
    2865           0 :     if(pBiDi!=NULL) {
    2866           0 :         pBiDi->orderParagraphsLTR=orderParagraphsLTR;
    2867             :     }
    2868           0 : }
    2869             : 
    2870             : U_CAPI UBool U_EXPORT2
    2871           0 : ubidi_isOrderParagraphsLTR(UBiDi *pBiDi) {
    2872           0 :     if(pBiDi!=NULL) {
    2873           0 :         return pBiDi->orderParagraphsLTR;
    2874             :     } else {
    2875           0 :         return FALSE;
    2876             :     }
    2877             : }
    2878             : 
    2879             : U_CAPI UBiDiDirection U_EXPORT2
    2880           0 : ubidi_getDirection(const UBiDi *pBiDi) {
    2881           0 :     if(IS_VALID_PARA_OR_LINE(pBiDi)) {
    2882           0 :         return pBiDi->direction;
    2883             :     } else {
    2884           0 :         return UBIDI_LTR;
    2885             :     }
    2886             : }
    2887             : 
    2888             : U_CAPI const UChar * U_EXPORT2
    2889           0 : ubidi_getText(const UBiDi *pBiDi) {
    2890           0 :     if(IS_VALID_PARA_OR_LINE(pBiDi)) {
    2891           0 :         return pBiDi->text;
    2892             :     } else {
    2893           0 :         return NULL;
    2894             :     }
    2895             : }
    2896             : 
    2897             : U_CAPI int32_t U_EXPORT2
    2898           0 : ubidi_getLength(const UBiDi *pBiDi) {
    2899           0 :     if(IS_VALID_PARA_OR_LINE(pBiDi)) {
    2900           0 :         return pBiDi->originalLength;
    2901             :     } else {
    2902           0 :         return 0;
    2903             :     }
    2904             : }
    2905             : 
    2906             : U_CAPI int32_t U_EXPORT2
    2907           0 : ubidi_getProcessedLength(const UBiDi *pBiDi) {
    2908           0 :     if(IS_VALID_PARA_OR_LINE(pBiDi)) {
    2909           0 :         return pBiDi->length;
    2910             :     } else {
    2911           0 :         return 0;
    2912             :     }
    2913             : }
    2914             : 
    2915             : U_CAPI int32_t U_EXPORT2
    2916           0 : ubidi_getResultLength(const UBiDi *pBiDi) {
    2917           0 :     if(IS_VALID_PARA_OR_LINE(pBiDi)) {
    2918           0 :         return pBiDi->resultLength;
    2919             :     } else {
    2920           0 :         return 0;
    2921             :     }
    2922             : }
    2923             : 
    2924             : /* paragraphs API functions ------------------------------------------------- */
    2925             : 
    2926             : U_CAPI UBiDiLevel U_EXPORT2
    2927           0 : ubidi_getParaLevel(const UBiDi *pBiDi) {
    2928           0 :     if(IS_VALID_PARA_OR_LINE(pBiDi)) {
    2929           0 :         return pBiDi->paraLevel;
    2930             :     } else {
    2931           0 :         return 0;
    2932             :     }
    2933             : }
    2934             : 
    2935             : U_CAPI int32_t U_EXPORT2
    2936           0 : ubidi_countParagraphs(UBiDi *pBiDi) {
    2937           0 :     if(!IS_VALID_PARA_OR_LINE(pBiDi)) {
    2938           0 :         return 0;
    2939             :     } else {
    2940           0 :         return pBiDi->paraCount;
    2941             :     }
    2942             : }
    2943             : 
    2944             : U_CAPI void U_EXPORT2
    2945           0 : ubidi_getParagraphByIndex(const UBiDi *pBiDi, int32_t paraIndex,
    2946             :                           int32_t *pParaStart, int32_t *pParaLimit,
    2947             :                           UBiDiLevel *pParaLevel, UErrorCode *pErrorCode) {
    2948             :     int32_t paraStart;
    2949             : 
    2950             :     /* check the argument values */
    2951           0 :     RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
    2952           0 :     RETURN_VOID_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode);
    2953           0 :     RETURN_VOID_IF_BAD_RANGE(paraIndex, 0, pBiDi->paraCount, *pErrorCode);
    2954             : 
    2955           0 :     pBiDi=pBiDi->pParaBiDi;             /* get Para object if Line object */
    2956           0 :     if(paraIndex) {
    2957           0 :         paraStart=pBiDi->paras[paraIndex-1].limit;
    2958             :     } else {
    2959           0 :         paraStart=0;
    2960             :     }
    2961           0 :     if(pParaStart!=NULL) {
    2962           0 :         *pParaStart=paraStart;
    2963             :     }
    2964           0 :     if(pParaLimit!=NULL) {
    2965           0 :         *pParaLimit=pBiDi->paras[paraIndex].limit;
    2966             :     }
    2967           0 :     if(pParaLevel!=NULL) {
    2968           0 :         *pParaLevel=GET_PARALEVEL(pBiDi, paraStart);
    2969             :     }
    2970             : }
    2971             : 
    2972             : U_CAPI int32_t U_EXPORT2
    2973           0 : ubidi_getParagraph(const UBiDi *pBiDi, int32_t charIndex,
    2974             :                           int32_t *pParaStart, int32_t *pParaLimit,
    2975             :                           UBiDiLevel *pParaLevel, UErrorCode *pErrorCode) {
    2976             :     int32_t paraIndex;
    2977             : 
    2978             :     /* check the argument values */
    2979             :     /* pErrorCode will be checked by the call to ubidi_getParagraphByIndex */
    2980           0 :     RETURN_IF_NULL_OR_FAILING_ERRCODE(pErrorCode, -1);
    2981           0 :     RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode, -1);
    2982           0 :     pBiDi=pBiDi->pParaBiDi;             /* get Para object if Line object */
    2983           0 :     RETURN_IF_BAD_RANGE(charIndex, 0, pBiDi->length, *pErrorCode, -1);
    2984             : 
    2985           0 :     for(paraIndex=0; charIndex>=pBiDi->paras[paraIndex].limit; paraIndex++);
    2986           0 :     ubidi_getParagraphByIndex(pBiDi, paraIndex, pParaStart, pParaLimit, pParaLevel, pErrorCode);
    2987           0 :     return paraIndex;
    2988             : }
    2989             : 
    2990             : U_CAPI void U_EXPORT2
    2991           0 : ubidi_setClassCallback(UBiDi *pBiDi, UBiDiClassCallback *newFn,
    2992             :                        const void *newContext, UBiDiClassCallback **oldFn,
    2993             :                        const void **oldContext, UErrorCode *pErrorCode)
    2994             : {
    2995           0 :     RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
    2996           0 :     if(pBiDi==NULL) {
    2997           0 :         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    2998           0 :         return;
    2999             :     }
    3000           0 :     if( oldFn )
    3001             :     {
    3002           0 :         *oldFn = pBiDi->fnClassCallback;
    3003             :     }
    3004           0 :     if( oldContext )
    3005             :     {
    3006           0 :         *oldContext = pBiDi->coClassCallback;
    3007             :     }
    3008           0 :     pBiDi->fnClassCallback = newFn;
    3009           0 :     pBiDi->coClassCallback = newContext;
    3010             : }
    3011             : 
    3012             : U_CAPI void U_EXPORT2
    3013           0 : ubidi_getClassCallback(UBiDi *pBiDi, UBiDiClassCallback **fn, const void **context)
    3014             : {
    3015           0 :     if(pBiDi==NULL) {
    3016           0 :         return;
    3017             :     }
    3018           0 :     if( fn )
    3019             :     {
    3020           0 :         *fn = pBiDi->fnClassCallback;
    3021             :     }
    3022           0 :     if( context )
    3023             :     {
    3024           0 :         *context = pBiDi->coClassCallback;
    3025             :     }
    3026             : }
    3027             : 
    3028             : U_CAPI UCharDirection U_EXPORT2
    3029           0 : ubidi_getCustomizedClass(UBiDi *pBiDi, UChar32 c)
    3030             : {
    3031             :     UCharDirection dir;
    3032             : 
    3033           0 :     if( pBiDi->fnClassCallback == NULL ||
    3034           0 :         (dir = (*pBiDi->fnClassCallback)(pBiDi->coClassCallback, c)) == U_BIDI_CLASS_DEFAULT )
    3035             :     {
    3036           0 :         dir = ubidi_getClass(pBiDi->bdp, c);
    3037             :     }
    3038           0 :     if(dir >= U_CHAR_DIRECTION_COUNT) {
    3039           0 :         dir = (UCharDirection)ON;
    3040             :     }
    3041           0 :     return dir;
    3042             : }

Generated by: LCOV version 1.13