ubidiwrt.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  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) 2000-2015, International Business Machines
  7. * Corporation and others. All Rights Reserved.
  8. *
  9. ******************************************************************************
  10. * file name: ubidiwrt.c
  11. * encoding: UTF-8
  12. * tab size: 8 (not used)
  13. * indentation:4
  14. *
  15. * created on: 1999aug06
  16. * created by: Markus W. Scherer, updated by Matitiahu Allouche
  17. *
  18. * This file contains implementations for BiDi functions that use
  19. * the core algorithm and core API to write reordered text.
  20. */
  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 "cmemory.h"
  27. #include "ustr_imp.h"
  28. #include "ubidiimp.h"
  29. /*
  30. * The function implementations in this file are designed
  31. * for UTF-16 and UTF-32, not for UTF-8.
  32. *
  33. * Assumptions that are not true for UTF-8:
  34. * - Any code point always needs the same number of code units
  35. * ("minimum-length-problem" of UTF-8)
  36. * - The BiDi control characters need only one code unit each
  37. *
  38. * Further assumptions for all UTFs:
  39. * - u_charMirror(c) needs the same number of code units as c
  40. */
  41. #if defined(UTF_SIZE) && UTF_SIZE==8
  42. # error reimplement ubidi_writeReordered() for UTF-8, see comment above
  43. #endif
  44. #define IS_COMBINING(type) ((1UL<<(type))&(1UL<<U_NON_SPACING_MARK|1UL<<U_COMBINING_SPACING_MARK|1UL<<U_ENCLOSING_MARK))
  45. /*
  46. * When we have UBIDI_OUTPUT_REVERSE set on ubidi_writeReordered(), then we
  47. * semantically write RTL runs in reverse and later reverse them again.
  48. * Instead, we actually write them in forward order to begin with.
  49. * However, if the RTL run was to be mirrored, we need to mirror here now
  50. * since the implicit second reversal must not do it.
  51. * It looks strange to do mirroring in LTR output, but it is only because
  52. * we are writing RTL output in reverse.
  53. */
  54. static int32_t
  55. doWriteForward(const char16_t *src, int32_t srcLength,
  56. char16_t *dest, int32_t destSize,
  57. uint16_t options,
  58. UErrorCode *pErrorCode) {
  59. /* optimize for several combinations of options */
  60. switch(options&(UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING)) {
  61. case 0: {
  62. /* simply copy the LTR run to the destination */
  63. int32_t length=srcLength;
  64. if(destSize<length) {
  65. *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
  66. return srcLength;
  67. }
  68. do {
  69. *dest++=*src++;
  70. } while(--length>0);
  71. return srcLength;
  72. }
  73. case UBIDI_DO_MIRRORING: {
  74. /* do mirroring */
  75. int32_t i=0, j=0;
  76. UChar32 c;
  77. if(destSize<srcLength) {
  78. *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
  79. return srcLength;
  80. }
  81. do {
  82. U16_NEXT(src, i, srcLength, c);
  83. c=u_charMirror(c);
  84. U16_APPEND_UNSAFE(dest, j, c);
  85. } while(i<srcLength);
  86. return srcLength;
  87. }
  88. case UBIDI_REMOVE_BIDI_CONTROLS: {
  89. /* copy the LTR run and remove any BiDi control characters */
  90. int32_t remaining=destSize;
  91. char16_t c;
  92. do {
  93. c=*src++;
  94. if(!IS_BIDI_CONTROL_CHAR(c)) {
  95. if(--remaining<0) {
  96. *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
  97. /* preflight the length */
  98. while(--srcLength>0) {
  99. c=*src++;
  100. if(!IS_BIDI_CONTROL_CHAR(c)) {
  101. --remaining;
  102. }
  103. }
  104. return destSize-remaining;
  105. }
  106. *dest++=c;
  107. }
  108. } while(--srcLength>0);
  109. return destSize-remaining;
  110. }
  111. default: {
  112. /* remove BiDi control characters and do mirroring */
  113. int32_t remaining=destSize;
  114. int32_t i, j=0;
  115. UChar32 c;
  116. do {
  117. i=0;
  118. U16_NEXT(src, i, srcLength, c);
  119. src+=i;
  120. srcLength-=i;
  121. if(!IS_BIDI_CONTROL_CHAR(c)) {
  122. remaining-=i;
  123. if(remaining<0) {
  124. *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
  125. /* preflight the length */
  126. while(srcLength>0) {
  127. c=*src++;
  128. if(!IS_BIDI_CONTROL_CHAR(c)) {
  129. --remaining;
  130. }
  131. --srcLength;
  132. }
  133. return destSize-remaining;
  134. }
  135. c=u_charMirror(c);
  136. U16_APPEND_UNSAFE(dest, j, c);
  137. }
  138. } while(srcLength>0);
  139. return j;
  140. }
  141. } /* end of switch */
  142. }
  143. static int32_t
  144. doWriteReverse(const char16_t *src, int32_t srcLength,
  145. char16_t *dest, int32_t destSize,
  146. uint16_t options,
  147. UErrorCode *pErrorCode) {
  148. /*
  149. * RTL run -
  150. *
  151. * RTL runs need to be copied to the destination in reverse order
  152. * of code points, not code units, to keep Unicode characters intact.
  153. *
  154. * The general strategy for this is to read the source text
  155. * in backward order, collect all code units for a code point
  156. * (and optionally following combining characters, see below),
  157. * and copy all these code units in ascending order
  158. * to the destination for this run.
  159. *
  160. * Several options request whether combining characters
  161. * should be kept after their base characters,
  162. * whether BiDi control characters should be removed, and
  163. * whether characters should be replaced by their mirror-image
  164. * equivalent Unicode characters.
  165. */
  166. int32_t i, j;
  167. UChar32 c;
  168. /* optimize for several combinations of options */
  169. switch(options&(UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING|UBIDI_KEEP_BASE_COMBINING)) {
  170. case 0:
  171. /*
  172. * With none of the "complicated" options set, the destination
  173. * run will have the same length as the source run,
  174. * and there is no mirroring and no keeping combining characters
  175. * with their base characters.
  176. */
  177. if(destSize<srcLength) {
  178. *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
  179. return srcLength;
  180. }
  181. destSize=srcLength;
  182. /* preserve character integrity */
  183. do {
  184. /* i is always after the last code unit known to need to be kept in this segment */
  185. i=srcLength;
  186. /* collect code units for one base character */
  187. U16_BACK_1(src, 0, srcLength);
  188. /* copy this base character */
  189. j=srcLength;
  190. do {
  191. *dest++=src[j++];
  192. } while(j<i);
  193. } while(srcLength>0);
  194. break;
  195. case UBIDI_KEEP_BASE_COMBINING:
  196. /*
  197. * Here, too, the destination
  198. * run will have the same length as the source run,
  199. * and there is no mirroring.
  200. * We do need to keep combining characters with their base characters.
  201. */
  202. if(destSize<srcLength) {
  203. *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
  204. return srcLength;
  205. }
  206. destSize=srcLength;
  207. /* preserve character integrity */
  208. do {
  209. /* i is always after the last code unit known to need to be kept in this segment */
  210. i=srcLength;
  211. /* collect code units and modifier letters for one base character */
  212. do {
  213. U16_PREV(src, 0, srcLength, c);
  214. } while(srcLength>0 && IS_COMBINING(u_charType(c)));
  215. /* copy this "user character" */
  216. j=srcLength;
  217. do {
  218. *dest++=src[j++];
  219. } while(j<i);
  220. } while(srcLength>0);
  221. break;
  222. default:
  223. /*
  224. * With several "complicated" options set, this is the most
  225. * general and the slowest copying of an RTL run.
  226. * We will do mirroring, remove BiDi controls, and
  227. * keep combining characters with their base characters
  228. * as requested.
  229. */
  230. if(!(options&UBIDI_REMOVE_BIDI_CONTROLS)) {
  231. i=srcLength;
  232. } else {
  233. /* we need to find out the destination length of the run,
  234. which will not include the BiDi control characters */
  235. int32_t length=srcLength;
  236. char16_t ch;
  237. i=0;
  238. do {
  239. ch=*src++;
  240. if(!IS_BIDI_CONTROL_CHAR(ch)) {
  241. ++i;
  242. }
  243. } while(--length>0);
  244. src-=srcLength;
  245. }
  246. if(destSize<i) {
  247. *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
  248. return i;
  249. }
  250. destSize=i;
  251. /* preserve character integrity */
  252. do {
  253. /* i is always after the last code unit known to need to be kept in this segment */
  254. i=srcLength;
  255. /* collect code units for one base character */
  256. U16_PREV(src, 0, srcLength, c);
  257. if(options&UBIDI_KEEP_BASE_COMBINING) {
  258. /* collect modifier letters for this base character */
  259. while(srcLength>0 && IS_COMBINING(u_charType(c))) {
  260. U16_PREV(src, 0, srcLength, c);
  261. }
  262. }
  263. if(options&UBIDI_REMOVE_BIDI_CONTROLS && IS_BIDI_CONTROL_CHAR(c)) {
  264. /* do not copy this BiDi control character */
  265. continue;
  266. }
  267. /* copy this "user character" */
  268. j=srcLength;
  269. if(options&UBIDI_DO_MIRRORING) {
  270. /* mirror only the base character */
  271. int32_t k=0;
  272. c=u_charMirror(c);
  273. U16_APPEND_UNSAFE(dest, k, c);
  274. dest+=k;
  275. j+=k;
  276. }
  277. while(j<i) {
  278. *dest++=src[j++];
  279. }
  280. } while(srcLength>0);
  281. break;
  282. } /* end of switch */
  283. return destSize;
  284. }
  285. U_CAPI int32_t U_EXPORT2
  286. ubidi_writeReverse(const char16_t *src, int32_t srcLength,
  287. char16_t *dest, int32_t destSize,
  288. uint16_t options,
  289. UErrorCode *pErrorCode) {
  290. int32_t destLength;
  291. if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) {
  292. return 0;
  293. }
  294. /* more error checking */
  295. if( src==nullptr || srcLength<-1 ||
  296. destSize<0 || (destSize>0 && dest==nullptr))
  297. {
  298. *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
  299. return 0;
  300. }
  301. /* do input and output overlap? */
  302. if( dest!=nullptr &&
  303. ((src>=dest && src<dest+destSize) ||
  304. (dest>=src && dest<src+srcLength)))
  305. {
  306. *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
  307. return 0;
  308. }
  309. if(srcLength==-1) {
  310. srcLength=u_strlen(src);
  311. }
  312. if(srcLength>0) {
  313. destLength=doWriteReverse(src, srcLength, dest, destSize, options, pErrorCode);
  314. } else {
  315. /* nothing to do */
  316. destLength=0;
  317. }
  318. return u_terminateUChars(dest, destSize, destLength, pErrorCode);
  319. }
  320. // Ticket 20907 - The optimizer in MSVC/Visual Studio versions below 16.4 has trouble with this
  321. // function on Windows ARM64. As a work-around, we disable optimizations for this function.
  322. // This work-around could/should be removed once the following versions of Visual Studio are no
  323. // longer supported: All versions of VS2017, and versions of VS2019 below 16.4.
  324. #if (defined(_MSC_VER) && (defined(_M_ARM64)) && (_MSC_VER < 1924))
  325. #pragma optimize( "", off )
  326. #endif
  327. U_CAPI int32_t U_EXPORT2
  328. ubidi_writeReordered(UBiDi *pBiDi,
  329. char16_t *dest, int32_t destSize,
  330. uint16_t options,
  331. UErrorCode *pErrorCode) {
  332. const char16_t *text;
  333. char16_t *saveDest;
  334. int32_t length, destCapacity;
  335. int32_t run, runCount, logicalStart, runLength;
  336. if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) {
  337. return 0;
  338. }
  339. /* more error checking */
  340. if( pBiDi==nullptr ||
  341. (text=pBiDi->text)==nullptr || (length=pBiDi->length)<0 ||
  342. destSize<0 || (destSize>0 && dest==nullptr))
  343. {
  344. *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
  345. return 0;
  346. }
  347. /* do input and output overlap? */
  348. if( dest!=nullptr &&
  349. ((text>=dest && text<dest+destSize) ||
  350. (dest>=text && dest<text+pBiDi->originalLength)))
  351. {
  352. *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
  353. return 0;
  354. }
  355. if(length==0) {
  356. /* nothing to do */
  357. return u_terminateUChars(dest, destSize, 0, pErrorCode);
  358. }
  359. runCount=ubidi_countRuns(pBiDi, pErrorCode);
  360. if(U_FAILURE(*pErrorCode)) {
  361. return 0;
  362. }
  363. /* destSize shrinks, later destination length=destCapacity-destSize */
  364. saveDest=dest;
  365. destCapacity=destSize;
  366. /*
  367. * Option "insert marks" implies UBIDI_INSERT_LRM_FOR_NUMERIC if the
  368. * reordering mode (checked below) is appropriate.
  369. */
  370. if(pBiDi->reorderingOptions & UBIDI_OPTION_INSERT_MARKS) {
  371. options|=UBIDI_INSERT_LRM_FOR_NUMERIC;
  372. options&=~UBIDI_REMOVE_BIDI_CONTROLS;
  373. }
  374. /*
  375. * Option "remove controls" implies UBIDI_REMOVE_BIDI_CONTROLS
  376. * and cancels UBIDI_INSERT_LRM_FOR_NUMERIC.
  377. */
  378. if(pBiDi->reorderingOptions & UBIDI_OPTION_REMOVE_CONTROLS) {
  379. options|=UBIDI_REMOVE_BIDI_CONTROLS;
  380. options&=~UBIDI_INSERT_LRM_FOR_NUMERIC;
  381. }
  382. /*
  383. * If we do not perform the "inverse BiDi" algorithm, then we
  384. * don't need to insert any LRMs, and don't need to test for it.
  385. */
  386. if((pBiDi->reorderingMode != UBIDI_REORDER_INVERSE_NUMBERS_AS_L) &&
  387. (pBiDi->reorderingMode != UBIDI_REORDER_INVERSE_LIKE_DIRECT) &&
  388. (pBiDi->reorderingMode != UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL) &&
  389. (pBiDi->reorderingMode != UBIDI_REORDER_RUNS_ONLY)) {
  390. options&=~UBIDI_INSERT_LRM_FOR_NUMERIC;
  391. }
  392. /*
  393. * Iterate through all visual runs and copy the run text segments to
  394. * the destination, according to the options.
  395. *
  396. * The tests for where to insert LRMs ignore the fact that there may be
  397. * BN codes or non-BMP code points at the beginning and end of a run;
  398. * they may insert LRMs unnecessarily but the tests are faster this way
  399. * (this would have to be improved for UTF-8).
  400. *
  401. * Note that the only errors that are set by doWriteXY() are buffer overflow
  402. * errors. Ignore them until the end, and continue for preflighting.
  403. */
  404. if(!(options&UBIDI_OUTPUT_REVERSE)) {
  405. /* forward output */
  406. if(!(options&UBIDI_INSERT_LRM_FOR_NUMERIC)) {
  407. /* do not insert BiDi controls */
  408. for(run=0; run<runCount; ++run) {
  409. if(UBIDI_LTR==ubidi_getVisualRun(pBiDi, run, &logicalStart, &runLength)) {
  410. runLength=doWriteForward(text+logicalStart, runLength,
  411. dest, destSize,
  412. (uint16_t)(options&~UBIDI_DO_MIRRORING), pErrorCode);
  413. } else {
  414. runLength=doWriteReverse(text+logicalStart, runLength,
  415. dest, destSize,
  416. options, pErrorCode);
  417. }
  418. if(dest!=nullptr) {
  419. dest+=runLength;
  420. }
  421. destSize-=runLength;
  422. }
  423. } else {
  424. /* insert BiDi controls for "inverse BiDi" */
  425. const DirProp *dirProps=pBiDi->dirProps;
  426. const char16_t *src;
  427. char16_t uc;
  428. UBiDiDirection dir;
  429. int32_t markFlag;
  430. for(run=0; run<runCount; ++run) {
  431. dir=ubidi_getVisualRun(pBiDi, run, &logicalStart, &runLength);
  432. src=text+logicalStart;
  433. /* check if something relevant in insertPoints */
  434. markFlag=pBiDi->runs[run].insertRemove;
  435. if(markFlag<0) { /* BiDi controls count */
  436. markFlag=0;
  437. }
  438. if(UBIDI_LTR==dir) {
  439. if((pBiDi->isInverse) &&
  440. (/*run>0 &&*/ dirProps[logicalStart]!=L)) {
  441. markFlag |= LRM_BEFORE;
  442. }
  443. if (markFlag & LRM_BEFORE) {
  444. uc=LRM_CHAR;
  445. }
  446. else if (markFlag & RLM_BEFORE) {
  447. uc=RLM_CHAR;
  448. }
  449. else uc=0;
  450. if(uc) {
  451. if(destSize>0) {
  452. *dest++=uc;
  453. }
  454. --destSize;
  455. }
  456. runLength=doWriteForward(src, runLength,
  457. dest, destSize,
  458. (uint16_t)(options&~UBIDI_DO_MIRRORING), pErrorCode);
  459. if(dest!=nullptr) {
  460. dest+=runLength;
  461. }
  462. destSize-=runLength;
  463. if((pBiDi->isInverse) &&
  464. (/*run<runCount-1 &&*/ dirProps[logicalStart+runLength-1]!=L)) {
  465. markFlag |= LRM_AFTER;
  466. }
  467. if (markFlag & LRM_AFTER) {
  468. uc=LRM_CHAR;
  469. }
  470. else if (markFlag & RLM_AFTER) {
  471. uc=RLM_CHAR;
  472. }
  473. else uc=0;
  474. if(uc) {
  475. if(destSize>0) {
  476. *dest++=uc;
  477. }
  478. --destSize;
  479. }
  480. } else { /* RTL run */
  481. if((pBiDi->isInverse) &&
  482. (/*run>0 &&*/ !(MASK_R_AL&DIRPROP_FLAG(dirProps[logicalStart+runLength-1])))) {
  483. markFlag |= RLM_BEFORE;
  484. }
  485. if (markFlag & LRM_BEFORE) {
  486. uc=LRM_CHAR;
  487. }
  488. else if (markFlag & RLM_BEFORE) {
  489. uc=RLM_CHAR;
  490. }
  491. else uc=0;
  492. if(uc) {
  493. if(destSize>0) {
  494. *dest++=uc;
  495. }
  496. --destSize;
  497. }
  498. runLength=doWriteReverse(src, runLength,
  499. dest, destSize,
  500. options, pErrorCode);
  501. if(dest!=nullptr) {
  502. dest+=runLength;
  503. }
  504. destSize-=runLength;
  505. if((pBiDi->isInverse) &&
  506. (/*run<runCount-1 &&*/ !(MASK_R_AL&DIRPROP_FLAG(dirProps[logicalStart])))) {
  507. markFlag |= RLM_AFTER;
  508. }
  509. if (markFlag & LRM_AFTER) {
  510. uc=LRM_CHAR;
  511. }
  512. else if (markFlag & RLM_AFTER) {
  513. uc=RLM_CHAR;
  514. }
  515. else uc=0;
  516. if(uc) {
  517. if(destSize>0) {
  518. *dest++=uc;
  519. }
  520. --destSize;
  521. }
  522. }
  523. }
  524. }
  525. } else {
  526. /* reverse output */
  527. if(!(options&UBIDI_INSERT_LRM_FOR_NUMERIC)) {
  528. /* do not insert BiDi controls */
  529. for(run=runCount; --run>=0;) {
  530. if(UBIDI_LTR==ubidi_getVisualRun(pBiDi, run, &logicalStart, &runLength)) {
  531. runLength=doWriteReverse(text+logicalStart, runLength,
  532. dest, destSize,
  533. (uint16_t)(options&~UBIDI_DO_MIRRORING), pErrorCode);
  534. } else {
  535. runLength=doWriteForward(text+logicalStart, runLength,
  536. dest, destSize,
  537. options, pErrorCode);
  538. }
  539. if(dest!=nullptr) {
  540. dest+=runLength;
  541. }
  542. destSize-=runLength;
  543. }
  544. } else {
  545. /* insert BiDi controls for "inverse BiDi" */
  546. const DirProp *dirProps=pBiDi->dirProps;
  547. const char16_t *src;
  548. UBiDiDirection dir;
  549. for(run=runCount; --run>=0;) {
  550. /* reverse output */
  551. dir=ubidi_getVisualRun(pBiDi, run, &logicalStart, &runLength);
  552. src=text+logicalStart;
  553. if(UBIDI_LTR==dir) {
  554. if(/*run<runCount-1 &&*/ dirProps[logicalStart+runLength-1]!=L) {
  555. if(destSize>0) {
  556. *dest++=LRM_CHAR;
  557. }
  558. --destSize;
  559. }
  560. runLength=doWriteReverse(src, runLength,
  561. dest, destSize,
  562. (uint16_t)(options&~UBIDI_DO_MIRRORING), pErrorCode);
  563. if(dest!=nullptr) {
  564. dest+=runLength;
  565. }
  566. destSize-=runLength;
  567. if(/*run>0 &&*/ dirProps[logicalStart]!=L) {
  568. if(destSize>0) {
  569. *dest++=LRM_CHAR;
  570. }
  571. --destSize;
  572. }
  573. } else {
  574. if(/*run<runCount-1 &&*/ !(MASK_R_AL&DIRPROP_FLAG(dirProps[logicalStart]))) {
  575. if(destSize>0) {
  576. *dest++=RLM_CHAR;
  577. }
  578. --destSize;
  579. }
  580. runLength=doWriteForward(src, runLength,
  581. dest, destSize,
  582. options, pErrorCode);
  583. if(dest!=nullptr) {
  584. dest+=runLength;
  585. }
  586. destSize-=runLength;
  587. if(/*run>0 &&*/ !(MASK_R_AL&DIRPROP_FLAG(dirProps[logicalStart+runLength-1]))) {
  588. if(destSize>0) {
  589. *dest++=RLM_CHAR;
  590. }
  591. --destSize;
  592. }
  593. }
  594. }
  595. }
  596. }
  597. return u_terminateUChars(saveDest, destCapacity, destCapacity-destSize, pErrorCode);
  598. }
  599. #if (defined(_MSC_VER) && (defined(_M_ARM64)) && (_MSC_VER < 1924))
  600. #pragma optimize( "", on )
  601. #endif