1 /* 2 ******************************************************************************* 3 * 4 * Copyright (C) 2005-2013, International Business Machines 5 * Corporation and others. All Rights Reserved. 6 * 7 ******************************************************************************* 8 * file name: utext.cpp 9 * encoding: US-ASCII 10 * tab size: 8 (not used) 11 * indentation:4 12 * 13 * created on: 2005apr12 14 * created by: Markus W. Scherer 15 */ 16 17 #include "unicode/utypes.h" 18 #include "unicode/ustring.h" 19 #include "unicode/unistr.h" 20 #include "unicode/chariter.h" 21 #include "unicode/utext.h" 22 #include "unicode/utf.h" 23 #include "unicode/utf8.h" 24 #include "unicode/utf16.h" 25 #include "ustr_imp.h" 26 #include "cmemory.h" 27 #include "cstring.h" 28 #include "uassert.h" 29 #include "putilimp.h" 30 31 U_NAMESPACE_USE 32 33 #define I32_FLAG(bitIndex) ((int32_t)1<<(bitIndex)) 34 35 36 static UBool 37 utext_access(UText *ut, int64_t index, UBool forward) { 38 return ut->pFuncs->access(ut, index, forward); 39 } 40 41 42 43 U_CAPI UBool U_EXPORT2 44 utext_moveIndex32(UText *ut, int32_t delta) { 45 UChar32 c; 46 if (delta > 0) { 47 do { 48 if(ut->chunkOffset>=ut->chunkLength && !utext_access(ut, ut->chunkNativeLimit, TRUE)) { 49 return FALSE; 50 } 51 c = ut->chunkContents[ut->chunkOffset]; 52 if (U16_IS_SURROGATE(c)) { 53 c = utext_next32(ut); 54 if (c == U_SENTINEL) { 55 return FALSE; 56 } 57 } else { 58 ut->chunkOffset++; 59 } 60 } while(--delta>0); 61 62 } else if (delta<0) { 63 do { 64 if(ut->chunkOffset<=0 && !utext_access(ut, ut->chunkNativeStart, FALSE)) { 65 return FALSE; 66 } 67 c = ut->chunkContents[ut->chunkOffset-1]; 68 if (U16_IS_SURROGATE(c)) { 69 c = utext_previous32(ut); 70 if (c == U_SENTINEL) { 71 return FALSE; 72 } 73 } else { 74 ut->chunkOffset--; 75 } 76 } while(++delta<0); 77 } 78 79 return TRUE; 80 } 81 82 83 U_CAPI int64_t U_EXPORT2 84 utext_nativeLength(UText *ut) { 85 return ut->pFuncs->nativeLength(ut); 86 } 87 88 89 U_CAPI UBool U_EXPORT2 90 utext_isLengthExpensive(const UText *ut) { 91 UBool r = (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE)) != 0; 92 return r; 93 } 94 95 96 U_CAPI int64_t U_EXPORT2 97 utext_getNativeIndex(const UText *ut) { 98 if(ut->chunkOffset <= ut->nativeIndexingLimit) { 99 return ut->chunkNativeStart+ut->chunkOffset; 100 } else { 101 return ut->pFuncs->mapOffsetToNative(ut); 102 } 103 } 104 105 106 U_CAPI void U_EXPORT2 107 utext_setNativeIndex(UText *ut, int64_t index) { 108 if(index<ut->chunkNativeStart || index>=ut->chunkNativeLimit) { 109 // The desired position is outside of the current chunk. 110 // Access the new position. Assume a forward iteration from here, 111 // which will also be optimimum for a single random access. 112 // Reverse iterations may suffer slightly. 113 ut->pFuncs->access(ut, index, TRUE); 114 } else if((int32_t)(index - ut->chunkNativeStart) <= ut->nativeIndexingLimit) { 115 // utf-16 indexing. 116 ut->chunkOffset=(int32_t)(index-ut->chunkNativeStart); 117 } else { 118 ut->chunkOffset=ut->pFuncs->mapNativeIndexToUTF16(ut, index); 119 } 120 // The convention is that the index must always be on a code point boundary. 121 // Adjust the index position if it is in the middle of a surrogate pair. 122 if (ut->chunkOffset<ut->chunkLength) { 123 UChar c= ut->chunkContents[ut->chunkOffset]; 124 if (U16_IS_TRAIL(c)) { 125 if (ut->chunkOffset==0) { 126 ut->pFuncs->access(ut, ut->chunkNativeStart, FALSE); 127 } 128 if (ut->chunkOffset>0) { 129 UChar lead = ut->chunkContents[ut->chunkOffset-1]; 130 if (U16_IS_LEAD(lead)) { 131 ut->chunkOffset--; 132 } 133 } 134 } 135 } 136 } 137 138 139 140 U_CAPI int64_t U_EXPORT2 141 utext_getPreviousNativeIndex(UText *ut) { 142 // 143 // Fast-path the common case. 144 // Common means current position is not at the beginning of a chunk 145 // and the preceding character is not supplementary. 146 // 147 int32_t i = ut->chunkOffset - 1; 148 int64_t result; 149 if (i >= 0) { 150 UChar c = ut->chunkContents[i]; 151 if (U16_IS_TRAIL(c) == FALSE) { 152 if (i <= ut->nativeIndexingLimit) { 153 result = ut->chunkNativeStart + i; 154 } else { 155 ut->chunkOffset = i; 156 result = ut->pFuncs->mapOffsetToNative(ut); 157 ut->chunkOffset++; 158 } 159 return result; 160 } 161 } 162 163 // If at the start of text, simply return 0. 164 if (ut->chunkOffset==0 && ut->chunkNativeStart==0) { 165 return 0; 166 } 167 168 // Harder, less common cases. We are at a chunk boundary, or on a surrogate. 169 // Keep it simple, use other functions to handle the edges. 170 // 171 utext_previous32(ut); 172 result = UTEXT_GETNATIVEINDEX(ut); 173 utext_next32(ut); 174 return result; 175 } 176 177 178 // 179 // utext_current32. Get the UChar32 at the current position. 180 // UText iteration position is always on a code point boundary, 181 // never on the trail half of a surrogate pair. 182 // 183 U_CAPI UChar32 U_EXPORT2 184 utext_current32(UText *ut) { 185 UChar32 c; 186 if (ut->chunkOffset==ut->chunkLength) { 187 // Current position is just off the end of the chunk. 188 if (ut->pFuncs->access(ut, ut->chunkNativeLimit, TRUE) == FALSE) { 189 // Off the end of the text. 190 return U_SENTINEL; 191 } 192 } 193 194 c = ut->chunkContents[ut->chunkOffset]; 195 if (U16_IS_LEAD(c) == FALSE) { 196 // Normal, non-supplementary case. 197 return c; 198 } 199 200 // 201 // Possible supplementary char. 202 // 203 UChar32 trail = 0; 204 UChar32 supplementaryC = c; 205 if ((ut->chunkOffset+1) < ut->chunkLength) { 206 // The trail surrogate is in the same chunk. 207 trail = ut->chunkContents[ut->chunkOffset+1]; 208 } else { 209 // The trail surrogate is in a different chunk. 210 // Because we must maintain the iteration position, we need to switch forward 211 // into the new chunk, get the trail surrogate, then revert the chunk back to the 212 // original one. 213 // An edge case to be careful of: the entire text may end with an unpaired 214 // leading surrogate. The attempt to access the trail will fail, but 215 // the original position before the unpaired lead still needs to be restored. 216 int64_t nativePosition = ut->chunkNativeLimit; 217 int32_t originalOffset = ut->chunkOffset; 218 if (ut->pFuncs->access(ut, nativePosition, TRUE)) { 219 trail = ut->chunkContents[ut->chunkOffset]; 220 } 221 UBool r = ut->pFuncs->access(ut, nativePosition, FALSE); // reverse iteration flag loads preceding chunk 222 U_ASSERT(r==TRUE); 223 ut->chunkOffset = originalOffset; 224 if(!r) { 225 return U_SENTINEL; 226 } 227 } 228 229 if (U16_IS_TRAIL(trail)) { 230 supplementaryC = U16_GET_SUPPLEMENTARY(c, trail); 231 } 232 return supplementaryC; 233 234 } 235 236 237 U_CAPI UChar32 U_EXPORT2 238 utext_char32At(UText *ut, int64_t nativeIndex) { 239 UChar32 c = U_SENTINEL; 240 241 // Fast path the common case. 242 if (nativeIndex>=ut->chunkNativeStart && nativeIndex < ut->chunkNativeStart + ut->nativeIndexingLimit) { 243 ut->chunkOffset = (int32_t)(nativeIndex - ut->chunkNativeStart); 244 c = ut->chunkContents[ut->chunkOffset]; 245 if (U16_IS_SURROGATE(c) == FALSE) { 246 return c; 247 } 248 } 249 250 251 utext_setNativeIndex(ut, nativeIndex); 252 if (nativeIndex>=ut->chunkNativeStart && ut->chunkOffset<ut->chunkLength) { 253 c = ut->chunkContents[ut->chunkOffset]; 254 if (U16_IS_SURROGATE(c)) { 255 // For surrogates, let current32() deal with the complications 256 // of supplementaries that may span chunk boundaries. 257 c = utext_current32(ut); 258 } 259 } 260 return c; 261 } 262 263 264 U_CAPI UChar32 U_EXPORT2 265 utext_next32(UText *ut) { 266 UChar32 c; 267 268 if (ut->chunkOffset >= ut->chunkLength) { 269 if (ut->pFuncs->access(ut, ut->chunkNativeLimit, TRUE) == FALSE) { 270 return U_SENTINEL; 271 } 272 } 273 274 c = ut->chunkContents[ut->chunkOffset++]; 275 if (U16_IS_LEAD(c) == FALSE) { 276 // Normal case, not supplementary. 277 // (A trail surrogate seen here is just returned as is, as a surrogate value. 278 // It cannot be part of a pair.) 279 return c; 280 } 281 282 if (ut->chunkOffset >= ut->chunkLength) { 283 if (ut->pFuncs->access(ut, ut->chunkNativeLimit, TRUE) == FALSE) { 284 // c is an unpaired lead surrogate at the end of the text. 285 // return it as it is. 286 return c; 287 } 288 } 289 UChar32 trail = ut->chunkContents[ut->chunkOffset]; 290 if (U16_IS_TRAIL(trail) == FALSE) { 291 // c was an unpaired lead surrogate, not at the end of the text. 292 // return it as it is (unpaired). Iteration position is on the 293 // following character, possibly in the next chunk, where the 294 // trail surrogate would have been if it had existed. 295 return c; 296 } 297 298 UChar32 supplementary = U16_GET_SUPPLEMENTARY(c, trail); 299 ut->chunkOffset++; // move iteration position over the trail surrogate. 300 return supplementary; 301 } 302 303 304 U_CAPI UChar32 U_EXPORT2 305 utext_previous32(UText *ut) { 306 UChar32 c; 307 308 if (ut->chunkOffset <= 0) { 309 if (ut->pFuncs->access(ut, ut->chunkNativeStart, FALSE) == FALSE) { 310 return U_SENTINEL; 311 } 312 } 313 ut->chunkOffset--; 314 c = ut->chunkContents[ut->chunkOffset]; 315 if (U16_IS_TRAIL(c) == FALSE) { 316 // Normal case, not supplementary. 317 // (A lead surrogate seen here is just returned as is, as a surrogate value. 318 // It cannot be part of a pair.) 319 return c; 320 } 321 322 if (ut->chunkOffset <= 0) { 323 if (ut->pFuncs->access(ut, ut->chunkNativeStart, FALSE) == FALSE) { 324 // c is an unpaired trail surrogate at the start of the text. 325 // return it as it is. 326 return c; 327 } 328 } 329 330 UChar32 lead = ut->chunkContents[ut->chunkOffset-1]; 331 if (U16_IS_LEAD(lead) == FALSE) { 332 // c was an unpaired trail surrogate, not at the end of the text. 333 // return it as it is (unpaired). Iteration position is at c 334 return c; 335 } 336 337 UChar32 supplementary = U16_GET_SUPPLEMENTARY(lead, c); 338 ut->chunkOffset--; // move iteration position over the lead surrogate. 339 return supplementary; 340 } 341 342 343 344 U_CAPI UChar32 U_EXPORT2 345 utext_next32From(UText *ut, int64_t index) { 346 UChar32 c = U_SENTINEL; 347 348 if(index<ut->chunkNativeStart || index>=ut->chunkNativeLimit) { 349 // Desired position is outside of the current chunk. 350 if(!ut->pFuncs->access(ut, index, TRUE)) { 351 // no chunk available here 352 return U_SENTINEL; 353 } 354 } else if (index - ut->chunkNativeStart <= (int64_t)ut->nativeIndexingLimit) { 355 // Desired position is in chunk, with direct 1:1 native to UTF16 indexing 356 ut->chunkOffset = (int32_t)(index - ut->chunkNativeStart); 357 } else { 358 // Desired position is in chunk, with non-UTF16 indexing. 359 ut->chunkOffset = ut->pFuncs->mapNativeIndexToUTF16(ut, index); 360 } 361 362 c = ut->chunkContents[ut->chunkOffset++]; 363 if (U16_IS_SURROGATE(c)) { 364 // Surrogates. Many edge cases. Use other functions that already 365 // deal with the problems. 366 utext_setNativeIndex(ut, index); 367 c = utext_next32(ut); 368 } 369 return c; 370 } 371 372 373 U_CAPI UChar32 U_EXPORT2 374 utext_previous32From(UText *ut, int64_t index) { 375 // 376 // Return the character preceding the specified index. 377 // Leave the iteration position at the start of the character that was returned. 378 // 379 UChar32 cPrev; // The character preceding cCurr, which is what we will return. 380 381 // Address the chunk containg the position preceding the incoming index 382 // A tricky edge case: 383 // We try to test the requested native index against the chunkNativeStart to determine 384 // whether the character preceding the one at the index is in the current chunk. 385 // BUT, this test can fail with UTF-8 (or any other multibyte encoding), when the 386 // requested index is on something other than the first position of the first char. 387 // 388 if(index<=ut->chunkNativeStart || index>ut->chunkNativeLimit) { 389 // Requested native index is outside of the current chunk. 390 if(!ut->pFuncs->access(ut, index, FALSE)) { 391 // no chunk available here 392 return U_SENTINEL; 393 } 394 } else if(index - ut->chunkNativeStart <= (int64_t)ut->nativeIndexingLimit) { 395 // Direct UTF-16 indexing. 396 ut->chunkOffset = (int32_t)(index - ut->chunkNativeStart); 397 } else { 398 ut->chunkOffset=ut->pFuncs->mapNativeIndexToUTF16(ut, index); 399 if (ut->chunkOffset==0 && !ut->pFuncs->access(ut, index, FALSE)) { 400 // no chunk available here 401 return U_SENTINEL; 402 } 403 } 404 405 // 406 // Simple case with no surrogates. 407 // 408 ut->chunkOffset--; 409 cPrev = ut->chunkContents[ut->chunkOffset]; 410 411 if (U16_IS_SURROGATE(cPrev)) { 412 // Possible supplementary. Many edge cases. 413 // Let other functions do the heavy lifting. 414 utext_setNativeIndex(ut, index); 415 cPrev = utext_previous32(ut); 416 } 417 return cPrev; 418 } 419 420 421 U_CAPI int32_t U_EXPORT2 422 utext_extract(UText *ut, 423 int64_t start, int64_t limit, 424 UChar *dest, int32_t destCapacity, 425 UErrorCode *status) { 426 return ut->pFuncs->extract(ut, start, limit, dest, destCapacity, status); 427 } 428 429 430 431 U_CAPI UBool U_EXPORT2 432 utext_equals(const UText *a, const UText *b) { 433 if (a==NULL || b==NULL || 434 a->magic != UTEXT_MAGIC || 435 b->magic != UTEXT_MAGIC) { 436 // Null or invalid arguments don't compare equal to anything. 437 return FALSE; 438 } 439 440 if (a->pFuncs != b->pFuncs) { 441 // Different types of text providers. 442 return FALSE; 443 } 444 445 if (a->context != b->context) { 446 // Different sources (different strings) 447 return FALSE; 448 } 449 if (utext_getNativeIndex(a) != utext_getNativeIndex(b)) { 450 // Different current position in the string. 451 return FALSE; 452 } 453 454 return TRUE; 455 } 456 457 U_CAPI UBool U_EXPORT2 458 utext_isWritable(const UText *ut) 459 { 460 UBool b = (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_WRITABLE)) != 0; 461 return b; 462 } 463 464 465 U_CAPI void U_EXPORT2 466 utext_freeze(UText *ut) { 467 // Zero out the WRITABLE flag. 468 ut->providerProperties &= ~(I32_FLAG(UTEXT_PROVIDER_WRITABLE)); 469 } 470 471 472 U_CAPI UBool U_EXPORT2 473 utext_hasMetaData(const UText *ut) 474 { 475 UBool b = (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_HAS_META_DATA)) != 0; 476 return b; 477 } 478 479 480 481 U_CAPI int32_t U_EXPORT2 482 utext_replace(UText *ut, 483 int64_t nativeStart, int64_t nativeLimit, 484 const UChar *replacementText, int32_t replacementLength, 485 UErrorCode *status) 486 { 487 if (U_FAILURE(*status)) { 488 return 0; 489 } 490 if ((ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_WRITABLE)) == 0) { 491 *status = U_NO_WRITE_PERMISSION; 492 return 0; 493 } 494 int32_t i = ut->pFuncs->replace(ut, nativeStart, nativeLimit, replacementText, replacementLength, status); 495 return i; 496 } 497 498 U_CAPI void U_EXPORT2 499 utext_copy(UText *ut, 500 int64_t nativeStart, int64_t nativeLimit, 501 int64_t destIndex, 502 UBool move, 503 UErrorCode *status) 504 { 505 if (U_FAILURE(*status)) { 506 return; 507 } 508 if ((ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_WRITABLE)) == 0) { 509 *status = U_NO_WRITE_PERMISSION; 510 return; 511 } 512 ut->pFuncs->copy(ut, nativeStart, nativeLimit, destIndex, move, status); 513 } 514 515 516 517 U_CAPI UText * U_EXPORT2 518 utext_clone(UText *dest, const UText *src, UBool deep, UBool readOnly, UErrorCode *status) { 519 UText *result; 520 result = src->pFuncs->clone(dest, src, deep, status); 521 if (readOnly) { 522 utext_freeze(result); 523 } 524 return result; 525 } 526 527 528 529 //------------------------------------------------------------------------------ 530 // 531 // UText common functions implementation 532 // 533 //------------------------------------------------------------------------------ 534 535 // 536 // UText.flags bit definitions 537 // 538 enum { 539 UTEXT_HEAP_ALLOCATED = 1, // 1 if ICU has allocated this UText struct on the heap. 540 // 0 if caller provided storage for the UText. 541 542 UTEXT_EXTRA_HEAP_ALLOCATED = 2, // 1 if ICU has allocated extra storage as a separate 543 // heap block. 544 // 0 if there is no separate allocation. Either no extra 545 // storage was requested, or it is appended to the end 546 // of the main UText storage. 547 548 UTEXT_OPEN = 4 // 1 if this UText is currently open 549 // 0 if this UText is not open. 550 }; 551 552 553 // 554 // Extended form of a UText. The purpose is to aid in computing the total size required 555 // when a provider asks for a UText to be allocated with extra storage. 556 557 struct ExtendedUText { 558 UText ut; 559 UAlignedMemory extension; 560 }; 561 562 static const UText emptyText = UTEXT_INITIALIZER; 563 564 U_CAPI UText * U_EXPORT2 565 utext_setup(UText *ut, int32_t extraSpace, UErrorCode *status) { 566 if (U_FAILURE(*status)) { 567 return ut; 568 } 569 570 if (ut == NULL) { 571 // We need to heap-allocate storage for the new UText 572 int32_t spaceRequired = sizeof(UText); 573 if (extraSpace > 0) { 574 spaceRequired = sizeof(ExtendedUText) + extraSpace - sizeof(UAlignedMemory); 575 } 576 ut = (UText *)uprv_malloc(spaceRequired); 577 if (ut == NULL) { 578 *status = U_MEMORY_ALLOCATION_ERROR; 579 return NULL; 580 } else { 581 *ut = emptyText; 582 ut->flags |= UTEXT_HEAP_ALLOCATED; 583 if (spaceRequired>0) { 584 ut->extraSize = extraSpace; 585 ut->pExtra = &((ExtendedUText *)ut)->extension; 586 } 587 } 588 } else { 589 // We have been supplied with an already existing UText. 590 // Verify that it really appears to be a UText. 591 if (ut->magic != UTEXT_MAGIC) { 592 *status = U_ILLEGAL_ARGUMENT_ERROR; 593 return ut; 594 } 595 // If the ut is already open and there's a provider supplied close 596 // function, call it. 597 if ((ut->flags & UTEXT_OPEN) && ut->pFuncs->close != NULL) { 598 ut->pFuncs->close(ut); 599 } 600 ut->flags &= ~UTEXT_OPEN; 601 602 // If extra space was requested by our caller, check whether 603 // sufficient already exists, and allocate new if needed. 604 if (extraSpace > ut->extraSize) { 605 // Need more space. If there is existing separately allocated space, 606 // delete it first, then allocate new space. 607 if (ut->flags & UTEXT_EXTRA_HEAP_ALLOCATED) { 608 uprv_free(ut->pExtra); 609 ut->extraSize = 0; 610 } 611 ut->pExtra = uprv_malloc(extraSpace); 612 if (ut->pExtra == NULL) { 613 *status = U_MEMORY_ALLOCATION_ERROR; 614 } else { 615 ut->extraSize = extraSpace; 616 ut->flags |= UTEXT_EXTRA_HEAP_ALLOCATED; 617 } 618 } 619 } 620 if (U_SUCCESS(*status)) { 621 ut->flags |= UTEXT_OPEN; 622 623 // Initialize all remaining fields of the UText. 624 // 625 ut->context = NULL; 626 ut->chunkContents = NULL; 627 ut->p = NULL; 628 ut->q = NULL; 629 ut->r = NULL; 630 ut->a = 0; 631 ut->b = 0; 632 ut->c = 0; 633 ut->chunkOffset = 0; 634 ut->chunkLength = 0; 635 ut->chunkNativeStart = 0; 636 ut->chunkNativeLimit = 0; 637 ut->nativeIndexingLimit = 0; 638 ut->providerProperties = 0; 639 ut->privA = 0; 640 ut->privB = 0; 641 ut->privC = 0; 642 ut->privP = NULL; 643 if (ut->pExtra!=NULL && ut->extraSize>0) 644 uprv_memset(ut->pExtra, 0, ut->extraSize); 645 646 } 647 return ut; 648 } 649 650 651 U_CAPI UText * U_EXPORT2 652 utext_close(UText *ut) { 653 if (ut==NULL || 654 ut->magic != UTEXT_MAGIC || 655 (ut->flags & UTEXT_OPEN) == 0) 656 { 657 // The supplied ut is not an open UText. 658 // Do nothing. 659 return ut; 660 } 661 662 // If the provider gave us a close function, call it now. 663 // This will clean up anything allocated specifically by the provider. 664 if (ut->pFuncs->close != NULL) { 665 ut->pFuncs->close(ut); 666 } 667 ut->flags &= ~UTEXT_OPEN; 668 669 // If we (the framework) allocated the UText or subsidiary storage, 670 // delete it. 671 if (ut->flags & UTEXT_EXTRA_HEAP_ALLOCATED) { 672 uprv_free(ut->pExtra); 673 ut->pExtra = NULL; 674 ut->flags &= ~UTEXT_EXTRA_HEAP_ALLOCATED; 675 ut->extraSize = 0; 676 } 677 678 // Zero out function table of the closed UText. This is a defensive move, 679 // inteded to cause applications that inadvertantly use a closed 680 // utext to crash with null pointer errors. 681 ut->pFuncs = NULL; 682 683 if (ut->flags & UTEXT_HEAP_ALLOCATED) { 684 // This UText was allocated by UText setup. We need to free it. 685 // Clear magic, so we can detect if the user messes up and immediately 686 // tries to reopen another UText using the deleted storage. 687 ut->magic = 0; 688 uprv_free(ut); 689 ut = NULL; 690 } 691 return ut; 692 } 693 694 695 696 697 // 698 // invalidateChunk Reset a chunk to have no contents, so that the next call 699 // to access will cause new data to load. 700 // This is needed when copy/move/replace operate directly on the 701 // backing text, potentially putting it out of sync with the 702 // contents in the chunk. 703 // 704 static void 705 invalidateChunk(UText *ut) { 706 ut->chunkLength = 0; 707 ut->chunkNativeLimit = 0; 708 ut->chunkNativeStart = 0; 709 ut->chunkOffset = 0; 710 ut->nativeIndexingLimit = 0; 711 } 712 713 // 714 // pinIndex Do range pinning on a native index parameter. 715 // 64 bit pinning is done in place. 716 // 32 bit truncated result is returned as a convenience for 717 // use in providers that don't need 64 bits. 718 static int32_t 719 pinIndex(int64_t &index, int64_t limit) { 720 if (index<0) { 721 index = 0; 722 } else if (index > limit) { 723 index = limit; 724 } 725 return (int32_t)index; 726 } 727 728 729 U_CDECL_BEGIN 730 731 // 732 // Pointer relocation function, 733 // a utility used by shallow clone. 734 // Adjust a pointer that refers to something within one UText (the source) 735 // to refer to the same relative offset within a another UText (the target) 736 // 737 static void adjustPointer(UText *dest, const void **destPtr, const UText *src) { 738 // convert all pointers to (char *) so that byte address arithmetic will work. 739 char *dptr = (char *)*destPtr; 740 char *dUText = (char *)dest; 741 char *sUText = (char *)src; 742 743 if (dptr >= (char *)src->pExtra && dptr < ((char*)src->pExtra)+src->extraSize) { 744 // target ptr was to something within the src UText's pExtra storage. 745 // relocate it into the target UText's pExtra region. 746 *destPtr = ((char *)dest->pExtra) + (dptr - (char *)src->pExtra); 747 } else if (dptr>=sUText && dptr < sUText+src->sizeOfStruct) { 748 // target ptr was pointing to somewhere within the source UText itself. 749 // Move it to the same offset within the target UText. 750 *destPtr = dUText + (dptr-sUText); 751 } 752 } 753 754 755 // 756 // Clone. This is a generic copy-the-utext-by-value clone function that can be 757 // used as-is with some utext types, and as a helper by other clones. 758 // 759 static UText * U_CALLCONV 760 shallowTextClone(UText * dest, const UText * src, UErrorCode * status) { 761 if (U_FAILURE(*status)) { 762 return NULL; 763 } 764 int32_t srcExtraSize = src->extraSize; 765 766 // 767 // Use the generic text_setup to allocate storage if required. 768 // 769 dest = utext_setup(dest, srcExtraSize, status); 770 if (U_FAILURE(*status)) { 771 return dest; 772 } 773 774 // 775 // flags (how the UText was allocated) and the pointer to the 776 // extra storage must retain the values in the cloned utext that 777 // were set up by utext_setup. Save them separately before 778 // copying the whole struct. 779 // 780 void *destExtra = dest->pExtra; 781 int32_t flags = dest->flags; 782 783 784 // 785 // Copy the whole UText struct by value. 786 // Any "Extra" storage is copied also. 787 // 788 int sizeToCopy = src->sizeOfStruct; 789 if (sizeToCopy > dest->sizeOfStruct) { 790 sizeToCopy = dest->sizeOfStruct; 791 } 792 uprv_memcpy(dest, src, sizeToCopy); 793 dest->pExtra = destExtra; 794 dest->flags = flags; 795 if (srcExtraSize > 0) { 796 uprv_memcpy(dest->pExtra, src->pExtra, srcExtraSize); 797 } 798 799 // 800 // Relocate any pointers in the target that refer to the UText itself 801 // to point to the cloned copy rather than the original source. 802 // 803 adjustPointer(dest, &dest->context, src); 804 adjustPointer(dest, &dest->p, src); 805 adjustPointer(dest, &dest->q, src); 806 adjustPointer(dest, &dest->r, src); 807 adjustPointer(dest, (const void **)&dest->chunkContents, src); 808 809 // The newly shallow-cloned UText does _not_ own the underlying storage for the text. 810 // (The source for the clone may or may not have owned the text.) 811 812 dest->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT); 813 814 return dest; 815 } 816 817 818 U_CDECL_END 819 820 821 822 //------------------------------------------------------------------------------ 823 // 824 // UText implementation for UTF-8 char * strings (read-only) 825 // Limitation: string length must be <= 0x7fffffff in length. 826 // (length must for in an int32_t variable) 827 // 828 // Use of UText data members: 829 // context pointer to UTF-8 string 830 // utext.b is the input string length (bytes). 831 // utext.c Length scanned so far in string 832 // (for optimizing finding length of zero terminated strings.) 833 // utext.p pointer to the current buffer 834 // utext.q pointer to the other buffer. 835 // 836 //------------------------------------------------------------------------------ 837 838 // Chunk size. 839 // Must be less than 85, because of byte mapping from UChar indexes to native indexes. 840 // Worst case is three native bytes to one UChar. (Supplemenaries are 4 native bytes 841 // to two UChars.) 842 // 843 enum { UTF8_TEXT_CHUNK_SIZE=32 }; 844 845 // 846 // UTF8Buf Two of these structs will be set up in the UText's extra allocated space. 847 // Each contains the UChar chunk buffer, the to and from native maps, and 848 // header info. 849 // 850 // because backwards iteration fills the buffers starting at the end and 851 // working towards the front, the filled part of the buffers may not begin 852 // at the start of the available storage for the buffers. 853 // 854 // Buffer size is one bigger than the specified UTF8_TEXT_CHUNK_SIZE to allow for 855 // the last character added being a supplementary, and thus requiring a surrogate 856 // pair. Doing this is simpler than checking for the edge case. 857 // 858 859 struct UTF8Buf { 860 int32_t bufNativeStart; // Native index of first char in UChar buf 861 int32_t bufNativeLimit; // Native index following last char in buf. 862 int32_t bufStartIdx; // First filled position in buf. 863 int32_t bufLimitIdx; // Limit of filled range in buf. 864 int32_t bufNILimit; // Limit of native indexing part of buf 865 int32_t toUCharsMapStart; // Native index corresponding to 866 // mapToUChars[0]. 867 // Set to bufNativeStart when filling forwards. 868 // Set to computed value when filling backwards. 869 870 UChar buf[UTF8_TEXT_CHUNK_SIZE+4]; // The UChar buffer. Requires one extra position beyond the 871 // the chunk size, to allow for surrogate at the end. 872 // Length must be identical to mapToNative array, below, 873 // because of the way indexing works when the array is 874 // filled backwards during a reverse iteration. Thus, 875 // the additional extra size. 876 uint8_t mapToNative[UTF8_TEXT_CHUNK_SIZE+4]; // map UChar index in buf to 877 // native offset from bufNativeStart. 878 // Requires two extra slots, 879 // one for a supplementary starting in the last normal position, 880 // and one for an entry for the buffer limit position. 881 uint8_t mapToUChars[UTF8_TEXT_CHUNK_SIZE*3+6]; // Map native offset from bufNativeStart to 882 // correspoding offset in filled part of buf. 883 int32_t align; 884 }; 885 886 U_CDECL_BEGIN 887 888 // 889 // utf8TextLength 890 // 891 // Get the length of the string. If we don't already know it, 892 // we'll need to scan for the trailing nul. 893 // 894 static int64_t U_CALLCONV 895 utf8TextLength(UText *ut) { 896 if (ut->b < 0) { 897 // Zero terminated string, and we haven't scanned to the end yet. 898 // Scan it now. 899 const char *r = (const char *)ut->context + ut->c; 900 while (*r != 0) { 901 r++; 902 } 903 if ((r - (const char *)ut->context) < 0x7fffffff) { 904 ut->b = (int32_t)(r - (const char *)ut->context); 905 } else { 906 // Actual string was bigger (more than 2 gig) than we 907 // can handle. Clip it to 2 GB. 908 ut->b = 0x7fffffff; 909 } 910 ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 911 } 912 return ut->b; 913 } 914 915 916 917 918 919 920 static UBool U_CALLCONV 921 utf8TextAccess(UText *ut, int64_t index, UBool forward) { 922 // 923 // Apologies to those who are allergic to goto statements. 924 // Consider each goto to a labelled block to be the equivalent of 925 // call the named block as if it were a function(); 926 // return; 927 // 928 const uint8_t *s8=(const uint8_t *)ut->context; 929 UTF8Buf *u8b = NULL; 930 int32_t length = ut->b; // Length of original utf-8 931 int32_t ix= (int32_t)index; // Requested index, trimmed to 32 bits. 932 int32_t mapIndex = 0; 933 if (index<0) { 934 ix=0; 935 } else if (index > 0x7fffffff) { 936 // Strings with 64 bit lengths not supported by this UTF-8 provider. 937 ix = 0x7fffffff; 938 } 939 940 // Pin requested index to the string length. 941 if (ix>length) { 942 if (length>=0) { 943 ix=length; 944 } else if (ix>=ut->c) { 945 // Zero terminated string, and requested index is beyond 946 // the region that has already been scanned. 947 // Scan up to either the end of the string or to the 948 // requested position, whichever comes first. 949 while (ut->c<ix && s8[ut->c]!=0) { 950 ut->c++; 951 } 952 // TODO: support for null terminated string length > 32 bits. 953 if (s8[ut->c] == 0) { 954 // We just found the actual length of the string. 955 // Trim the requested index back to that. 956 ix = ut->c; 957 ut->b = ut->c; 958 length = ut->c; 959 ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 960 } 961 } 962 } 963 964 // 965 // Dispatch to the appropriate action for a forward iteration request. 966 // 967 if (forward) { 968 if (ix==ut->chunkNativeLimit) { 969 // Check for normal sequential iteration cases first. 970 if (ix==length) { 971 // Just reached end of string 972 // Don't swap buffers, but do set the 973 // current buffer position. 974 ut->chunkOffset = ut->chunkLength; 975 return FALSE; 976 } else { 977 // End of current buffer. 978 // check whether other buffer already has what we need. 979 UTF8Buf *altB = (UTF8Buf *)ut->q; 980 if (ix>=altB->bufNativeStart && ix<altB->bufNativeLimit) { 981 goto swapBuffers; 982 } 983 } 984 } 985 986 // A random access. Desired index could be in either or niether buf. 987 // For optimizing the order of testing, first check for the index 988 // being in the other buffer. This will be the case for uses that 989 // move back and forth over a fairly limited range 990 { 991 u8b = (UTF8Buf *)ut->q; // the alternate buffer 992 if (ix>=u8b->bufNativeStart && ix<u8b->bufNativeLimit) { 993 // Requested index is in the other buffer. 994 goto swapBuffers; 995 } 996 if (ix == length) { 997 // Requested index is end-of-string. 998 // (this is the case of randomly seeking to the end. 999 // The case of iterating off the end is handled earlier.) 1000 if (ix == ut->chunkNativeLimit) { 1001 // Current buffer extends up to the end of the string. 1002 // Leave it as the current buffer. 1003 ut->chunkOffset = ut->chunkLength; 1004 return FALSE; 1005 } 1006 if (ix == u8b->bufNativeLimit) { 1007 // Alternate buffer extends to the end of string. 1008 // Swap it in as the current buffer. 1009 goto swapBuffersAndFail; 1010 } 1011 1012 // Neither existing buffer extends to the end of the string. 1013 goto makeStubBuffer; 1014 } 1015 1016 if (ix<ut->chunkNativeStart || ix>=ut->chunkNativeLimit) { 1017 // Requested index is in neither buffer. 1018 goto fillForward; 1019 } 1020 1021 // Requested index is in this buffer. 1022 u8b = (UTF8Buf *)ut->p; // the current buffer 1023 mapIndex = ix - u8b->toUCharsMapStart; 1024 ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx; 1025 return TRUE; 1026 1027 } 1028 } 1029 1030 1031 // 1032 // Dispatch to the appropriate action for a 1033 // Backwards Diretion iteration request. 1034 // 1035 if (ix==ut->chunkNativeStart) { 1036 // Check for normal sequential iteration cases first. 1037 if (ix==0) { 1038 // Just reached the start of string 1039 // Don't swap buffers, but do set the 1040 // current buffer position. 1041 ut->chunkOffset = 0; 1042 return FALSE; 1043 } else { 1044 // Start of current buffer. 1045 // check whether other buffer already has what we need. 1046 UTF8Buf *altB = (UTF8Buf *)ut->q; 1047 if (ix>altB->bufNativeStart && ix<=altB->bufNativeLimit) { 1048 goto swapBuffers; 1049 } 1050 } 1051 } 1052 1053 // A random access. Desired index could be in either or niether buf. 1054 // For optimizing the order of testing, 1055 // Most likely case: in the other buffer. 1056 // Second most likely: in neither buffer. 1057 // Unlikely, but must work: in the current buffer. 1058 u8b = (UTF8Buf *)ut->q; // the alternate buffer 1059 if (ix>u8b->bufNativeStart && ix<=u8b->bufNativeLimit) { 1060 // Requested index is in the other buffer. 1061 goto swapBuffers; 1062 } 1063 // Requested index is start-of-string. 1064 // (this is the case of randomly seeking to the start. 1065 // The case of iterating off the start is handled earlier.) 1066 if (ix==0) { 1067 if (u8b->bufNativeStart==0) { 1068 // Alternate buffer contains the data for the start string. 1069 // Make it be the current buffer. 1070 goto swapBuffersAndFail; 1071 } else { 1072 // Request for data before the start of string, 1073 // neither buffer is usable. 1074 // set up a zero-length buffer. 1075 goto makeStubBuffer; 1076 } 1077 } 1078 1079 if (ix<=ut->chunkNativeStart || ix>ut->chunkNativeLimit) { 1080 // Requested index is in neither buffer. 1081 goto fillReverse; 1082 } 1083 1084 // Requested index is in this buffer. 1085 // Set the utf16 buffer index. 1086 u8b = (UTF8Buf *)ut->p; 1087 mapIndex = ix - u8b->toUCharsMapStart; 1088 ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx; 1089 if (ut->chunkOffset==0) { 1090 // This occurs when the first character in the text is 1091 // a multi-byte UTF-8 char, and the requested index is to 1092 // one of the trailing bytes. Because there is no preceding , 1093 // character, this access fails. We can't pick up on the 1094 // situation sooner because the requested index is not zero. 1095 return FALSE; 1096 } else { 1097 return TRUE; 1098 } 1099 1100 1101 1102 swapBuffers: 1103 // The alternate buffer (ut->q) has the string data that was requested. 1104 // Swap the primary and alternate buffers, and set the 1105 // chunk index into the new primary buffer. 1106 { 1107 u8b = (UTF8Buf *)ut->q; 1108 ut->q = ut->p; 1109 ut->p = u8b; 1110 ut->chunkContents = &u8b->buf[u8b->bufStartIdx]; 1111 ut->chunkLength = u8b->bufLimitIdx - u8b->bufStartIdx; 1112 ut->chunkNativeStart = u8b->bufNativeStart; 1113 ut->chunkNativeLimit = u8b->bufNativeLimit; 1114 ut->nativeIndexingLimit = u8b->bufNILimit; 1115 1116 // Index into the (now current) chunk 1117 // Use the map to set the chunk index. It's more trouble than it's worth 1118 // to check whether native indexing can be used. 1119 U_ASSERT(ix>=u8b->bufNativeStart); 1120 U_ASSERT(ix<=u8b->bufNativeLimit); 1121 mapIndex = ix - u8b->toUCharsMapStart; 1122 U_ASSERT(mapIndex>=0); 1123 U_ASSERT(mapIndex<(int32_t)sizeof(u8b->mapToUChars)); 1124 ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx; 1125 1126 return TRUE; 1127 } 1128 1129 1130 swapBuffersAndFail: 1131 // We got a request for either the start or end of the string, 1132 // with iteration continuing in the out-of-bounds direction. 1133 // The alternate buffer already contains the data up to the 1134 // start/end. 1135 // Swap the buffers, then return failure, indicating that we couldn't 1136 // make things correct for continuing the iteration in the requested 1137 // direction. The position & buffer are correct should the 1138 // user decide to iterate in the opposite direction. 1139 u8b = (UTF8Buf *)ut->q; 1140 ut->q = ut->p; 1141 ut->p = u8b; 1142 ut->chunkContents = &u8b->buf[u8b->bufStartIdx]; 1143 ut->chunkLength = u8b->bufLimitIdx - u8b->bufStartIdx; 1144 ut->chunkNativeStart = u8b->bufNativeStart; 1145 ut->chunkNativeLimit = u8b->bufNativeLimit; 1146 ut->nativeIndexingLimit = u8b->bufNILimit; 1147 1148 // Index into the (now current) chunk 1149 // For this function (swapBuffersAndFail), the requested index 1150 // will always be at either the start or end of the chunk. 1151 if (ix==u8b->bufNativeLimit) { 1152 ut->chunkOffset = ut->chunkLength; 1153 } else { 1154 ut->chunkOffset = 0; 1155 U_ASSERT(ix == u8b->bufNativeStart); 1156 } 1157 return FALSE; 1158 1159 makeStubBuffer: 1160 // The user has done a seek/access past the start or end 1161 // of the string. Rather than loading data that is likely 1162 // to never be used, just set up a zero-length buffer at 1163 // the position. 1164 u8b = (UTF8Buf *)ut->q; 1165 u8b->bufNativeStart = ix; 1166 u8b->bufNativeLimit = ix; 1167 u8b->bufStartIdx = 0; 1168 u8b->bufLimitIdx = 0; 1169 u8b->bufNILimit = 0; 1170 u8b->toUCharsMapStart = ix; 1171 u8b->mapToNative[0] = 0; 1172 u8b->mapToUChars[0] = 0; 1173 goto swapBuffersAndFail; 1174 1175 1176 1177 fillForward: 1178 { 1179 // Move the incoming index to a code point boundary. 1180 U8_SET_CP_START(s8, 0, ix); 1181 1182 // Swap the UText buffers. 1183 // We want to fill what was previously the alternate buffer, 1184 // and make what was the current buffer be the new alternate. 1185 UTF8Buf *u8b = (UTF8Buf *)ut->q; 1186 ut->q = ut->p; 1187 ut->p = u8b; 1188 1189 int32_t strLen = ut->b; 1190 UBool nulTerminated = FALSE; 1191 if (strLen < 0) { 1192 strLen = 0x7fffffff; 1193 nulTerminated = TRUE; 1194 } 1195 1196 UChar *buf = u8b->buf; 1197 uint8_t *mapToNative = u8b->mapToNative; 1198 uint8_t *mapToUChars = u8b->mapToUChars; 1199 int32_t destIx = 0; 1200 int32_t srcIx = ix; 1201 UBool seenNonAscii = FALSE; 1202 UChar32 c = 0; 1203 1204 // Fill the chunk buffer and mapping arrays. 1205 while (destIx<UTF8_TEXT_CHUNK_SIZE) { 1206 c = s8[srcIx]; 1207 if (c>0 && c<0x80) { 1208 // Special case ASCII range for speed. 1209 // zero is excluded to simplify bounds checking. 1210 buf[destIx] = (UChar)c; 1211 mapToNative[destIx] = (uint8_t)(srcIx - ix); 1212 mapToUChars[srcIx-ix] = (uint8_t)destIx; 1213 srcIx++; 1214 destIx++; 1215 } else { 1216 // General case, handle everything. 1217 if (seenNonAscii == FALSE) { 1218 seenNonAscii = TRUE; 1219 u8b->bufNILimit = destIx; 1220 } 1221 1222 int32_t cIx = srcIx; 1223 int32_t dIx = destIx; 1224 int32_t dIxSaved = destIx; 1225 U8_NEXT_OR_FFFD(s8, srcIx, strLen, c); 1226 if (c==0 && nulTerminated) { 1227 srcIx--; 1228 break; 1229 } 1230 1231 U16_APPEND_UNSAFE(buf, destIx, c); 1232 do { 1233 mapToNative[dIx++] = (uint8_t)(cIx - ix); 1234 } while (dIx < destIx); 1235 1236 do { 1237 mapToUChars[cIx++ - ix] = (uint8_t)dIxSaved; 1238 } while (cIx < srcIx); 1239 } 1240 if (srcIx>=strLen) { 1241 break; 1242 } 1243 1244 } 1245 1246 // store Native <--> Chunk Map entries for the end of the buffer. 1247 // There is no actual character here, but the index position is valid. 1248 mapToNative[destIx] = (uint8_t)(srcIx - ix); 1249 mapToUChars[srcIx - ix] = (uint8_t)destIx; 1250 1251 // fill in Buffer descriptor 1252 u8b->bufNativeStart = ix; 1253 u8b->bufNativeLimit = srcIx; 1254 u8b->bufStartIdx = 0; 1255 u8b->bufLimitIdx = destIx; 1256 if (seenNonAscii == FALSE) { 1257 u8b->bufNILimit = destIx; 1258 } 1259 u8b->toUCharsMapStart = u8b->bufNativeStart; 1260 1261 // Set UText chunk to refer to this buffer. 1262 ut->chunkContents = buf; 1263 ut->chunkOffset = 0; 1264 ut->chunkLength = u8b->bufLimitIdx; 1265 ut->chunkNativeStart = u8b->bufNativeStart; 1266 ut->chunkNativeLimit = u8b->bufNativeLimit; 1267 ut->nativeIndexingLimit = u8b->bufNILimit; 1268 1269 // For zero terminated strings, keep track of the maximum point 1270 // scanned so far. 1271 if (nulTerminated && srcIx>ut->c) { 1272 ut->c = srcIx; 1273 if (c==0) { 1274 // We scanned to the end. 1275 // Remember the actual length. 1276 ut->b = srcIx; 1277 ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 1278 } 1279 } 1280 return TRUE; 1281 } 1282 1283 1284 fillReverse: 1285 { 1286 // Move the incoming index to a code point boundary. 1287 // Can only do this if the incoming index is somewhere in the interior of the string. 1288 // If index is at the end, there is no character there to look at. 1289 if (ix != ut->b) { 1290 U8_SET_CP_START(s8, 0, ix); 1291 } 1292 1293 // Swap the UText buffers. 1294 // We want to fill what was previously the alternate buffer, 1295 // and make what was the current buffer be the new alternate. 1296 UTF8Buf *u8b = (UTF8Buf *)ut->q; 1297 ut->q = ut->p; 1298 ut->p = u8b; 1299 1300 UChar *buf = u8b->buf; 1301 uint8_t *mapToNative = u8b->mapToNative; 1302 uint8_t *mapToUChars = u8b->mapToUChars; 1303 int32_t toUCharsMapStart = ix - (UTF8_TEXT_CHUNK_SIZE*3 + 1); 1304 int32_t destIx = UTF8_TEXT_CHUNK_SIZE+2; // Start in the overflow region 1305 // at end of buffer to leave room 1306 // for a surrogate pair at the 1307 // buffer start. 1308 int32_t srcIx = ix; 1309 int32_t bufNILimit = destIx; 1310 UChar32 c; 1311 1312 // Map to/from Native Indexes, fill in for the position at the end of 1313 // the buffer. 1314 // 1315 mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart); 1316 mapToUChars[srcIx - toUCharsMapStart] = (uint8_t)destIx; 1317 1318 // Fill the chunk buffer 1319 // Work backwards, filling from the end of the buffer towards the front. 1320 // 1321 while (destIx>2 && (srcIx - toUCharsMapStart > 5) && (srcIx > 0)) { 1322 srcIx--; 1323 destIx--; 1324 1325 // Get last byte of the UTF-8 character 1326 c = s8[srcIx]; 1327 if (c<0x80) { 1328 // Special case ASCII range for speed. 1329 buf[destIx] = (UChar)c; 1330 mapToUChars[srcIx - toUCharsMapStart] = (uint8_t)destIx; 1331 mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart); 1332 } else { 1333 // General case, handle everything non-ASCII. 1334 1335 int32_t sIx = srcIx; // ix of last byte of multi-byte u8 char 1336 1337 // Get the full character from the UTF8 string. 1338 // use code derived from tbe macros in utf8.h 1339 // Leaves srcIx pointing at the first byte of the UTF-8 char. 1340 // 1341 c=utf8_prevCharSafeBody(s8, 0, &srcIx, c, -3); 1342 // leaves srcIx at first byte of the multi-byte char. 1343 1344 // Store the character in UTF-16 buffer. 1345 if (c<0x10000) { 1346 buf[destIx] = (UChar)c; 1347 mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart); 1348 } else { 1349 buf[destIx] = U16_TRAIL(c); 1350 mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart); 1351 buf[--destIx] = U16_LEAD(c); 1352 mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart); 1353 } 1354 1355 // Fill in the map from native indexes to UChars buf index. 1356 do { 1357 mapToUChars[sIx-- - toUCharsMapStart] = (uint8_t)destIx; 1358 } while (sIx >= srcIx); 1359 1360 // Set native indexing limit to be the current position. 1361 // We are processing a non-ascii, non-native-indexing char now; 1362 // the limit will be here if the rest of the chars to be 1363 // added to this buffer are ascii. 1364 bufNILimit = destIx; 1365 } 1366 } 1367 u8b->bufNativeStart = srcIx; 1368 u8b->bufNativeLimit = ix; 1369 u8b->bufStartIdx = destIx; 1370 u8b->bufLimitIdx = UTF8_TEXT_CHUNK_SIZE+2; 1371 u8b->bufNILimit = bufNILimit - u8b->bufStartIdx; 1372 u8b->toUCharsMapStart = toUCharsMapStart; 1373 1374 ut->chunkContents = &buf[u8b->bufStartIdx]; 1375 ut->chunkLength = u8b->bufLimitIdx - u8b->bufStartIdx; 1376 ut->chunkOffset = ut->chunkLength; 1377 ut->chunkNativeStart = u8b->bufNativeStart; 1378 ut->chunkNativeLimit = u8b->bufNativeLimit; 1379 ut->nativeIndexingLimit = u8b->bufNILimit; 1380 return TRUE; 1381 } 1382 1383 } 1384 1385 1386 1387 // 1388 // This is a slightly modified copy of u_strFromUTF8, 1389 // Inserts a Replacement Char rather than failing on invalid UTF-8 1390 // Removes unnecessary features. 1391 // 1392 static UChar* 1393 utext_strFromUTF8(UChar *dest, 1394 int32_t destCapacity, 1395 int32_t *pDestLength, 1396 const char* src, 1397 int32_t srcLength, // required. NUL terminated not supported. 1398 UErrorCode *pErrorCode 1399 ) 1400 { 1401 1402 UChar *pDest = dest; 1403 UChar *pDestLimit = (dest!=NULL)?(dest+destCapacity):NULL; 1404 UChar32 ch=0; 1405 int32_t index = 0; 1406 int32_t reqLength = 0; 1407 uint8_t* pSrc = (uint8_t*) src; 1408 1409 1410 while((index < srcLength)&&(pDest<pDestLimit)){ 1411 ch = pSrc[index++]; 1412 if(ch <=0x7f){ 1413 *pDest++=(UChar)ch; 1414 }else{ 1415 ch=utf8_nextCharSafeBody(pSrc, &index, srcLength, ch, -3); 1416 if(U_IS_BMP(ch)){ 1417 *(pDest++)=(UChar)ch; 1418 }else{ 1419 *(pDest++)=U16_LEAD(ch); 1420 if(pDest<pDestLimit){ 1421 *(pDest++)=U16_TRAIL(ch); 1422 }else{ 1423 reqLength++; 1424 break; 1425 } 1426 } 1427 } 1428 } 1429 /* donot fill the dest buffer just count the UChars needed */ 1430 while(index < srcLength){ 1431 ch = pSrc[index++]; 1432 if(ch <= 0x7f){ 1433 reqLength++; 1434 }else{ 1435 ch=utf8_nextCharSafeBody(pSrc, &index, srcLength, ch, -3); 1436 reqLength+=U16_LENGTH(ch); 1437 } 1438 } 1439 1440 reqLength+=(int32_t)(pDest - dest); 1441 1442 if(pDestLength){ 1443 *pDestLength = reqLength; 1444 } 1445 1446 /* Terminate the buffer */ 1447 u_terminateUChars(dest,destCapacity,reqLength,pErrorCode); 1448 1449 return dest; 1450 } 1451 1452 1453 1454 static int32_t U_CALLCONV 1455 utf8TextExtract(UText *ut, 1456 int64_t start, int64_t limit, 1457 UChar *dest, int32_t destCapacity, 1458 UErrorCode *pErrorCode) { 1459 if(U_FAILURE(*pErrorCode)) { 1460 return 0; 1461 } 1462 if(destCapacity<0 || (dest==NULL && destCapacity>0)) { 1463 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1464 return 0; 1465 } 1466 int32_t length = ut->b; 1467 int32_t start32 = pinIndex(start, length); 1468 int32_t limit32 = pinIndex(limit, length); 1469 1470 if(start32>limit32) { 1471 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 1472 return 0; 1473 } 1474 1475 1476 // adjust the incoming indexes to land on code point boundaries if needed. 1477 // adjust by no more than three, because that is the largest number of trail bytes 1478 // in a well formed UTF8 character. 1479 const uint8_t *buf = (const uint8_t *)ut->context; 1480 int i; 1481 if (start32 < ut->chunkNativeLimit) { 1482 for (i=0; i<3; i++) { 1483 if (U8_IS_SINGLE(buf[start32]) || U8_IS_LEAD(buf[start32]) || start32==0) { 1484 break; 1485 } 1486 start32--; 1487 } 1488 } 1489 1490 if (limit32 < ut->chunkNativeLimit) { 1491 for (i=0; i<3; i++) { 1492 if (U8_IS_SINGLE(buf[limit32]) || U8_IS_LEAD(buf[limit32]) || limit32==0) { 1493 break; 1494 } 1495 limit32--; 1496 } 1497 } 1498 1499 // Do the actual extract. 1500 int32_t destLength=0; 1501 utext_strFromUTF8(dest, destCapacity, &destLength, 1502 (const char *)ut->context+start32, limit32-start32, 1503 pErrorCode); 1504 utf8TextAccess(ut, limit32, TRUE); 1505 return destLength; 1506 } 1507 1508 // 1509 // utf8TextMapOffsetToNative 1510 // 1511 // Map a chunk (UTF-16) offset to a native index. 1512 static int64_t U_CALLCONV 1513 utf8TextMapOffsetToNative(const UText *ut) { 1514 // 1515 UTF8Buf *u8b = (UTF8Buf *)ut->p; 1516 U_ASSERT(ut->chunkOffset>ut->nativeIndexingLimit && ut->chunkOffset<=ut->chunkLength); 1517 int32_t nativeOffset = u8b->mapToNative[ut->chunkOffset + u8b->bufStartIdx] + u8b->toUCharsMapStart; 1518 U_ASSERT(nativeOffset >= ut->chunkNativeStart && nativeOffset <= ut->chunkNativeLimit); 1519 return nativeOffset; 1520 } 1521 1522 // 1523 // Map a native index to the corrsponding chunk offset 1524 // 1525 static int32_t U_CALLCONV 1526 utf8TextMapIndexToUTF16(const UText *ut, int64_t index64) { 1527 U_ASSERT(index64 <= 0x7fffffff); 1528 int32_t index = (int32_t)index64; 1529 UTF8Buf *u8b = (UTF8Buf *)ut->p; 1530 U_ASSERT(index>=ut->chunkNativeStart+ut->nativeIndexingLimit); 1531 U_ASSERT(index<=ut->chunkNativeLimit); 1532 int32_t mapIndex = index - u8b->toUCharsMapStart; 1533 int32_t offset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx; 1534 U_ASSERT(offset>=0 && offset<=ut->chunkLength); 1535 return offset; 1536 } 1537 1538 static UText * U_CALLCONV 1539 utf8TextClone(UText *dest, const UText *src, UBool deep, UErrorCode *status) 1540 { 1541 // First do a generic shallow clone. Does everything needed for the UText struct itself. 1542 dest = shallowTextClone(dest, src, status); 1543 1544 // For deep clones, make a copy of the string. 1545 // The copied storage is owned by the newly created clone. 1546 // 1547 // TODO: There is an isssue with using utext_nativeLength(). 1548 // That function is non-const in cases where the input was NUL terminated 1549 // and the length has not yet been determined. 1550 // This function (clone()) is const. 1551 // There potentially a thread safety issue lurking here. 1552 // 1553 if (deep && U_SUCCESS(*status)) { 1554 int32_t len = (int32_t)utext_nativeLength((UText *)src); 1555 char *copyStr = (char *)uprv_malloc(len+1); 1556 if (copyStr == NULL) { 1557 *status = U_MEMORY_ALLOCATION_ERROR; 1558 } else { 1559 uprv_memcpy(copyStr, src->context, len+1); 1560 dest->context = copyStr; 1561 dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT); 1562 } 1563 } 1564 return dest; 1565 } 1566 1567 1568 static void U_CALLCONV 1569 utf8TextClose(UText *ut) { 1570 // Most of the work of close is done by the generic UText framework close. 1571 // All that needs to be done here is to delete the UTF8 string if the UText 1572 // owns it. This occurs if the UText was created by cloning. 1573 if (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT)) { 1574 char *s = (char *)ut->context; 1575 uprv_free(s); 1576 ut->context = NULL; 1577 } 1578 } 1579 1580 U_CDECL_END 1581 1582 1583 static const struct UTextFuncs utf8Funcs = 1584 { 1585 sizeof(UTextFuncs), 1586 0, 0, 0, // Reserved alignment padding 1587 utf8TextClone, 1588 utf8TextLength, 1589 utf8TextAccess, 1590 utf8TextExtract, 1591 NULL, /* replace*/ 1592 NULL, /* copy */ 1593 utf8TextMapOffsetToNative, 1594 utf8TextMapIndexToUTF16, 1595 utf8TextClose, 1596 NULL, // spare 1 1597 NULL, // spare 2 1598 NULL // spare 3 1599 }; 1600 1601 1602 static const char gEmptyString[] = {0}; 1603 1604 U_CAPI UText * U_EXPORT2 1605 utext_openUTF8(UText *ut, const char *s, int64_t length, UErrorCode *status) { 1606 if(U_FAILURE(*status)) { 1607 return NULL; 1608 } 1609 if(s==NULL && length==0) { 1610 s = gEmptyString; 1611 } 1612 1613 if(s==NULL || length<-1 || length>INT32_MAX) { 1614 *status=U_ILLEGAL_ARGUMENT_ERROR; 1615 return NULL; 1616 } 1617 1618 ut = utext_setup(ut, sizeof(UTF8Buf) * 2, status); 1619 if (U_FAILURE(*status)) { 1620 return ut; 1621 } 1622 1623 ut->pFuncs = &utf8Funcs; 1624 ut->context = s; 1625 ut->b = (int32_t)length; 1626 ut->c = (int32_t)length; 1627 if (ut->c < 0) { 1628 ut->c = 0; 1629 ut->providerProperties |= I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 1630 } 1631 ut->p = ut->pExtra; 1632 ut->q = (char *)ut->pExtra + sizeof(UTF8Buf); 1633 return ut; 1634 1635 } 1636 1637 1638 1639 1640 1641 1642 1643 1644 //------------------------------------------------------------------------------ 1645 // 1646 // UText implementation wrapper for Replaceable (read/write) 1647 // 1648 // Use of UText data members: 1649 // context pointer to Replaceable. 1650 // p pointer to Replaceable if it is owned by the UText. 1651 // 1652 //------------------------------------------------------------------------------ 1653 1654 1655 1656 // minimum chunk size for this implementation: 3 1657 // to allow for possible trimming for code point boundaries 1658 enum { REP_TEXT_CHUNK_SIZE=10 }; 1659 1660 struct ReplExtra { 1661 /* 1662 * Chunk UChars. 1663 * +1 to simplify filling with surrogate pair at the end. 1664 */ 1665 UChar s[REP_TEXT_CHUNK_SIZE+1]; 1666 }; 1667 1668 1669 U_CDECL_BEGIN 1670 1671 static UText * U_CALLCONV 1672 repTextClone(UText *dest, const UText *src, UBool deep, UErrorCode *status) { 1673 // First do a generic shallow clone. Does everything needed for the UText struct itself. 1674 dest = shallowTextClone(dest, src, status); 1675 1676 // For deep clones, make a copy of the Replaceable. 1677 // The copied Replaceable storage is owned by the newly created UText clone. 1678 // A non-NULL pointer in UText.p is the signal to the close() function to delete 1679 // it. 1680 // 1681 if (deep && U_SUCCESS(*status)) { 1682 const Replaceable *replSrc = (const Replaceable *)src->context; 1683 dest->context = replSrc->clone(); 1684 dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT); 1685 1686 // with deep clone, the copy is writable, even when the source is not. 1687 dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_WRITABLE); 1688 } 1689 return dest; 1690 } 1691 1692 1693 static void U_CALLCONV 1694 repTextClose(UText *ut) { 1695 // Most of the work of close is done by the generic UText framework close. 1696 // All that needs to be done here is delete the Replaceable if the UText 1697 // owns it. This occurs if the UText was created by cloning. 1698 if (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT)) { 1699 Replaceable *rep = (Replaceable *)ut->context; 1700 delete rep; 1701 ut->context = NULL; 1702 } 1703 } 1704 1705 1706 static int64_t U_CALLCONV 1707 repTextLength(UText *ut) { 1708 const Replaceable *replSrc = (const Replaceable *)ut->context; 1709 int32_t len = replSrc->length(); 1710 return len; 1711 } 1712 1713 1714 static UBool U_CALLCONV 1715 repTextAccess(UText *ut, int64_t index, UBool forward) { 1716 const Replaceable *rep=(const Replaceable *)ut->context; 1717 int32_t length=rep->length(); // Full length of the input text (bigger than a chunk) 1718 1719 // clip the requested index to the limits of the text. 1720 int32_t index32 = pinIndex(index, length); 1721 U_ASSERT(index<=INT32_MAX); 1722 1723 1724 /* 1725 * Compute start/limit boundaries around index, for a segment of text 1726 * to be extracted. 1727 * To allow for the possibility that our user gave an index to the trailing 1728 * half of a surrogate pair, we must request one extra preceding UChar when 1729 * going in the forward direction. This will ensure that the buffer has the 1730 * entire code point at the specified index. 1731 */ 1732 if(forward) { 1733 1734 if (index32>=ut->chunkNativeStart && index32<ut->chunkNativeLimit) { 1735 // Buffer already contains the requested position. 1736 ut->chunkOffset = (int32_t)(index - ut->chunkNativeStart); 1737 return TRUE; 1738 } 1739 if (index32>=length && ut->chunkNativeLimit==length) { 1740 // Request for end of string, and buffer already extends up to it. 1741 // Can't get the data, but don't change the buffer. 1742 ut->chunkOffset = length - (int32_t)ut->chunkNativeStart; 1743 return FALSE; 1744 } 1745 1746 ut->chunkNativeLimit = index + REP_TEXT_CHUNK_SIZE - 1; 1747 // Going forward, so we want to have the buffer with stuff at and beyond 1748 // the requested index. The -1 gets us one code point before the 1749 // requested index also, to handle the case of the index being on 1750 // a trail surrogate of a surrogate pair. 1751 if(ut->chunkNativeLimit > length) { 1752 ut->chunkNativeLimit = length; 1753 } 1754 // unless buffer ran off end, start is index-1. 1755 ut->chunkNativeStart = ut->chunkNativeLimit - REP_TEXT_CHUNK_SIZE; 1756 if(ut->chunkNativeStart < 0) { 1757 ut->chunkNativeStart = 0; 1758 } 1759 } else { 1760 // Reverse iteration. Fill buffer with data preceding the requested index. 1761 if (index32>ut->chunkNativeStart && index32<=ut->chunkNativeLimit) { 1762 // Requested position already in buffer. 1763 ut->chunkOffset = index32 - (int32_t)ut->chunkNativeStart; 1764 return TRUE; 1765 } 1766 if (index32==0 && ut->chunkNativeStart==0) { 1767 // Request for start, buffer already begins at start. 1768 // No data, but keep the buffer as is. 1769 ut->chunkOffset = 0; 1770 return FALSE; 1771 } 1772 1773 // Figure out the bounds of the chunk to extract for reverse iteration. 1774 // Need to worry about chunk not splitting surrogate pairs, and while still 1775 // containing the data we need. 1776 // Fix by requesting a chunk that includes an extra UChar at the end. 1777 // If this turns out to be a lead surrogate, we can lop it off and still have 1778 // the data we wanted. 1779 ut->chunkNativeStart = index32 + 1 - REP_TEXT_CHUNK_SIZE; 1780 if (ut->chunkNativeStart < 0) { 1781 ut->chunkNativeStart = 0; 1782 } 1783 1784 ut->chunkNativeLimit = index32 + 1; 1785 if (ut->chunkNativeLimit > length) { 1786 ut->chunkNativeLimit = length; 1787 } 1788 } 1789 1790 // Extract the new chunk of text from the Replaceable source. 1791 ReplExtra *ex = (ReplExtra *)ut->pExtra; 1792 // UnicodeString with its buffer a writable alias to the chunk buffer 1793 UnicodeString buffer(ex->s, 0 /*buffer length*/, REP_TEXT_CHUNK_SIZE /*buffer capacity*/); 1794 rep->extractBetween((int32_t)ut->chunkNativeStart, (int32_t)ut->chunkNativeLimit, buffer); 1795 1796 ut->chunkContents = ex->s; 1797 ut->chunkLength = (int32_t)(ut->chunkNativeLimit - ut->chunkNativeStart); 1798 ut->chunkOffset = (int32_t)(index32 - ut->chunkNativeStart); 1799 1800 // Surrogate pairs from the input text must not span chunk boundaries. 1801 // If end of chunk could be the start of a surrogate, trim it off. 1802 if (ut->chunkNativeLimit < length && 1803 U16_IS_LEAD(ex->s[ut->chunkLength-1])) { 1804 ut->chunkLength--; 1805 ut->chunkNativeLimit--; 1806 if (ut->chunkOffset > ut->chunkLength) { 1807 ut->chunkOffset = ut->chunkLength; 1808 } 1809 } 1810 1811 // if the first UChar in the chunk could be the trailing half of a surrogate pair, 1812 // trim it off. 1813 if(ut->chunkNativeStart>0 && U16_IS_TRAIL(ex->s[0])) { 1814 ++(ut->chunkContents); 1815 ++(ut->chunkNativeStart); 1816 --(ut->chunkLength); 1817 --(ut->chunkOffset); 1818 } 1819 1820 // adjust the index/chunkOffset to a code point boundary 1821 U16_SET_CP_START(ut->chunkContents, 0, ut->chunkOffset); 1822 1823 // Use fast indexing for get/setNativeIndex() 1824 ut->nativeIndexingLimit = ut->chunkLength; 1825 1826 return TRUE; 1827 } 1828 1829 1830 1831 static int32_t U_CALLCONV 1832 repTextExtract(UText *ut, 1833 int64_t start, int64_t limit, 1834 UChar *dest, int32_t destCapacity, 1835 UErrorCode *status) { 1836 const Replaceable *rep=(const Replaceable *)ut->context; 1837 int32_t length=rep->length(); 1838 1839 if(U_FAILURE(*status)) { 1840 return 0; 1841 } 1842 if(destCapacity<0 || (dest==NULL && destCapacity>0)) { 1843 *status=U_ILLEGAL_ARGUMENT_ERROR; 1844 } 1845 if(start>limit) { 1846 *status=U_INDEX_OUTOFBOUNDS_ERROR; 1847 return 0; 1848 } 1849 1850 int32_t start32 = pinIndex(start, length); 1851 int32_t limit32 = pinIndex(limit, length); 1852 1853 // adjust start, limit if they point to trail half of surrogates 1854 if (start32<length && U16_IS_TRAIL(rep->charAt(start32)) && 1855 U_IS_SUPPLEMENTARY(rep->char32At(start32))){ 1856 start32--; 1857 } 1858 if (limit32<length && U16_IS_TRAIL(rep->charAt(limit32)) && 1859 U_IS_SUPPLEMENTARY(rep->char32At(limit32))){ 1860 limit32--; 1861 } 1862 1863 length=limit32-start32; 1864 if(length>destCapacity) { 1865 limit32 = start32 + destCapacity; 1866 } 1867 UnicodeString buffer(dest, 0, destCapacity); // writable alias 1868 rep->extractBetween(start32, limit32, buffer); 1869 repTextAccess(ut, limit32, TRUE); 1870 1871 return u_terminateUChars(dest, destCapacity, length, status); 1872 } 1873 1874 static int32_t U_CALLCONV 1875 repTextReplace(UText *ut, 1876 int64_t start, int64_t limit, 1877 const UChar *src, int32_t length, 1878 UErrorCode *status) { 1879 Replaceable *rep=(Replaceable *)ut->context; 1880 int32_t oldLength; 1881 1882 if(U_FAILURE(*status)) { 1883 return 0; 1884 } 1885 if(src==NULL && length!=0) { 1886 *status=U_ILLEGAL_ARGUMENT_ERROR; 1887 return 0; 1888 } 1889 oldLength=rep->length(); // will subtract from new length 1890 if(start>limit ) { 1891 *status=U_INDEX_OUTOFBOUNDS_ERROR; 1892 return 0; 1893 } 1894 1895 int32_t start32 = pinIndex(start, oldLength); 1896 int32_t limit32 = pinIndex(limit, oldLength); 1897 1898 // Snap start & limit to code point boundaries. 1899 if (start32<oldLength && U16_IS_TRAIL(rep->charAt(start32)) && 1900 start32>0 && U16_IS_LEAD(rep->charAt(start32-1))) 1901 { 1902 start32--; 1903 } 1904 if (limit32<oldLength && U16_IS_LEAD(rep->charAt(limit32-1)) && 1905 U16_IS_TRAIL(rep->charAt(limit32))) 1906 { 1907 limit32++; 1908 } 1909 1910 // Do the actual replace operation using methods of the Replaceable class 1911 UnicodeString replStr((UBool)(length<0), src, length); // read-only alias 1912 rep->handleReplaceBetween(start32, limit32, replStr); 1913 int32_t newLength = rep->length(); 1914 int32_t lengthDelta = newLength - oldLength; 1915 1916 // Is the UText chunk buffer OK? 1917 if (ut->chunkNativeLimit > start32) { 1918 // this replace operation may have impacted the current chunk. 1919 // invalidate it, which will force a reload on the next access. 1920 invalidateChunk(ut); 1921 } 1922 1923 // set the iteration position to the end of the newly inserted replacement text. 1924 int32_t newIndexPos = limit32 + lengthDelta; 1925 repTextAccess(ut, newIndexPos, TRUE); 1926 1927 return lengthDelta; 1928 } 1929 1930 1931 static void U_CALLCONV 1932 repTextCopy(UText *ut, 1933 int64_t start, int64_t limit, 1934 int64_t destIndex, 1935 UBool move, 1936 UErrorCode *status) 1937 { 1938 Replaceable *rep=(Replaceable *)ut->context; 1939 int32_t length=rep->length(); 1940 1941 if(U_FAILURE(*status)) { 1942 return; 1943 } 1944 if (start>limit || (start<destIndex && destIndex<limit)) 1945 { 1946 *status=U_INDEX_OUTOFBOUNDS_ERROR; 1947 return; 1948 } 1949 1950 int32_t start32 = pinIndex(start, length); 1951 int32_t limit32 = pinIndex(limit, length); 1952 int32_t destIndex32 = pinIndex(destIndex, length); 1953 1954 // TODO: snap input parameters to code point boundaries. 1955 1956 if(move) { 1957 // move: copy to destIndex, then replace original with nothing 1958 int32_t segLength=limit32-start32; 1959 rep->copy(start32, limit32, destIndex32); 1960 if(destIndex32<start32) { 1961 start32+=segLength; 1962 limit32+=segLength; 1963 } 1964 rep->handleReplaceBetween(start32, limit32, UnicodeString()); 1965 } else { 1966 // copy 1967 rep->copy(start32, limit32, destIndex32); 1968 } 1969 1970 // If the change to the text touched the region in the chunk buffer, 1971 // invalidate the buffer. 1972 int32_t firstAffectedIndex = destIndex32; 1973 if (move && start32<firstAffectedIndex) { 1974 firstAffectedIndex = start32; 1975 } 1976 if (firstAffectedIndex < ut->chunkNativeLimit) { 1977 // changes may have affected range covered by the chunk 1978 invalidateChunk(ut); 1979 } 1980 1981 // Put iteration position at the newly inserted (moved) block, 1982 int32_t nativeIterIndex = destIndex32 + limit32 - start32; 1983 if (move && destIndex32>start32) { 1984 // moved a block of text towards the end of the string. 1985 nativeIterIndex = destIndex32; 1986 } 1987 1988 // Set position, reload chunk if needed. 1989 repTextAccess(ut, nativeIterIndex, TRUE); 1990 } 1991 1992 static const struct UTextFuncs repFuncs = 1993 { 1994 sizeof(UTextFuncs), 1995 0, 0, 0, // Reserved alignment padding 1996 repTextClone, 1997 repTextLength, 1998 repTextAccess, 1999 repTextExtract, 2000 repTextReplace, 2001 repTextCopy, 2002 NULL, // MapOffsetToNative, 2003 NULL, // MapIndexToUTF16, 2004 repTextClose, 2005 NULL, // spare 1 2006 NULL, // spare 2 2007 NULL // spare 3 2008 }; 2009 2010 2011 U_CAPI UText * U_EXPORT2 2012 utext_openReplaceable(UText *ut, Replaceable *rep, UErrorCode *status) 2013 { 2014 if(U_FAILURE(*status)) { 2015 return NULL; 2016 } 2017 if(rep==NULL) { 2018 *status=U_ILLEGAL_ARGUMENT_ERROR; 2019 return NULL; 2020 } 2021 ut = utext_setup(ut, sizeof(ReplExtra), status); 2022 2023 ut->providerProperties = I32_FLAG(UTEXT_PROVIDER_WRITABLE); 2024 if(rep->hasMetaData()) { 2025 ut->providerProperties |=I32_FLAG(UTEXT_PROVIDER_HAS_META_DATA); 2026 } 2027 2028 ut->pFuncs = &repFuncs; 2029 ut->context = rep; 2030 return ut; 2031 } 2032 2033 U_CDECL_END 2034 2035 2036 2037 2038 2039 2040 2041 2042 //------------------------------------------------------------------------------ 2043 // 2044 // UText implementation for UnicodeString (read/write) and 2045 // for const UnicodeString (read only) 2046 // (same implementation, only the flags are different) 2047 // 2048 // Use of UText data members: 2049 // context pointer to UnicodeString 2050 // p pointer to UnicodeString IF this UText owns the string 2051 // and it must be deleted on close(). NULL otherwise. 2052 // 2053 //------------------------------------------------------------------------------ 2054 2055 U_CDECL_BEGIN 2056 2057 2058 static UText * U_CALLCONV 2059 unistrTextClone(UText *dest, const UText *src, UBool deep, UErrorCode *status) { 2060 // First do a generic shallow clone. Does everything needed for the UText struct itself. 2061 dest = shallowTextClone(dest, src, status); 2062 2063 // For deep clones, make a copy of the UnicodeSring. 2064 // The copied UnicodeString storage is owned by the newly created UText clone. 2065 // A non-NULL pointer in UText.p is the signal to the close() function to delete 2066 // the UText. 2067 // 2068 if (deep && U_SUCCESS(*status)) { 2069 const UnicodeString *srcString = (const UnicodeString *)src->context; 2070 dest->context = new UnicodeString(*srcString); 2071 dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT); 2072 2073 // with deep clone, the copy is writable, even when the source is not. 2074 dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_WRITABLE); 2075 } 2076 return dest; 2077 } 2078 2079 static void U_CALLCONV 2080 unistrTextClose(UText *ut) { 2081 // Most of the work of close is done by the generic UText framework close. 2082 // All that needs to be done here is delete the UnicodeString if the UText 2083 // owns it. This occurs if the UText was created by cloning. 2084 if (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT)) { 2085 UnicodeString *str = (UnicodeString *)ut->context; 2086 delete str; 2087 ut->context = NULL; 2088 } 2089 } 2090 2091 2092 static int64_t U_CALLCONV 2093 unistrTextLength(UText *t) { 2094 return ((const UnicodeString *)t->context)->length(); 2095 } 2096 2097 2098 static UBool U_CALLCONV 2099 unistrTextAccess(UText *ut, int64_t index, UBool forward) { 2100 int32_t length = ut->chunkLength; 2101 ut->chunkOffset = pinIndex(index, length); 2102 2103 // Check whether request is at the start or end 2104 UBool retVal = (forward && index<length) || (!forward && index>0); 2105 return retVal; 2106 } 2107 2108 2109 2110 static int32_t U_CALLCONV 2111 unistrTextExtract(UText *t, 2112 int64_t start, int64_t limit, 2113 UChar *dest, int32_t destCapacity, 2114 UErrorCode *pErrorCode) { 2115 const UnicodeString *us=(const UnicodeString *)t->context; 2116 int32_t length=us->length(); 2117 2118 if(U_FAILURE(*pErrorCode)) { 2119 return 0; 2120 } 2121 if(destCapacity<0 || (dest==NULL && destCapacity>0)) { 2122 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 2123 } 2124 if(start<0 || start>limit) { 2125 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 2126 return 0; 2127 } 2128 2129 int32_t start32 = start<length ? us->getChar32Start((int32_t)start) : length; 2130 int32_t limit32 = limit<length ? us->getChar32Start((int32_t)limit) : length; 2131 2132 length=limit32-start32; 2133 if (destCapacity>0 && dest!=NULL) { 2134 int32_t trimmedLength = length; 2135 if(trimmedLength>destCapacity) { 2136 trimmedLength=destCapacity; 2137 } 2138 us->extract(start32, trimmedLength, dest); 2139 t->chunkOffset = start32+trimmedLength; 2140 } else { 2141 t->chunkOffset = start32; 2142 } 2143 u_terminateUChars(dest, destCapacity, length, pErrorCode); 2144 return length; 2145 } 2146 2147 static int32_t U_CALLCONV 2148 unistrTextReplace(UText *ut, 2149 int64_t start, int64_t limit, 2150 const UChar *src, int32_t length, 2151 UErrorCode *pErrorCode) { 2152 UnicodeString *us=(UnicodeString *)ut->context; 2153 int32_t oldLength; 2154 2155 if(U_FAILURE(*pErrorCode)) { 2156 return 0; 2157 } 2158 if(src==NULL && length!=0) { 2159 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 2160 } 2161 if(start>limit) { 2162 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 2163 return 0; 2164 } 2165 oldLength=us->length(); 2166 int32_t start32 = pinIndex(start, oldLength); 2167 int32_t limit32 = pinIndex(limit, oldLength); 2168 if (start32 < oldLength) { 2169 start32 = us->getChar32Start(start32); 2170 } 2171 if (limit32 < oldLength) { 2172 limit32 = us->getChar32Start(limit32); 2173 } 2174 2175 // replace 2176 us->replace(start32, limit32-start32, src, length); 2177 int32_t newLength = us->length(); 2178 2179 // Update the chunk description. 2180 ut->chunkContents = us->getBuffer(); 2181 ut->chunkLength = newLength; 2182 ut->chunkNativeLimit = newLength; 2183 ut->nativeIndexingLimit = newLength; 2184 2185 // Set iteration position to the point just following the newly inserted text. 2186 int32_t lengthDelta = newLength - oldLength; 2187 ut->chunkOffset = limit32 + lengthDelta; 2188 2189 return lengthDelta; 2190 } 2191 2192 static void U_CALLCONV 2193 unistrTextCopy(UText *ut, 2194 int64_t start, int64_t limit, 2195 int64_t destIndex, 2196 UBool move, 2197 UErrorCode *pErrorCode) { 2198 UnicodeString *us=(UnicodeString *)ut->context; 2199 int32_t length=us->length(); 2200 2201 if(U_FAILURE(*pErrorCode)) { 2202 return; 2203 } 2204 int32_t start32 = pinIndex(start, length); 2205 int32_t limit32 = pinIndex(limit, length); 2206 int32_t destIndex32 = pinIndex(destIndex, length); 2207 2208 if( start32>limit32 || (start32<destIndex32 && destIndex32<limit32)) { 2209 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 2210 return; 2211 } 2212 2213 if(move) { 2214 // move: copy to destIndex, then replace original with nothing 2215 int32_t segLength=limit32-start32; 2216 us->copy(start32, limit32, destIndex32); 2217 if(destIndex32<start32) { 2218 start32+=segLength; 2219 } 2220 us->replace(start32, segLength, NULL, 0); 2221 } else { 2222 // copy 2223 us->copy(start32, limit32, destIndex32); 2224 } 2225 2226 // update chunk description, set iteration position. 2227 ut->chunkContents = us->getBuffer(); 2228 if (move==FALSE) { 2229 // copy operation, string length grows 2230 ut->chunkLength += limit32-start32; 2231 ut->chunkNativeLimit = ut->chunkLength; 2232 ut->nativeIndexingLimit = ut->chunkLength; 2233 } 2234 2235 // Iteration position to end of the newly inserted text. 2236 ut->chunkOffset = destIndex32+limit32-start32; 2237 if (move && destIndex32>start32) { 2238 ut->chunkOffset = destIndex32; 2239 } 2240 2241 } 2242 2243 static const struct UTextFuncs unistrFuncs = 2244 { 2245 sizeof(UTextFuncs), 2246 0, 0, 0, // Reserved alignment padding 2247 unistrTextClone, 2248 unistrTextLength, 2249 unistrTextAccess, 2250 unistrTextExtract, 2251 unistrTextReplace, 2252 unistrTextCopy, 2253 NULL, // MapOffsetToNative, 2254 NULL, // MapIndexToUTF16, 2255 unistrTextClose, 2256 NULL, // spare 1 2257 NULL, // spare 2 2258 NULL // spare 3 2259 }; 2260 2261 2262 2263 U_CDECL_END 2264 2265 2266 U_CAPI UText * U_EXPORT2 2267 utext_openUnicodeString(UText *ut, UnicodeString *s, UErrorCode *status) { 2268 ut = utext_openConstUnicodeString(ut, s, status); 2269 if (U_SUCCESS(*status)) { 2270 ut->providerProperties |= I32_FLAG(UTEXT_PROVIDER_WRITABLE); 2271 } 2272 return ut; 2273 } 2274 2275 2276 2277 U_CAPI UText * U_EXPORT2 2278 utext_openConstUnicodeString(UText *ut, const UnicodeString *s, UErrorCode *status) { 2279 if (U_SUCCESS(*status) && s->isBogus()) { 2280 // The UnicodeString is bogus, but we still need to detach the UText 2281 // from whatever it was hooked to before, if anything. 2282 utext_openUChars(ut, NULL, 0, status); 2283 *status = U_ILLEGAL_ARGUMENT_ERROR; 2284 return ut; 2285 } 2286 ut = utext_setup(ut, 0, status); 2287 // note: use the standard (writable) function table for UnicodeString. 2288 // The flag settings disable writing, so having the functions in 2289 // the table is harmless. 2290 if (U_SUCCESS(*status)) { 2291 ut->pFuncs = &unistrFuncs; 2292 ut->context = s; 2293 ut->providerProperties = I32_FLAG(UTEXT_PROVIDER_STABLE_CHUNKS); 2294 ut->chunkContents = s->getBuffer(); 2295 ut->chunkLength = s->length(); 2296 ut->chunkNativeStart = 0; 2297 ut->chunkNativeLimit = ut->chunkLength; 2298 ut->nativeIndexingLimit = ut->chunkLength; 2299 } 2300 return ut; 2301 } 2302 2303 //------------------------------------------------------------------------------ 2304 // 2305 // UText implementation for const UChar * strings 2306 // 2307 // Use of UText data members: 2308 // context pointer to UnicodeString 2309 // a length. -1 if not yet known. 2310 // 2311 // TODO: support 64 bit lengths. 2312 // 2313 //------------------------------------------------------------------------------ 2314 2315 U_CDECL_BEGIN 2316 2317 2318 static UText * U_CALLCONV 2319 ucstrTextClone(UText *dest, const UText * src, UBool deep, UErrorCode * status) { 2320 // First do a generic shallow clone. 2321 dest = shallowTextClone(dest, src, status); 2322 2323 // For deep clones, make a copy of the string. 2324 // The copied storage is owned by the newly created clone. 2325 // A non-NULL pointer in UText.p is the signal to the close() function to delete 2326 // it. 2327 // 2328 if (deep && U_SUCCESS(*status)) { 2329 U_ASSERT(utext_nativeLength(dest) < INT32_MAX); 2330 int32_t len = (int32_t)utext_nativeLength(dest); 2331 2332 // The cloned string IS going to be NUL terminated, whether or not the original was. 2333 const UChar *srcStr = (const UChar *)src->context; 2334 UChar *copyStr = (UChar *)uprv_malloc((len+1) * sizeof(UChar)); 2335 if (copyStr == NULL) { 2336 *status = U_MEMORY_ALLOCATION_ERROR; 2337 } else { 2338 int64_t i; 2339 for (i=0; i<len; i++) { 2340 copyStr[i] = srcStr[i]; 2341 } 2342 copyStr[len] = 0; 2343 dest->context = copyStr; 2344 dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT); 2345 } 2346 } 2347 return dest; 2348 } 2349 2350 2351 static void U_CALLCONV 2352 ucstrTextClose(UText *ut) { 2353 // Most of the work of close is done by the generic UText framework close. 2354 // All that needs to be done here is delete the string if the UText 2355 // owns it. This occurs if the UText was created by cloning. 2356 if (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT)) { 2357 UChar *s = (UChar *)ut->context; 2358 uprv_free(s); 2359 ut->context = NULL; 2360 } 2361 } 2362 2363 2364 2365 static int64_t U_CALLCONV 2366 ucstrTextLength(UText *ut) { 2367 if (ut->a < 0) { 2368 // null terminated, we don't yet know the length. Scan for it. 2369 // Access is not convenient for doing this 2370 // because the current interation postion can't be changed. 2371 const UChar *str = (const UChar *)ut->context; 2372 for (;;) { 2373 if (str[ut->chunkNativeLimit] == 0) { 2374 break; 2375 } 2376 ut->chunkNativeLimit++; 2377 } 2378 ut->a = ut->chunkNativeLimit; 2379 ut->chunkLength = (int32_t)ut->chunkNativeLimit; 2380 ut->nativeIndexingLimit = ut->chunkLength; 2381 ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 2382 } 2383 return ut->a; 2384 } 2385 2386 2387 static UBool U_CALLCONV 2388 ucstrTextAccess(UText *ut, int64_t index, UBool forward) { 2389 const UChar *str = (const UChar *)ut->context; 2390 2391 // pin the requested index to the bounds of the string, 2392 // and set current iteration position. 2393 if (index<0) { 2394 index = 0; 2395 } else if (index < ut->chunkNativeLimit) { 2396 // The request data is within the chunk as it is known so far. 2397 // Put index on a code point boundary. 2398 U16_SET_CP_START(str, 0, index); 2399 } else if (ut->a >= 0) { 2400 // We know the length of this string, and the user is requesting something 2401 // at or beyond the length. Pin the requested index to the length. 2402 index = ut->a; 2403 } else { 2404 // Null terminated string, length not yet known, and the requested index 2405 // is beyond where we have scanned so far. 2406 // Scan to 32 UChars beyond the requested index. The strategy here is 2407 // to avoid fully scanning a long string when the caller only wants to 2408 // see a few characters at its beginning. 2409 int32_t scanLimit = (int32_t)index + 32; 2410 if ((index + 32)>INT32_MAX || (index + 32)<0 ) { // note: int64 expression 2411 scanLimit = INT32_MAX; 2412 } 2413 2414 int32_t chunkLimit = (int32_t)ut->chunkNativeLimit; 2415 for (; chunkLimit<scanLimit; chunkLimit++) { 2416 if (str[chunkLimit] == 0) { 2417 // We found the end of the string. Remember it, pin the requested index to it, 2418 // and bail out of here. 2419 ut->a = chunkLimit; 2420 ut->chunkLength = chunkLimit; 2421 ut->nativeIndexingLimit = chunkLimit; 2422 if (index >= chunkLimit) { 2423 index = chunkLimit; 2424 } else { 2425 U16_SET_CP_START(str, 0, index); 2426 } 2427 2428 ut->chunkNativeLimit = chunkLimit; 2429 ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 2430 goto breakout; 2431 } 2432 } 2433 // We scanned through the next batch of UChars without finding the end. 2434 U16_SET_CP_START(str, 0, index); 2435 if (chunkLimit == INT32_MAX) { 2436 // Scanned to the limit of a 32 bit length. 2437 // Forceably trim the overlength string back so length fits in int32 2438 // TODO: add support for 64 bit strings. 2439 ut->a = chunkLimit; 2440 ut->chunkLength = chunkLimit; 2441 ut->nativeIndexingLimit = chunkLimit; 2442 if (index > chunkLimit) { 2443 index = chunkLimit; 2444 } 2445 ut->chunkNativeLimit = chunkLimit; 2446 ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 2447 } else { 2448 // The endpoint of a chunk must not be left in the middle of a surrogate pair. 2449 // If the current end is on a lead surrogate, back the end up by one. 2450 // It doesn't matter if the end char happens to be an unpaired surrogate, 2451 // and it's simpler not to worry about it. 2452 if (U16_IS_LEAD(str[chunkLimit-1])) { 2453 --chunkLimit; 2454 } 2455 // Null-terminated chunk with end still unknown. 2456 // Update the chunk length to reflect what has been scanned thus far. 2457 // That the full length is still unknown is (still) flagged by 2458 // ut->a being < 0. 2459 ut->chunkNativeLimit = chunkLimit; 2460 ut->nativeIndexingLimit = chunkLimit; 2461 ut->chunkLength = chunkLimit; 2462 } 2463 2464 } 2465 breakout: 2466 U_ASSERT(index<=INT32_MAX); 2467 ut->chunkOffset = (int32_t)index; 2468 2469 // Check whether request is at the start or end 2470 UBool retVal = (forward && index<ut->chunkNativeLimit) || (!forward && index>0); 2471 return retVal; 2472 } 2473 2474 2475 2476 static int32_t U_CALLCONV 2477 ucstrTextExtract(UText *ut, 2478 int64_t start, int64_t limit, 2479 UChar *dest, int32_t destCapacity, 2480 UErrorCode *pErrorCode) 2481 { 2482 if(U_FAILURE(*pErrorCode)) { 2483 return 0; 2484 } 2485 if(destCapacity<0 || (dest==NULL && destCapacity>0) || start>limit) { 2486 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 2487 return 0; 2488 } 2489 2490 //const UChar *s=(const UChar *)ut->context; 2491 int32_t si, di; 2492 2493 int32_t start32; 2494 int32_t limit32; 2495 2496 // Access the start. Does two things we need: 2497 // Pins 'start' to the length of the string, if it came in out-of-bounds. 2498 // Snaps 'start' to the beginning of a code point. 2499 ucstrTextAccess(ut, start, TRUE); 2500 const UChar *s=ut->chunkContents; 2501 start32 = ut->chunkOffset; 2502 2503 int32_t strLength=(int32_t)ut->a; 2504 if (strLength >= 0) { 2505 limit32 = pinIndex(limit, strLength); 2506 } else { 2507 limit32 = pinIndex(limit, INT32_MAX); 2508 } 2509 di = 0; 2510 for (si=start32; si<limit32; si++) { 2511 if (strLength<0 && s[si]==0) { 2512 // Just hit the end of a null-terminated string. 2513 ut->a = si; // set string length for this UText 2514 ut->chunkNativeLimit = si; 2515 ut->chunkLength = si; 2516 ut->nativeIndexingLimit = si; 2517 strLength = si; 2518 break; 2519 } 2520 U_ASSERT(di>=0); /* to ensure di never exceeds INT32_MAX, which must not happen logically */ 2521 if (di<destCapacity) { 2522 // only store if there is space. 2523 dest[di] = s[si]; 2524 } else { 2525 if (strLength>=0) { 2526 // We have filled the destination buffer, and the string length is known. 2527 // Cut the loop short. There is no need to scan string termination. 2528 di = limit32 - start32; 2529 si = limit32; 2530 break; 2531 } 2532 } 2533 di++; 2534 } 2535 2536 // If the limit index points to a lead surrogate of a pair, 2537 // add the corresponding trail surrogate to the destination. 2538 if (si>0 && U16_IS_LEAD(s[si-1]) && 2539 ((si<strLength || strLength<0) && U16_IS_TRAIL(s[si]))) 2540 { 2541 if (di<destCapacity) { 2542 // store only if there is space in the output buffer. 2543 dest[di++] = s[si++]; 2544 } 2545 } 2546 2547 // Put iteration position at the point just following the extracted text 2548 ut->chunkOffset = uprv_min(strLength, start32 + destCapacity); 2549 2550 // Add a terminating NUL if space in the buffer permits, 2551 // and set the error status as required. 2552 u_terminateUChars(dest, destCapacity, di, pErrorCode); 2553 return di; 2554 } 2555 2556 static const struct UTextFuncs ucstrFuncs = 2557 { 2558 sizeof(UTextFuncs), 2559 0, 0, 0, // Reserved alignment padding 2560 ucstrTextClone, 2561 ucstrTextLength, 2562 ucstrTextAccess, 2563 ucstrTextExtract, 2564 NULL, // Replace 2565 NULL, // Copy 2566 NULL, // MapOffsetToNative, 2567 NULL, // MapIndexToUTF16, 2568 ucstrTextClose, 2569 NULL, // spare 1 2570 NULL, // spare 2 2571 NULL, // spare 3 2572 }; 2573 2574 U_CDECL_END 2575 2576 static const UChar gEmptyUString[] = {0}; 2577 2578 U_CAPI UText * U_EXPORT2 2579 utext_openUChars(UText *ut, const UChar *s, int64_t length, UErrorCode *status) { 2580 if (U_FAILURE(*status)) { 2581 return NULL; 2582 } 2583 if(s==NULL && length==0) { 2584 s = gEmptyUString; 2585 } 2586 if (s==NULL || length < -1 || length>INT32_MAX) { 2587 *status = U_ILLEGAL_ARGUMENT_ERROR; 2588 return NULL; 2589 } 2590 ut = utext_setup(ut, 0, status); 2591 if (U_SUCCESS(*status)) { 2592 ut->pFuncs = &ucstrFuncs; 2593 ut->context = s; 2594 ut->providerProperties = I32_FLAG(UTEXT_PROVIDER_STABLE_CHUNKS); 2595 if (length==-1) { 2596 ut->providerProperties |= I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 2597 } 2598 ut->a = length; 2599 ut->chunkContents = s; 2600 ut->chunkNativeStart = 0; 2601 ut->chunkNativeLimit = length>=0? length : 0; 2602 ut->chunkLength = (int32_t)ut->chunkNativeLimit; 2603 ut->chunkOffset = 0; 2604 ut->nativeIndexingLimit = ut->chunkLength; 2605 } 2606 return ut; 2607 } 2608 2609 2610 //------------------------------------------------------------------------------ 2611 // 2612 // UText implementation for text from ICU CharacterIterators 2613 // 2614 // Use of UText data members: 2615 // context pointer to the CharacterIterator 2616 // a length of the full text. 2617 // p pointer to buffer 1 2618 // b start index of local buffer 1 contents 2619 // q pointer to buffer 2 2620 // c start index of local buffer 2 contents 2621 // r pointer to the character iterator if the UText owns it. 2622 // Null otherwise. 2623 // 2624 //------------------------------------------------------------------------------ 2625 #define CIBufSize 16 2626 2627 U_CDECL_BEGIN 2628 static void U_CALLCONV 2629 charIterTextClose(UText *ut) { 2630 // Most of the work of close is done by the generic UText framework close. 2631 // All that needs to be done here is delete the CharacterIterator if the UText 2632 // owns it. This occurs if the UText was created by cloning. 2633 CharacterIterator *ci = (CharacterIterator *)ut->r; 2634 delete ci; 2635 ut->r = NULL; 2636 } 2637 2638 static int64_t U_CALLCONV 2639 charIterTextLength(UText *ut) { 2640 return (int32_t)ut->a; 2641 } 2642 2643 static UBool U_CALLCONV 2644 charIterTextAccess(UText *ut, int64_t index, UBool forward) { 2645 CharacterIterator *ci = (CharacterIterator *)ut->context; 2646 2647 int32_t clippedIndex = (int32_t)index; 2648 if (clippedIndex<0) { 2649 clippedIndex=0; 2650 } else if (clippedIndex>=ut->a) { 2651 clippedIndex=(int32_t)ut->a; 2652 } 2653 int32_t neededIndex = clippedIndex; 2654 if (!forward && neededIndex>0) { 2655 // reverse iteration, want the position just before what was asked for. 2656 neededIndex--; 2657 } else if (forward && neededIndex==ut->a && neededIndex>0) { 2658 // Forward iteration, don't ask for something past the end of the text. 2659 neededIndex--; 2660 } 2661 2662 // Find the native index of the start of the buffer containing what we want. 2663 neededIndex -= neededIndex % CIBufSize; 2664 2665 UChar *buf = NULL; 2666 UBool needChunkSetup = TRUE; 2667 int i; 2668 if (ut->chunkNativeStart == neededIndex) { 2669 // The buffer we want is already the current chunk. 2670 needChunkSetup = FALSE; 2671 } else if (ut->b == neededIndex) { 2672 // The first buffer (buffer p) has what we need. 2673 buf = (UChar *)ut->p; 2674 } else if (ut->c == neededIndex) { 2675 // The second buffer (buffer q) has what we need. 2676 buf = (UChar *)ut->q; 2677 } else { 2678 // Neither buffer already has what we need. 2679 // Load new data from the character iterator. 2680 // Use the buf that is not the current buffer. 2681 buf = (UChar *)ut->p; 2682 if (ut->p == ut->chunkContents) { 2683 buf = (UChar *)ut->q; 2684 } 2685 ci->setIndex(neededIndex); 2686 for (i=0; i<CIBufSize; i++) { 2687 buf[i] = ci->nextPostInc(); 2688 if (i+neededIndex > ut->a) { 2689 break; 2690 } 2691 } 2692 } 2693 2694 // We have a buffer with the data we need. 2695 // Set it up as the current chunk, if it wasn't already. 2696 if (needChunkSetup) { 2697 ut->chunkContents = buf; 2698 ut->chunkLength = CIBufSize; 2699 ut->chunkNativeStart = neededIndex; 2700 ut->chunkNativeLimit = neededIndex + CIBufSize; 2701 if (ut->chunkNativeLimit > ut->a) { 2702 ut->chunkNativeLimit = ut->a; 2703 ut->chunkLength = (int32_t)(ut->chunkNativeLimit)-(int32_t)(ut->chunkNativeStart); 2704 } 2705 ut->nativeIndexingLimit = ut->chunkLength; 2706 U_ASSERT(ut->chunkOffset>=0 && ut->chunkOffset<=CIBufSize); 2707 } 2708 ut->chunkOffset = clippedIndex - (int32_t)ut->chunkNativeStart; 2709 UBool success = (forward? ut->chunkOffset<ut->chunkLength : ut->chunkOffset>0); 2710 return success; 2711 } 2712 2713 static UText * U_CALLCONV 2714 charIterTextClone(UText *dest, const UText *src, UBool deep, UErrorCode * status) { 2715 if (U_FAILURE(*status)) { 2716 return NULL; 2717 } 2718 2719 if (deep) { 2720 // There is no CharacterIterator API for cloning the underlying text storage. 2721 *status = U_UNSUPPORTED_ERROR; 2722 return NULL; 2723 } else { 2724 CharacterIterator *srcCI =(CharacterIterator *)src->context; 2725 srcCI = srcCI->clone(); 2726 dest = utext_openCharacterIterator(dest, srcCI, status); 2727 // cast off const on getNativeIndex. 2728 // For CharacterIterator based UTexts, this is safe, the operation is const. 2729 int64_t ix = utext_getNativeIndex((UText *)src); 2730 utext_setNativeIndex(dest, ix); 2731 dest->r = srcCI; // flags that this UText owns the CharacterIterator 2732 } 2733 return dest; 2734 } 2735 2736 static int32_t U_CALLCONV 2737 charIterTextExtract(UText *ut, 2738 int64_t start, int64_t limit, 2739 UChar *dest, int32_t destCapacity, 2740 UErrorCode *status) 2741 { 2742 if(U_FAILURE(*status)) { 2743 return 0; 2744 } 2745 if(destCapacity<0 || (dest==NULL && destCapacity>0) || start>limit) { 2746 *status=U_ILLEGAL_ARGUMENT_ERROR; 2747 return 0; 2748 } 2749 int32_t length = (int32_t)ut->a; 2750 int32_t start32 = pinIndex(start, length); 2751 int32_t limit32 = pinIndex(limit, length); 2752 int32_t desti = 0; 2753 int32_t srci; 2754 int32_t copyLimit; 2755 2756 CharacterIterator *ci = (CharacterIterator *)ut->context; 2757 ci->setIndex32(start32); // Moves ix to lead of surrogate pair, if needed. 2758 srci = ci->getIndex(); 2759 copyLimit = srci; 2760 while (srci<limit32) { 2761 UChar32 c = ci->next32PostInc(); 2762 int32_t len = U16_LENGTH(c); 2763 U_ASSERT(desti+len>0); /* to ensure desti+len never exceeds MAX_INT32, which must not happen logically */ 2764 if (desti+len <= destCapacity) { 2765 U16_APPEND_UNSAFE(dest, desti, c); 2766 copyLimit = srci+len; 2767 } else { 2768 desti += len; 2769 *status = U_BUFFER_OVERFLOW_ERROR; 2770 } 2771 srci += len; 2772 } 2773 2774 charIterTextAccess(ut, copyLimit, TRUE); 2775 2776 u_terminateUChars(dest, destCapacity, desti, status); 2777 return desti; 2778 } 2779 2780 static const struct UTextFuncs charIterFuncs = 2781 { 2782 sizeof(UTextFuncs), 2783 0, 0, 0, // Reserved alignment padding 2784 charIterTextClone, 2785 charIterTextLength, 2786 charIterTextAccess, 2787 charIterTextExtract, 2788 NULL, // Replace 2789 NULL, // Copy 2790 NULL, // MapOffsetToNative, 2791 NULL, // MapIndexToUTF16, 2792 charIterTextClose, 2793 NULL, // spare 1 2794 NULL, // spare 2 2795 NULL // spare 3 2796 }; 2797 U_CDECL_END 2798 2799 2800 U_CAPI UText * U_EXPORT2 2801 utext_openCharacterIterator(UText *ut, CharacterIterator *ci, UErrorCode *status) { 2802 if (U_FAILURE(*status)) { 2803 return NULL; 2804 } 2805 2806 if (ci->startIndex() > 0) { 2807 // No support for CharacterIterators that do not start indexing from zero. 2808 *status = U_UNSUPPORTED_ERROR; 2809 return NULL; 2810 } 2811 2812 // Extra space in UText for 2 buffers of CIBufSize UChars each. 2813 int32_t extraSpace = 2 * CIBufSize * sizeof(UChar); 2814 ut = utext_setup(ut, extraSpace, status); 2815 if (U_SUCCESS(*status)) { 2816 ut->pFuncs = &charIterFuncs; 2817 ut->context = ci; 2818 ut->providerProperties = 0; 2819 ut->a = ci->endIndex(); // Length of text 2820 ut->p = ut->pExtra; // First buffer 2821 ut->b = -1; // Native index of first buffer contents 2822 ut->q = (UChar*)ut->pExtra+CIBufSize; // Second buffer 2823 ut->c = -1; // Native index of second buffer contents 2824 2825 // Initialize current chunk contents to be empty. 2826 // First access will fault something in. 2827 // Note: The initial nativeStart and chunkOffset must sum to zero 2828 // so that getNativeIndex() will correctly compute to zero 2829 // if no call to Access() has ever been made. They can't be both 2830 // zero without Access() thinking that the chunk is valid. 2831 ut->chunkContents = (UChar *)ut->p; 2832 ut->chunkNativeStart = -1; 2833 ut->chunkOffset = 1; 2834 ut->chunkNativeLimit = 0; 2835 ut->chunkLength = 0; 2836 ut->nativeIndexingLimit = ut->chunkOffset; // enables native indexing 2837 } 2838 return ut; 2839 } 2840