ubiditransform.cpp 20 KB

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