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