Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/intl/icu/source/common/ubiditransform.cpp
Line
Count
Source (jump to first uncovered line)
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
0
#define LTR                     UBIDI_LTR
28
0
#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
0
#define CHECK_LEN(STR, LEN, ERROR) { \
35
0
        if (LEN == 0) return 0; \
36
0
        if (LEN < -1) { *(ERROR) = U_ILLEGAL_ARGUMENT_ERROR; return 0; } \
37
0
        if (LEN == -1) LEN = u_strlen(STR); \
38
0
    } 
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
ubiditransform_open(UErrorCode *pErrorCode)
94
0
{
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
0
        }
101
0
    }
102
0
    return pBiDiTransform;
103
0
}
104
105
U_DRAFT void U_EXPORT2
106
ubiditransform_close(UBiDiTransform *pBiDiTransform)
107
0
{
108
0
    if (pBiDiTransform != NULL) {
109
0
        if (pBiDiTransform->pBidi != NULL) {
110
0
            ubidi_close(pBiDiTransform->pBidi);
111
0
        }
112
0
        if (pBiDiTransform->src != NULL) {
113
0
            uprv_free(pBiDiTransform->src);
114
0
        }
115
0
        uprv_free(pBiDiTransform);
116
0
    }
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
action_resolve(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
130
0
{
131
0
    ubidi_setPara(pTransform->pBidi, pTransform->src, pTransform->srcLength,
132
0
            pTransform->pActiveScheme->baseLevel, NULL, pErrorCode);
133
0
    return FALSE;
134
0
}
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
action_reorder(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
147
0
{
148
0
    ubidi_writeReordered(pTransform->pBidi, pTransform->dest, pTransform->destSize,
149
0
            pTransform->reorderingOptions, pErrorCode);
150
0
151
0
    *pTransform->pDestLength = pTransform->srcLength;
152
0
    pTransform->reorderingOptions = UBIDI_REORDER_DEFAULT;
153
0
    return TRUE;
154
0
}
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
action_setInverse(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
167
0
{
168
0
    (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
0
}
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
action_setRunsOnly(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
186
0
{
187
0
    (void)pErrorCode;
188
0
    ubidi_setReorderingMode(pTransform->pBidi, UBIDI_REORDER_RUNS_ONLY);
189
0
    return FALSE;
190
0
}
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
action_reverse(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
203
0
{
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
0
}
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
updateSrc(UBiDiTransform *pTransform, const UChar *newSrc, uint32_t newLength,
224
        uint32_t newSize, UErrorCode *pErrorCode)
225
0
{
226
0
    if (newSize < newLength) {
227
0
        *pErrorCode = U_BUFFER_OVERFLOW_ERROR;
228
0
        return;
229
0
    }
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
0
        }
236
0
        pTransform->src = (UChar *)uprv_malloc(newSize * sizeof(UChar));
237
0
        if (pTransform->src == NULL) {
238
0
            *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
239
0
            //pTransform->srcLength = pTransform->srcSize = 0;
240
0
            return;
241
0
        }
242
0
        pTransform->srcSize = newSize;
243
0
    }
244
0
    u_strncpy(pTransform->src, newSrc, newLength);
245
0
    pTransform->srcLength = u_terminateUChars(pTransform->src,
246
0
        pTransform->srcSize, newLength, pErrorCode);
247
0
}
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
doShape(UBiDiTransform *pTransform, uint32_t options, UErrorCode *pErrorCode)
258
0
{
259
0
    *pTransform->pDestLength = u_shapeArabic(pTransform->src,
260
0
            pTransform->srcLength, pTransform->dest, pTransform->destSize,
261
0
            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
action_shapeArabic(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
275
0
{
276
0
    if ((pTransform->letters | pTransform->digits) == 0) {
277
0
        return FALSE;
278
0
    }
279
0
    if (pTransform->pActiveScheme->lettersDir == pTransform->pActiveScheme->digitsDir) {
280
0
        doShape(pTransform, pTransform->letters | pTransform->digits | pTransform->pActiveScheme->lettersDir,
281
0
                pErrorCode);
282
0
    } 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
0
        }
290
0
    }
291
0
    return TRUE;
292
0
}
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
action_mirror(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
305
0
{
306
0
    UChar32 c;
307
0
    uint32_t i = 0, j = 0;
308
0
    if (0 == (pTransform->reorderingOptions & UBIDI_DO_MIRRORING)) {
309
0
        return FALSE;
310
0
    }
311
0
    if (pTransform->destSize < pTransform->srcLength) {
312
0
        *pErrorCode = U_BUFFER_OVERFLOW_ERROR;
313
0
        return FALSE;
314
0
    }
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
0
    
321
0
    *pTransform->pDestLength = pTransform->srcLength;
322
0
    pTransform->reorderingOptions = UBIDI_REORDER_DEFAULT;
323
0
    return TRUE;
324
0
}
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
resolveBaseDirection(const UChar *text, uint32_t length,
391
        UBiDiLevel *pInLevel, UBiDiLevel *pOutLevel)
392
0
{
393
0
    switch (*pInLevel) {
394
0
        case UBIDI_DEFAULT_LTR:
395
0
        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
0
        }
401
0
        default:
402
0
            *pInLevel &= 1;
403
0
            break;
404
0
    }
405
0
    switch (*pOutLevel) {
406
0
        case UBIDI_DEFAULT_LTR:
407
0
        case UBIDI_DEFAULT_RTL:
408
0
            *pOutLevel = *pInLevel;
409
0
            break;
410
0
        default:
411
0
            *pOutLevel &= 1;
412
0
            break;
413
0
    }
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
findMatchingScheme(UBiDiLevel inLevel, UBiDiLevel outLevel,
424
        UBiDiOrder inOrder, UBiDiOrder outOrder)
425
0
{
426
0
    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
0
        }
433
0
    }
434
0
    return NULL;
435
0
}
436
437
U_DRAFT uint32_t U_EXPORT2
438
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
0
{
446
0
    uint32_t destLength = 0;
447
0
    UBool textChanged = FALSE;
448
0
    const UBiDiTransform *pOrigTransform = pBiDiTransform;
449
0
    const UBiDiAction *action = NULL;
450
0
451
0
    if (U_FAILURE(*pErrorCode)) {
452
0
        return 0;
453
0
    }
454
0
    if (src == NULL || dest == NULL) {
455
0
        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
456
0
        return 0;
457
0
    }
458
0
    CHECK_LEN(src, srcLength, pErrorCode);
459
0
    CHECK_LEN(dest, destSize, pErrorCode);
460
0
461
0
    if (pBiDiTransform == NULL) {
462
0
        pBiDiTransform = ubiditransform_open(pErrorCode);
463
0
        if (U_FAILURE(*pErrorCode)) {
464
0
            return 0;
465
0
        }
466
0
    }
467
0
    /* Current limitation: in multiple paragraphs will be resolved according
468
0
       to the 1st paragraph */
469
0
    resolveBaseDirection(src, srcLength, &inParaLevel, &outParaLevel);
470
0
471
0
    pBiDiTransform->pActiveScheme = findMatchingScheme(inParaLevel, outParaLevel,
472
0
            inOrder, outOrder);
473
0
    if (pBiDiTransform->pActiveScheme == NULL) {
474
0
        goto cleanup;
475
0
    }
476
0
    pBiDiTransform->reorderingOptions = doMirroring ? UBIDI_DO_MIRRORING
477
0
            : UBIDI_REORDER_DEFAULT;
478
0
479
0
    /* Ignore TEXT_DIRECTION_* flags, as we apply our own depending on the text
480
0
       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
0
485
0
    updateSrc(pBiDiTransform, src, srcLength, destSize > srcLength ? destSize : srcLength, pErrorCode);
486
0
    if (U_FAILURE(*pErrorCode)) {
487
0
        goto cleanup;
488
0
    }
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
0
        }
494
0
    }
495
0
    pBiDiTransform->dest = dest;
496
0
    pBiDiTransform->destSize = destSize;
497
0
    pBiDiTransform->pDestLength = &destLength;
498
0
499
0
    /* 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
0
            }
506
0
            textChanged = TRUE;
507
0
        }
508
0
    }
509
0
    ubidi_setInverse(pBiDiTransform->pBidi, FALSE);
510
0
511
0
    if (!textChanged && U_SUCCESS(*pErrorCode)) {
512
0
        /* Text was not changed - just copy src to dest */
513
0
        if (destSize < srcLength) {
514
0
            *pErrorCode = U_BUFFER_OVERFLOW_ERROR;
515
0
        } else {
516
0
            u_strncpy(dest, src, srcLength);
517
0
            destLength = srcLength;
518
0
        }
519
0
    }
520
0
cleanup:
521
0
    if (pOrigTransform != pBiDiTransform) {
522
0
        ubiditransform_close(pBiDiTransform);
523
0
    } else {
524
0
        pBiDiTransform->dest = NULL;
525
0
        pBiDiTransform->pDestLength = NULL;
526
0
        pBiDiTransform->srcLength = 0;
527
0
        pBiDiTransform->destSize = 0;
528
0
    }
529
0
    return U_FAILURE(*pErrorCode) ? 0 : destLength;
530
0
}