LCOV - code coverage report
Current view: top level - intl/icu/source/common - ubiditransform.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 161 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 14 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             : ******************************************************************************
       3             : *
       4             : * © 2016 and later: Unicode, Inc. and others.
       5             : * License & terms of use: http://www.unicode.org/copyright.html
       6             : *
       7             : ******************************************************************************
       8             : *   file name:  ubiditransform.c
       9             : *   encoding:   UTF-8
      10             : *   tab size:   8 (not used)
      11             : *   indentation:4
      12             : *
      13             : *   created on: 2016jul24
      14             : *   created by: Lina Kemmel
      15             : *
      16             : */
      17             : 
      18             : #include "cmemory.h"
      19             : #include "unicode/ubidi.h"
      20             : #include "unicode/ustring.h"
      21             : #include "unicode/ushape.h"
      22             : #include "unicode/utf16.h"
      23             : #include "ustr_imp.h"
      24             : #include "unicode/ubiditransform.h"
      25             : 
      26             : /* Some convenience defines */
      27             : #define LTR                     UBIDI_LTR
      28             : #define RTL                     UBIDI_RTL
      29             : #define LOGICAL                 UBIDI_LOGICAL
      30             : #define VISUAL                  UBIDI_VISUAL
      31             : #define SHAPE_LOGICAL           U_SHAPE_TEXT_DIRECTION_LOGICAL
      32             : #define SHAPE_VISUAL            U_SHAPE_TEXT_DIRECTION_VISUAL_LTR
      33             : 
      34             : #define CHECK_LEN(STR, LEN, ERROR) { \
      35             :         if (LEN == 0) return 0; \
      36             :         if (LEN < -1) { *(ERROR) = U_ILLEGAL_ARGUMENT_ERROR; return 0; } \
      37             :         if (LEN == -1) LEN = u_strlen(STR); \
      38             :     } 
      39             : 
      40             : #define MAX_ACTIONS     7
      41             : 
      42             : /**
      43             :  * Typedef for a pointer to a function, which performs some operation (such as
      44             :  * reordering, setting "inverse" mode, character mirroring, etc.). Return value
      45             :  * indicates whether the text was changed in the course of this operation or
      46             :  * not.
      47             :  */
      48             : typedef UBool (*UBiDiAction)(UBiDiTransform *, UErrorCode *);
      49             : 
      50             : /**
      51             :  * Structure that holds a predefined reordering scheme, including the following
      52             :  * information:
      53             :  * <ul>
      54             :  * <li>an input base direction,</li>
      55             :  * <li>an input order,</li>
      56             :  * <li>an output base direction,</li>
      57             :  * <li>an output order,</li>
      58             :  * <li>a digit shaping direction,</li>
      59             :  * <li>a letter shaping direction,</li>
      60             :  * <li>a base direction that should be applied when the reordering engine is
      61             :  *     invoked (which can not always be derived from the caller-defined
      62             :  *     options),</li>
      63             :  * <li>an array of pointers to functions that accomplish the bidi layout
      64             :  *     transformation.</li>
      65             :  * </ul>
      66             :  */
      67             : typedef struct {
      68             :     UBiDiLevel        inLevel;               /* input level */
      69             :     UBiDiOrder        inOrder;               /* input order */
      70             :     UBiDiLevel        outLevel;              /* output level */
      71             :     UBiDiOrder        outOrder;              /* output order */
      72             :     uint32_t          digitsDir;             /* digit shaping direction */
      73             :     uint32_t          lettersDir;            /* letter shaping direction */
      74             :     UBiDiLevel        baseLevel;             /* paragraph level to be used with setPara */
      75             :     const UBiDiAction actions[MAX_ACTIONS];  /* array of pointers to functions carrying out the transformation */
      76             : } ReorderingScheme;
      77             : 
      78             : struct UBiDiTransform {
      79             :     UBiDi                   *pBidi;             /* pointer to a UBiDi object */
      80             :     const ReorderingScheme  *pActiveScheme;     /* effective reordering scheme */
      81             :     UChar                   *src;               /* input text */
      82             :     UChar                   *dest;              /* output text */
      83             :     uint32_t                srcLength;          /* input text length - not really needed as we are zero-terminated and can u_strlen */
      84             :     uint32_t                srcSize;            /* input text capacity excluding the trailing zero */
      85             :     uint32_t                destSize;           /* output text capacity */
      86             :     uint32_t                *pDestLength;       /* number of UChars written to dest */
      87             :     uint32_t                reorderingOptions;  /* reordering options - currently only suppot DO_MIRRORING */
      88             :     uint32_t                digits;             /* digit option for ArabicShaping */
      89             :     uint32_t                letters;            /* letter option for ArabicShaping */
      90             : };
      91             : 
      92             : U_DRAFT UBiDiTransform* U_EXPORT2
      93           0 : ubiditransform_open(UErrorCode *pErrorCode)
      94             : {
      95           0 :     UBiDiTransform *pBiDiTransform = NULL;
      96           0 :     if (U_SUCCESS(*pErrorCode)) {
      97           0 :         pBiDiTransform = (UBiDiTransform*) uprv_calloc(1, sizeof(UBiDiTransform));
      98           0 :         if (pBiDiTransform == NULL) {
      99           0 :             *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
     100             :         }
     101             :     }
     102           0 :     return pBiDiTransform;
     103             : }
     104             : 
     105             : U_DRAFT void U_EXPORT2
     106           0 : ubiditransform_close(UBiDiTransform *pBiDiTransform)
     107             : {
     108           0 :     if (pBiDiTransform != NULL) {
     109           0 :         if (pBiDiTransform->pBidi != NULL) {
     110           0 :             ubidi_close(pBiDiTransform->pBidi);
     111             :         }
     112           0 :         if (pBiDiTransform->src != NULL) {
     113           0 :             uprv_free(pBiDiTransform->src);
     114             :         }
     115           0 :         uprv_free(pBiDiTransform);
     116             :     }
     117           0 : }
     118             : 
     119             : /**
     120             :  * Performs Bidi resolution of text.
     121             :  * 
     122             :  * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.
     123             :  * @param pErrorCode Pointer to the error code value.
     124             :  *
     125             :  * @return Whether or not this function modifies the text. Besides the return
     126             :  * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
     127             :  */
     128             : static UBool
     129           0 : action_resolve(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
     130             : {
     131           0 :     ubidi_setPara(pTransform->pBidi, pTransform->src, pTransform->srcLength,
     132           0 :             pTransform->pActiveScheme->baseLevel, NULL, pErrorCode);
     133           0 :     return FALSE;
     134             : }
     135             : 
     136             : /**
     137             :  * Performs basic reordering of text (Logical -> Visual LTR).
     138             :  * 
     139             :  * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.
     140             :  * @param pErrorCode Pointer to the error code value.
     141             :  *
     142             :  * @return Whether or not this function modifies the text. Besides the return
     143             :  * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
     144             :  */
     145             : static UBool
     146           0 : action_reorder(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
     147             : {
     148           0 :     ubidi_writeReordered(pTransform->pBidi, pTransform->dest, pTransform->destSize,
     149           0 :             pTransform->reorderingOptions, pErrorCode);
     150             : 
     151           0 :     *pTransform->pDestLength = pTransform->srcLength;
     152           0 :     pTransform->reorderingOptions = UBIDI_REORDER_DEFAULT;
     153           0 :     return TRUE;
     154             : }
     155             : 
     156             : /**
     157             :  * Sets "inverse" mode on the <code>UBiDi</code> object.
     158             :  * 
     159             :  * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.
     160             :  * @param pErrorCode Pointer to the error code value.
     161             :  *
     162             :  * @return Whether or not this function modifies the text. Besides the return
     163             :  * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
     164             :  */
     165             : static UBool
     166           0 : action_setInverse(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
     167             : {
     168             :     (void)pErrorCode;
     169           0 :     ubidi_setInverse(pTransform->pBidi, TRUE);
     170           0 :     ubidi_setReorderingMode(pTransform->pBidi, UBIDI_REORDER_INVERSE_LIKE_DIRECT);
     171           0 :     return FALSE;
     172             : }
     173             : 
     174             : /**
     175             :  * Sets "runs only" reordering mode indicating a Logical LTR <-> Logical RTL
     176             :  * transformation.
     177             :  * 
     178             :  * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.
     179             :  * @param pErrorCode Pointer to the error code value.
     180             :  *
     181             :  * @return Whether or not this function modifies the text. Besides the return
     182             :  * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
     183             :  */
     184             : static UBool
     185           0 : action_setRunsOnly(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
     186             : {
     187             :     (void)pErrorCode;
     188           0 :     ubidi_setReorderingMode(pTransform->pBidi, UBIDI_REORDER_RUNS_ONLY);
     189           0 :     return FALSE;
     190             : }
     191             : 
     192             : /**
     193             :  * Performs string reverse.
     194             :  * 
     195             :  * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.
     196             :  * @param pErrorCode Pointer to the error code value.
     197             :  *
     198             :  * @return Whether or not this function modifies the text. Besides the return
     199             :  * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
     200             :  */
     201             : static UBool
     202           0 : action_reverse(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
     203             : {
     204           0 :     ubidi_writeReverse(pTransform->src, pTransform->srcLength,
     205           0 :             pTransform->dest, pTransform->destSize,
     206           0 :             UBIDI_REORDER_DEFAULT, pErrorCode);
     207           0 :     *pTransform->pDestLength = pTransform->srcLength;
     208           0 :     return TRUE;
     209             : }
     210             : 
     211             : /**
     212             :  * Applies a new value to the text that serves as input at the current
     213             :  * processing step. This value is identical to the original one when we begin
     214             :  * the processing, but usually changes as the transformation progresses.
     215             :  * 
     216             :  * @param pTransform A pointer to the <code>UBiDiTransform</code> structure.
     217             :  * @param newSrc A pointer whose value is to be used as input text.
     218             :  * @param newLength A length of the new text in <code>UChar</code>s.
     219             :  * @param newSize A new source capacity in <code>UChar</code>s.
     220             :  * @param pErrorCode Pointer to the error code value.
     221             :  */
     222             : static void
     223           0 : updateSrc(UBiDiTransform *pTransform, const UChar *newSrc, uint32_t newLength,
     224             :         uint32_t newSize, UErrorCode *pErrorCode)
     225             : {
     226           0 :     if (newSize < newLength) {
     227           0 :         *pErrorCode = U_BUFFER_OVERFLOW_ERROR;
     228           0 :         return;
     229             :     }
     230           0 :     if (newSize > pTransform->srcSize) {
     231           0 :         newSize += 50; // allocate slightly more than needed right now
     232           0 :         if (pTransform->src != NULL) {
     233           0 :             uprv_free(pTransform->src);
     234           0 :             pTransform->src = NULL;
     235             :         }
     236           0 :         pTransform->src = (UChar *)uprv_malloc(newSize * sizeof(UChar));
     237           0 :         if (pTransform->src == NULL) {
     238           0 :             *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
     239             :             //pTransform->srcLength = pTransform->srcSize = 0;
     240           0 :             return;
     241             :         }
     242           0 :         pTransform->srcSize = newSize;
     243             :     }
     244           0 :     u_strncpy(pTransform->src, newSrc, newLength);
     245           0 :     pTransform->srcLength = u_terminateUChars(pTransform->src,
     246           0 :                 pTransform->srcSize, newLength, pErrorCode);
     247             : }
     248             : 
     249             : /**
     250             :  * Calls a lower level shaping function.
     251             :  * 
     252             :  * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.
     253             :  * @param options Shaping options.
     254             :  * @param pErrorCode Pointer to the error code value.
     255             :  */
     256             : static void
     257           0 : doShape(UBiDiTransform *pTransform, uint32_t options, UErrorCode *pErrorCode)
     258             : {
     259           0 :     *pTransform->pDestLength = u_shapeArabic(pTransform->src,
     260           0 :             pTransform->srcLength, pTransform->dest, pTransform->destSize,
     261             :             options, pErrorCode);
     262           0 : }
     263             : 
     264             : /**
     265             :  * Performs digit and letter shaping.
     266             :  * 
     267             :  * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.
     268             :  * @param pErrorCode Pointer to the error code value.
     269             :  *
     270             :  * @return Whether or not this function modifies the text. Besides the return
     271             :  * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
     272             :  */
     273             : static UBool
     274           0 : action_shapeArabic(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
     275             : {
     276           0 :     if ((pTransform->letters | pTransform->digits) == 0) {
     277           0 :         return FALSE;
     278             :     }
     279           0 :     if (pTransform->pActiveScheme->lettersDir == pTransform->pActiveScheme->digitsDir) {
     280           0 :         doShape(pTransform, pTransform->letters | pTransform->digits | pTransform->pActiveScheme->lettersDir,
     281           0 :                 pErrorCode);
     282             :     } else {
     283           0 :         doShape(pTransform, pTransform->digits | pTransform->pActiveScheme->digitsDir, pErrorCode);
     284           0 :         if (U_SUCCESS(*pErrorCode)) {
     285           0 :             updateSrc(pTransform, pTransform->dest, *pTransform->pDestLength,
     286           0 :                     *pTransform->pDestLength, pErrorCode);
     287           0 :             doShape(pTransform, pTransform->letters | pTransform->pActiveScheme->lettersDir,
     288           0 :                     pErrorCode);
     289             :         }
     290             :     }
     291           0 :     return TRUE;
     292             : }
     293             : 
     294             : /**
     295             :  * Performs character mirroring.
     296             :  * 
     297             :  * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.
     298             :  * @param pErrorCode Pointer to the error code value.
     299             :  *
     300             :  * @return Whether or not this function modifies the text. Besides the return
     301             :  * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
     302             :  */
     303             : static UBool
     304           0 : action_mirror(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
     305             : {
     306             :     UChar32 c;
     307           0 :     uint32_t i = 0, j = 0;
     308           0 :     if (0 == (pTransform->reorderingOptions & UBIDI_DO_MIRRORING)) {
     309           0 :         return FALSE;
     310             :     }
     311           0 :     if (pTransform->destSize < pTransform->srcLength) {
     312           0 :         *pErrorCode = U_BUFFER_OVERFLOW_ERROR;
     313           0 :         return FALSE;
     314             :     }
     315           0 :     do {
     316           0 :         UBool isOdd = ubidi_getLevelAt(pTransform->pBidi, i) & 1;
     317           0 :         U16_NEXT(pTransform->src, i, pTransform->srcLength, c); 
     318           0 :         U16_APPEND_UNSAFE(pTransform->dest, j, isOdd ? u_charMirror(c) : c);
     319           0 :     } while (i < pTransform->srcLength);
     320             :     
     321           0 :     *pTransform->pDestLength = pTransform->srcLength;
     322           0 :     pTransform->reorderingOptions = UBIDI_REORDER_DEFAULT;
     323           0 :     return TRUE;
     324             : }
     325             : 
     326             : /**
     327             :  * All possible reordering schemes.
     328             :  *
     329             :  */
     330             : static const ReorderingScheme Schemes[] =
     331             : {
     332             :     /* 0: Logical LTR => Visual LTR */
     333             :     {LTR, LOGICAL, LTR, VISUAL, SHAPE_LOGICAL, SHAPE_LOGICAL, LTR,
     334             :             {action_shapeArabic, action_resolve, action_reorder, NULL}},
     335             :     /* 1: Logical RTL => Visual LTR */
     336             :     {RTL, LOGICAL, LTR, VISUAL, SHAPE_LOGICAL, SHAPE_VISUAL, RTL,
     337             :             {action_resolve, action_reorder, action_shapeArabic, NULL}},
     338             :     /* 2: Logical LTR => Visual RTL */
     339             :     {LTR, LOGICAL, RTL, VISUAL, SHAPE_LOGICAL, SHAPE_LOGICAL, LTR,
     340             :             {action_shapeArabic, action_resolve, action_reorder, action_reverse, NULL}},
     341             :     /* 3: Logical RTL => Visual RTL */
     342             :     {RTL, LOGICAL, RTL, VISUAL, SHAPE_LOGICAL, SHAPE_VISUAL, RTL,
     343             :             {action_resolve, action_reorder, action_shapeArabic, action_reverse, NULL}},
     344             :     /* 4: Visual LTR => Logical RTL */
     345             :     {LTR, VISUAL, RTL, LOGICAL, SHAPE_LOGICAL, SHAPE_VISUAL, RTL,
     346             :             {action_shapeArabic, action_setInverse, action_resolve, action_reorder, NULL}},
     347             :     /* 5: Visual RTL => Logical RTL */
     348             :     {RTL, VISUAL, RTL, LOGICAL, SHAPE_LOGICAL, SHAPE_VISUAL, RTL,
     349             :             {action_reverse, action_shapeArabic, action_setInverse, action_resolve, action_reorder, NULL}},
     350             :     /* 6: Visual LTR => Logical LTR */
     351             :     {LTR, VISUAL, LTR, LOGICAL, SHAPE_LOGICAL, SHAPE_LOGICAL, LTR,
     352             :             {action_setInverse, action_resolve, action_reorder, action_shapeArabic, NULL}},
     353             :     /* 7: Visual RTL => Logical LTR */
     354             :     {RTL, VISUAL, LTR, LOGICAL, SHAPE_LOGICAL, SHAPE_LOGICAL, LTR,
     355             :             {action_reverse, action_setInverse, action_resolve, action_reorder, action_shapeArabic, NULL}},
     356             :     /* 8: Logical LTR => Logical RTL */
     357             :     {LTR, LOGICAL, RTL, LOGICAL, SHAPE_LOGICAL, SHAPE_LOGICAL, LTR,
     358             :             {action_shapeArabic, action_resolve, action_mirror, action_setRunsOnly, action_resolve, action_reorder, NULL}},
     359             :     /* 9: Logical RTL => Logical LTR */
     360             :     {RTL, LOGICAL, LTR, LOGICAL, SHAPE_LOGICAL, SHAPE_LOGICAL, RTL,
     361             :             {action_resolve, action_mirror, action_setRunsOnly, action_resolve, action_reorder, action_shapeArabic, NULL}},
     362             :     /* 10: Visual LTR => Visual RTL */
     363             :     {LTR, VISUAL, RTL, VISUAL, SHAPE_LOGICAL, SHAPE_VISUAL, LTR,
     364             :             {action_shapeArabic, action_setInverse, action_resolve, action_mirror, action_reverse, NULL}},
     365             :     /* 11: Visual RTL => Visual LTR */
     366             :     {RTL, VISUAL, LTR, VISUAL, SHAPE_LOGICAL, SHAPE_VISUAL, LTR,
     367             :             {action_reverse, action_shapeArabic, action_setInverse, action_resolve, action_mirror, NULL}},
     368             :     /* 12: Logical LTR => Logical LTR */
     369             :     {LTR, LOGICAL, LTR, LOGICAL, SHAPE_LOGICAL, SHAPE_LOGICAL, LTR,
     370             :             {action_resolve, action_mirror, action_shapeArabic, NULL}},
     371             :     /* 13: Logical RTL => Logical RTL */
     372             :     {RTL, LOGICAL, RTL, LOGICAL, SHAPE_VISUAL, SHAPE_LOGICAL, RTL,
     373             :             {action_resolve, action_mirror, action_shapeArabic, NULL}},
     374             :     /* 14: Visual LTR => Visual LTR */
     375             :     {LTR, VISUAL, LTR, VISUAL, SHAPE_LOGICAL, SHAPE_VISUAL, LTR,
     376             :             {action_resolve, action_mirror, action_shapeArabic, NULL}},
     377             :     /* 15: Visual RTL => Visual RTL */
     378             :     {RTL, VISUAL, RTL, VISUAL, SHAPE_LOGICAL, SHAPE_VISUAL, LTR,
     379             :             {action_reverse, action_resolve, action_mirror, action_shapeArabic, action_reverse, NULL}}
     380             : };
     381             : 
     382             : static const uint32_t nSchemes = sizeof(Schemes) / sizeof(*Schemes);
     383             : 
     384             : /**
     385             :  * When the direction option is <code>UBIDI_DEFAULT_LTR</code> or
     386             :  * <code>UBIDI_DEFAULT_RTL</code>, resolve the base direction according to that
     387             :  * of the first strong bidi character.
     388             :  */
     389             : static void
     390           0 : resolveBaseDirection(const UChar *text, uint32_t length,
     391             :         UBiDiLevel *pInLevel, UBiDiLevel *pOutLevel)
     392             : {
     393           0 :     switch (*pInLevel) {
     394             :         case UBIDI_DEFAULT_LTR:
     395             :         case UBIDI_DEFAULT_RTL: {
     396           0 :             UBiDiLevel level = ubidi_getBaseDirection(text, length);
     397           0 :             *pInLevel = level != UBIDI_NEUTRAL ? level
     398           0 :                     : *pInLevel == UBIDI_DEFAULT_RTL ? RTL : LTR;
     399           0 :             break;
     400             :         }
     401             :         default:
     402           0 :             *pInLevel &= 1;
     403           0 :             break;
     404             :     }
     405           0 :     switch (*pOutLevel) {
     406             :         case UBIDI_DEFAULT_LTR:
     407             :         case UBIDI_DEFAULT_RTL:
     408           0 :             *pOutLevel = *pInLevel;
     409           0 :             break;
     410             :         default:
     411           0 :             *pOutLevel &= 1;
     412           0 :             break;
     413             :     }
     414           0 : }
     415             : 
     416             : /**
     417             :  * Finds a valid <code>ReorderingScheme</code> matching the
     418             :  * caller-defined scheme.
     419             :  * 
     420             :  * @return A valid <code>ReorderingScheme</code> object or NULL
     421             :  */
     422             : static const ReorderingScheme*
     423           0 : findMatchingScheme(UBiDiLevel inLevel, UBiDiLevel outLevel,
     424             :         UBiDiOrder inOrder, UBiDiOrder outOrder)
     425             : {
     426             :     uint32_t i;
     427           0 :     for (i = 0; i < nSchemes; i++) {
     428           0 :         const ReorderingScheme *pScheme = Schemes + i;
     429           0 :         if (inLevel == pScheme->inLevel && outLevel == pScheme->outLevel
     430           0 :                 && inOrder == pScheme->inOrder && outOrder == pScheme->outOrder) {
     431           0 :             return pScheme;
     432             :         }
     433             :     }
     434           0 :     return NULL;
     435             : }
     436             : 
     437             : U_DRAFT uint32_t U_EXPORT2
     438           0 : ubiditransform_transform(UBiDiTransform *pBiDiTransform,
     439             :             const UChar *src, int32_t srcLength,
     440             :             UChar *dest, int32_t destSize,
     441             :             UBiDiLevel inParaLevel, UBiDiOrder inOrder,
     442             :             UBiDiLevel outParaLevel, UBiDiOrder outOrder,
     443             :             UBiDiMirroring doMirroring, uint32_t shapingOptions,
     444             :             UErrorCode *pErrorCode)
     445             : {
     446           0 :     uint32_t destLength = 0;
     447           0 :     UBool textChanged = FALSE;
     448           0 :     const UBiDiTransform *pOrigTransform = pBiDiTransform;
     449           0 :     const UBiDiAction *action = NULL;
     450             : 
     451           0 :     if (U_FAILURE(*pErrorCode)) {
     452           0 :         return 0;
     453             :     }
     454           0 :     if (src == NULL || dest == NULL) {
     455           0 :         *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
     456           0 :         return 0;
     457             :     }
     458           0 :     CHECK_LEN(src, srcLength, pErrorCode);
     459           0 :     CHECK_LEN(dest, destSize, pErrorCode);
     460             : 
     461           0 :     if (pBiDiTransform == NULL) {
     462           0 :         pBiDiTransform = ubiditransform_open(pErrorCode);
     463           0 :         if (U_FAILURE(*pErrorCode)) {
     464           0 :             return 0;
     465             :         }
     466             :     }
     467             :     /* Current limitation: in multiple paragraphs will be resolved according
     468             :        to the 1st paragraph */
     469           0 :     resolveBaseDirection(src, srcLength, &inParaLevel, &outParaLevel);
     470             : 
     471           0 :     pBiDiTransform->pActiveScheme = findMatchingScheme(inParaLevel, outParaLevel,
     472             :             inOrder, outOrder);
     473           0 :     if (pBiDiTransform->pActiveScheme == NULL) {
     474           0 :         goto cleanup;
     475             :     }
     476           0 :     pBiDiTransform->reorderingOptions = doMirroring ? UBIDI_DO_MIRRORING
     477             :             : UBIDI_REORDER_DEFAULT;
     478             : 
     479             :     /* Ignore TEXT_DIRECTION_* flags, as we apply our own depending on the text
     480             :        scheme at the time shaping is invoked. */
     481           0 :     shapingOptions &= ~U_SHAPE_TEXT_DIRECTION_MASK;
     482           0 :     pBiDiTransform->digits = shapingOptions & ~U_SHAPE_LETTERS_MASK;
     483           0 :     pBiDiTransform->letters = shapingOptions & ~U_SHAPE_DIGITS_MASK;
     484             : 
     485           0 :     updateSrc(pBiDiTransform, src, srcLength, destSize > srcLength ? destSize : srcLength, pErrorCode);
     486           0 :     if (U_FAILURE(*pErrorCode)) {
     487           0 :         goto cleanup;
     488             :     }
     489           0 :     if (pBiDiTransform->pBidi == NULL) {
     490           0 :         pBiDiTransform->pBidi = ubidi_openSized(0, 0, pErrorCode);
     491           0 :         if (U_FAILURE(*pErrorCode)) {
     492           0 :             goto cleanup;
     493             :         }
     494             :     }
     495           0 :     pBiDiTransform->dest = dest;
     496           0 :     pBiDiTransform->destSize = destSize;
     497           0 :     pBiDiTransform->pDestLength = &destLength;
     498             : 
     499             :     /* Checking for U_SUCCESS() within the loop to bail out on first failure. */
     500           0 :     for (action = pBiDiTransform->pActiveScheme->actions; *action && U_SUCCESS(*pErrorCode); action++) {
     501           0 :         if ((*action)(pBiDiTransform, pErrorCode)) {
     502           0 :             if (action + 1) {
     503           0 :                 updateSrc(pBiDiTransform, pBiDiTransform->dest, *pBiDiTransform->pDestLength,
     504           0 :                         *pBiDiTransform->pDestLength, pErrorCode);
     505             :             }
     506           0 :             textChanged = TRUE;
     507             :         }
     508             :     }
     509           0 :     ubidi_setInverse(pBiDiTransform->pBidi, FALSE);
     510             : 
     511           0 :     if (!textChanged && U_SUCCESS(*pErrorCode)) {
     512             :         /* Text was not changed - just copy src to dest */
     513           0 :         if (destSize < srcLength) {
     514           0 :             *pErrorCode = U_BUFFER_OVERFLOW_ERROR;
     515             :         } else {
     516           0 :             u_strncpy(dest, src, srcLength);
     517           0 :             destLength = srcLength;
     518             :         }
     519             :     }
     520             : cleanup:
     521           0 :     if (pOrigTransform != pBiDiTransform) {
     522           0 :         ubiditransform_close(pBiDiTransform);
     523             :     } else {
     524           0 :         pBiDiTransform->dest = NULL;
     525           0 :         pBiDiTransform->pDestLength = NULL;
     526           0 :         pBiDiTransform->srcLength = 0;
     527           0 :         pBiDiTransform->destSize = 0;
     528             :     }
     529           0 :     return U_FAILURE(*pErrorCode) ? 0 : destLength;
     530             : }

Generated by: LCOV version 1.13