1/* 2******************************************************************************* 3* 4* Copyright (C) 2005-2012, 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 31U_NAMESPACE_USE 32 33#define I32_FLAG(bitIndex) ((int32_t)1<<(bitIndex)) 34 35 36static UBool 37utext_access(UText *ut, int64_t index, UBool forward) { 38 return ut->pFuncs->access(ut, index, forward); 39} 40 41 42 43U_CAPI UBool U_EXPORT2 44utext_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 83U_CAPI int64_t U_EXPORT2 84utext_nativeLength(UText *ut) { 85 return ut->pFuncs->nativeLength(ut); 86} 87 88 89U_CAPI UBool U_EXPORT2 90utext_isLengthExpensive(const UText *ut) { 91 UBool r = (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE)) != 0; 92 return r; 93} 94 95 96U_CAPI int64_t U_EXPORT2 97utext_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 106U_CAPI void U_EXPORT2 107utext_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 140U_CAPI int64_t U_EXPORT2 141utext_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// 183U_CAPI UChar32 U_EXPORT2 184utext_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 237U_CAPI UChar32 U_EXPORT2 238utext_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 264U_CAPI UChar32 U_EXPORT2 265utext_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 304U_CAPI UChar32 U_EXPORT2 305utext_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 344U_CAPI UChar32 U_EXPORT2 345utext_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 373U_CAPI UChar32 U_EXPORT2 374utext_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 421U_CAPI int32_t U_EXPORT2 422utext_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 431U_CAPI UBool U_EXPORT2 432utext_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 457U_CAPI UBool U_EXPORT2 458utext_isWritable(const UText *ut) 459{ 460 UBool b = (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_WRITABLE)) != 0; 461 return b; 462} 463 464 465U_CAPI void U_EXPORT2 466utext_freeze(UText *ut) { 467 // Zero out the WRITABLE flag. 468 ut->providerProperties &= ~(I32_FLAG(UTEXT_PROVIDER_WRITABLE)); 469} 470 471 472U_CAPI UBool U_EXPORT2 473utext_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 481U_CAPI int32_t U_EXPORT2 482utext_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 498U_CAPI void U_EXPORT2 499utext_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 517U_CAPI UText * U_EXPORT2 518utext_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// 538enum { 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 557struct ExtendedUText { 558 UText ut; 559 UAlignedMemory extension; 560}; 561 562static const UText emptyText = UTEXT_INITIALIZER; 563 564U_CAPI UText * U_EXPORT2 565utext_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 651U_CAPI UText * U_EXPORT2 652utext_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// 704static void 705invalidateChunk(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. 718static int32_t 719pinIndex(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 729U_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// 737static 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// 759static UText * U_CALLCONV 760shallowTextClone(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 return dest; 810} 811 812 813U_CDECL_END 814 815 816 817//------------------------------------------------------------------------------ 818// 819// UText implementation for UTF-8 char * strings (read-only) 820// Limitation: string length must be <= 0x7fffffff in length. 821// (length must for in an int32_t variable) 822// 823// Use of UText data members: 824// context pointer to UTF-8 string 825// utext.b is the input string length (bytes). 826// utext.c Length scanned so far in string 827// (for optimizing finding length of zero terminated strings.) 828// utext.p pointer to the current buffer 829// utext.q pointer to the other buffer. 830// 831//------------------------------------------------------------------------------ 832 833// Chunk size. 834// Must be less than 85, because of byte mapping from UChar indexes to native indexes. 835// Worst case is three native bytes to one UChar. (Supplemenaries are 4 native bytes 836// to two UChars.) 837// 838enum { UTF8_TEXT_CHUNK_SIZE=32 }; 839 840// 841// UTF8Buf Two of these structs will be set up in the UText's extra allocated space. 842// Each contains the UChar chunk buffer, the to and from native maps, and 843// header info. 844// 845// because backwards iteration fills the buffers starting at the end and 846// working towards the front, the filled part of the buffers may not begin 847// at the start of the available storage for the buffers. 848// 849// Buffer size is one bigger than the specified UTF8_TEXT_CHUNK_SIZE to allow for 850// the last character added being a supplementary, and thus requiring a surrogate 851// pair. Doing this is simpler than checking for the edge case. 852// 853 854struct UTF8Buf { 855 int32_t bufNativeStart; // Native index of first char in UChar buf 856 int32_t bufNativeLimit; // Native index following last char in buf. 857 int32_t bufStartIdx; // First filled position in buf. 858 int32_t bufLimitIdx; // Limit of filled range in buf. 859 int32_t bufNILimit; // Limit of native indexing part of buf 860 int32_t toUCharsMapStart; // Native index corresponding to 861 // mapToUChars[0]. 862 // Set to bufNativeStart when filling forwards. 863 // Set to computed value when filling backwards. 864 865 UChar buf[UTF8_TEXT_CHUNK_SIZE+4]; // The UChar buffer. Requires one extra position beyond the 866 // the chunk size, to allow for surrogate at the end. 867 // Length must be identical to mapToNative array, below, 868 // because of the way indexing works when the array is 869 // filled backwards during a reverse iteration. Thus, 870 // the additional extra size. 871 uint8_t mapToNative[UTF8_TEXT_CHUNK_SIZE+4]; // map UChar index in buf to 872 // native offset from bufNativeStart. 873 // Requires two extra slots, 874 // one for a supplementary starting in the last normal position, 875 // and one for an entry for the buffer limit position. 876 uint8_t mapToUChars[UTF8_TEXT_CHUNK_SIZE*3+6]; // Map native offset from bufNativeStart to 877 // correspoding offset in filled part of buf. 878 int32_t align; 879}; 880 881U_CDECL_BEGIN 882 883// 884// utf8TextLength 885// 886// Get the length of the string. If we don't already know it, 887// we'll need to scan for the trailing nul. 888// 889static int64_t U_CALLCONV 890utf8TextLength(UText *ut) { 891 if (ut->b < 0) { 892 // Zero terminated string, and we haven't scanned to the end yet. 893 // Scan it now. 894 const char *r = (const char *)ut->context + ut->c; 895 while (*r != 0) { 896 r++; 897 } 898 if ((r - (const char *)ut->context) < 0x7fffffff) { 899 ut->b = (int32_t)(r - (const char *)ut->context); 900 } else { 901 // Actual string was bigger (more than 2 gig) than we 902 // can handle. Clip it to 2 GB. 903 ut->b = 0x7fffffff; 904 } 905 ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 906 } 907 return ut->b; 908} 909 910 911 912 913 914 915static UBool U_CALLCONV 916utf8TextAccess(UText *ut, int64_t index, UBool forward) { 917 // 918 // Apologies to those who are allergic to goto statements. 919 // Consider each goto to a labelled block to be the equivalent of 920 // call the named block as if it were a function(); 921 // return; 922 // 923 const uint8_t *s8=(const uint8_t *)ut->context; 924 UTF8Buf *u8b = NULL; 925 int32_t length = ut->b; // Length of original utf-8 926 int32_t ix= (int32_t)index; // Requested index, trimmed to 32 bits. 927 int32_t mapIndex = 0; 928 if (index<0) { 929 ix=0; 930 } else if (index > 0x7fffffff) { 931 // Strings with 64 bit lengths not supported by this UTF-8 provider. 932 ix = 0x7fffffff; 933 } 934 935 // Pin requested index to the string length. 936 if (ix>length) { 937 if (length>=0) { 938 ix=length; 939 } else if (ix>=ut->c) { 940 // Zero terminated string, and requested index is beyond 941 // the region that has already been scanned. 942 // Scan up to either the end of the string or to the 943 // requested position, whichever comes first. 944 while (ut->c<ix && s8[ut->c]!=0) { 945 ut->c++; 946 } 947 // TODO: support for null terminated string length > 32 bits. 948 if (s8[ut->c] == 0) { 949 // We just found the actual length of the string. 950 // Trim the requested index back to that. 951 ix = ut->c; 952 ut->b = ut->c; 953 length = ut->c; 954 ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 955 } 956 } 957 } 958 959 // 960 // Dispatch to the appropriate action for a forward iteration request. 961 // 962 if (forward) { 963 if (ix==ut->chunkNativeLimit) { 964 // Check for normal sequential iteration cases first. 965 if (ix==length) { 966 // Just reached end of string 967 // Don't swap buffers, but do set the 968 // current buffer position. 969 ut->chunkOffset = ut->chunkLength; 970 return FALSE; 971 } else { 972 // End of current buffer. 973 // check whether other buffer already has what we need. 974 UTF8Buf *altB = (UTF8Buf *)ut->q; 975 if (ix>=altB->bufNativeStart && ix<altB->bufNativeLimit) { 976 goto swapBuffers; 977 } 978 } 979 } 980 981 // A random access. Desired index could be in either or niether buf. 982 // For optimizing the order of testing, first check for the index 983 // being in the other buffer. This will be the case for uses that 984 // move back and forth over a fairly limited range 985 { 986 u8b = (UTF8Buf *)ut->q; // the alternate buffer 987 if (ix>=u8b->bufNativeStart && ix<u8b->bufNativeLimit) { 988 // Requested index is in the other buffer. 989 goto swapBuffers; 990 } 991 if (ix == length) { 992 // Requested index is end-of-string. 993 // (this is the case of randomly seeking to the end. 994 // The case of iterating off the end is handled earlier.) 995 if (ix == ut->chunkNativeLimit) { 996 // Current buffer extends up to the end of the string. 997 // Leave it as the current buffer. 998 ut->chunkOffset = ut->chunkLength; 999 return FALSE; 1000 } 1001 if (ix == u8b->bufNativeLimit) { 1002 // Alternate buffer extends to the end of string. 1003 // Swap it in as the current buffer. 1004 goto swapBuffersAndFail; 1005 } 1006 1007 // Neither existing buffer extends to the end of the string. 1008 goto makeStubBuffer; 1009 } 1010 1011 if (ix<ut->chunkNativeStart || ix>=ut->chunkNativeLimit) { 1012 // Requested index is in neither buffer. 1013 goto fillForward; 1014 } 1015 1016 // Requested index is in this buffer. 1017 u8b = (UTF8Buf *)ut->p; // the current buffer 1018 mapIndex = ix - u8b->toUCharsMapStart; 1019 ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx; 1020 return TRUE; 1021 1022 } 1023 } 1024 1025 1026 // 1027 // Dispatch to the appropriate action for a 1028 // Backwards Diretion iteration request. 1029 // 1030 if (ix==ut->chunkNativeStart) { 1031 // Check for normal sequential iteration cases first. 1032 if (ix==0) { 1033 // Just reached the start of string 1034 // Don't swap buffers, but do set the 1035 // current buffer position. 1036 ut->chunkOffset = 0; 1037 return FALSE; 1038 } else { 1039 // Start of current buffer. 1040 // check whether other buffer already has what we need. 1041 UTF8Buf *altB = (UTF8Buf *)ut->q; 1042 if (ix>altB->bufNativeStart && ix<=altB->bufNativeLimit) { 1043 goto swapBuffers; 1044 } 1045 } 1046 } 1047 1048 // A random access. Desired index could be in either or niether buf. 1049 // For optimizing the order of testing, 1050 // Most likely case: in the other buffer. 1051 // Second most likely: in neither buffer. 1052 // Unlikely, but must work: in the current buffer. 1053 u8b = (UTF8Buf *)ut->q; // the alternate buffer 1054 if (ix>u8b->bufNativeStart && ix<=u8b->bufNativeLimit) { 1055 // Requested index is in the other buffer. 1056 goto swapBuffers; 1057 } 1058 // Requested index is start-of-string. 1059 // (this is the case of randomly seeking to the start. 1060 // The case of iterating off the start is handled earlier.) 1061 if (ix==0) { 1062 if (u8b->bufNativeStart==0) { 1063 // Alternate buffer contains the data for the start string. 1064 // Make it be the current buffer. 1065 goto swapBuffersAndFail; 1066 } else { 1067 // Request for data before the start of string, 1068 // neither buffer is usable. 1069 // set up a zero-length buffer. 1070 goto makeStubBuffer; 1071 } 1072 } 1073 1074 if (ix<=ut->chunkNativeStart || ix>ut->chunkNativeLimit) { 1075 // Requested index is in neither buffer. 1076 goto fillReverse; 1077 } 1078 1079 // Requested index is in this buffer. 1080 // Set the utf16 buffer index. 1081 u8b = (UTF8Buf *)ut->p; 1082 mapIndex = ix - u8b->toUCharsMapStart; 1083 ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx; 1084 if (ut->chunkOffset==0) { 1085 // This occurs when the first character in the text is 1086 // a multi-byte UTF-8 char, and the requested index is to 1087 // one of the trailing bytes. Because there is no preceding , 1088 // character, this access fails. We can't pick up on the 1089 // situation sooner because the requested index is not zero. 1090 return FALSE; 1091 } else { 1092 return TRUE; 1093 } 1094 1095 1096 1097swapBuffers: 1098 // The alternate buffer (ut->q) has the string data that was requested. 1099 // Swap the primary and alternate buffers, and set the 1100 // chunk index into the new primary buffer. 1101 { 1102 u8b = (UTF8Buf *)ut->q; 1103 ut->q = ut->p; 1104 ut->p = u8b; 1105 ut->chunkContents = &u8b->buf[u8b->bufStartIdx]; 1106 ut->chunkLength = u8b->bufLimitIdx - u8b->bufStartIdx; 1107 ut->chunkNativeStart = u8b->bufNativeStart; 1108 ut->chunkNativeLimit = u8b->bufNativeLimit; 1109 ut->nativeIndexingLimit = u8b->bufNILimit; 1110 1111 // Index into the (now current) chunk 1112 // Use the map to set the chunk index. It's more trouble than it's worth 1113 // to check whether native indexing can be used. 1114 U_ASSERT(ix>=u8b->bufNativeStart); 1115 U_ASSERT(ix<=u8b->bufNativeLimit); 1116 mapIndex = ix - u8b->toUCharsMapStart; 1117 U_ASSERT(mapIndex>=0); 1118 U_ASSERT(mapIndex<(int32_t)sizeof(u8b->mapToUChars)); 1119 ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx; 1120 1121 return TRUE; 1122 } 1123 1124 1125 swapBuffersAndFail: 1126 // We got a request for either the start or end of the string, 1127 // with iteration continuing in the out-of-bounds direction. 1128 // The alternate buffer already contains the data up to the 1129 // start/end. 1130 // Swap the buffers, then return failure, indicating that we couldn't 1131 // make things correct for continuing the iteration in the requested 1132 // direction. The position & buffer are correct should the 1133 // user decide to iterate in the opposite direction. 1134 u8b = (UTF8Buf *)ut->q; 1135 ut->q = ut->p; 1136 ut->p = u8b; 1137 ut->chunkContents = &u8b->buf[u8b->bufStartIdx]; 1138 ut->chunkLength = u8b->bufLimitIdx - u8b->bufStartIdx; 1139 ut->chunkNativeStart = u8b->bufNativeStart; 1140 ut->chunkNativeLimit = u8b->bufNativeLimit; 1141 ut->nativeIndexingLimit = u8b->bufNILimit; 1142 1143 // Index into the (now current) chunk 1144 // For this function (swapBuffersAndFail), the requested index 1145 // will always be at either the start or end of the chunk. 1146 if (ix==u8b->bufNativeLimit) { 1147 ut->chunkOffset = ut->chunkLength; 1148 } else { 1149 ut->chunkOffset = 0; 1150 U_ASSERT(ix == u8b->bufNativeStart); 1151 } 1152 return FALSE; 1153 1154makeStubBuffer: 1155 // The user has done a seek/access past the start or end 1156 // of the string. Rather than loading data that is likely 1157 // to never be used, just set up a zero-length buffer at 1158 // the position. 1159 u8b = (UTF8Buf *)ut->q; 1160 u8b->bufNativeStart = ix; 1161 u8b->bufNativeLimit = ix; 1162 u8b->bufStartIdx = 0; 1163 u8b->bufLimitIdx = 0; 1164 u8b->bufNILimit = 0; 1165 u8b->toUCharsMapStart = ix; 1166 u8b->mapToNative[0] = 0; 1167 u8b->mapToUChars[0] = 0; 1168 goto swapBuffersAndFail; 1169 1170 1171 1172fillForward: 1173 { 1174 // Move the incoming index to a code point boundary. 1175 U8_SET_CP_START(s8, 0, ix); 1176 1177 // Swap the UText buffers. 1178 // We want to fill what was previously the alternate buffer, 1179 // and make what was the current buffer be the new alternate. 1180 UTF8Buf *u8b = (UTF8Buf *)ut->q; 1181 ut->q = ut->p; 1182 ut->p = u8b; 1183 1184 int32_t strLen = ut->b; 1185 UBool nulTerminated = FALSE; 1186 if (strLen < 0) { 1187 strLen = 0x7fffffff; 1188 nulTerminated = TRUE; 1189 } 1190 1191 UChar *buf = u8b->buf; 1192 uint8_t *mapToNative = u8b->mapToNative; 1193 uint8_t *mapToUChars = u8b->mapToUChars; 1194 int32_t destIx = 0; 1195 int32_t srcIx = ix; 1196 UBool seenNonAscii = FALSE; 1197 UChar32 c = 0; 1198 1199 // Fill the chunk buffer and mapping arrays. 1200 while (destIx<UTF8_TEXT_CHUNK_SIZE) { 1201 c = s8[srcIx]; 1202 if (c>0 && c<0x80) { 1203 // Special case ASCII range for speed. 1204 // zero is excluded to simplify bounds checking. 1205 buf[destIx] = (UChar)c; 1206 mapToNative[destIx] = (uint8_t)(srcIx - ix); 1207 mapToUChars[srcIx-ix] = (uint8_t)destIx; 1208 srcIx++; 1209 destIx++; 1210 } else { 1211 // General case, handle everything. 1212 if (seenNonAscii == FALSE) { 1213 seenNonAscii = TRUE; 1214 u8b->bufNILimit = destIx; 1215 } 1216 1217 int32_t cIx = srcIx; 1218 int32_t dIx = destIx; 1219 int32_t dIxSaved = destIx; 1220 U8_NEXT(s8, srcIx, strLen, c); 1221 if (c==0 && nulTerminated) { 1222 srcIx--; 1223 break; 1224 } 1225 if (c<0) { 1226 // Illegal UTF-8. Replace with sub character. 1227 c = 0x0fffd; 1228 } 1229 1230 U16_APPEND_UNSAFE(buf, destIx, c); 1231 do { 1232 mapToNative[dIx++] = (uint8_t)(cIx - ix); 1233 } while (dIx < destIx); 1234 1235 do { 1236 mapToUChars[cIx++ - ix] = (uint8_t)dIxSaved; 1237 } while (cIx < srcIx); 1238 } 1239 if (srcIx>=strLen) { 1240 break; 1241 } 1242 1243 } 1244 1245 // store Native <--> Chunk Map entries for the end of the buffer. 1246 // There is no actual character here, but the index position is valid. 1247 mapToNative[destIx] = (uint8_t)(srcIx - ix); 1248 mapToUChars[srcIx - ix] = (uint8_t)destIx; 1249 1250 // fill in Buffer descriptor 1251 u8b->bufNativeStart = ix; 1252 u8b->bufNativeLimit = srcIx; 1253 u8b->bufStartIdx = 0; 1254 u8b->bufLimitIdx = destIx; 1255 if (seenNonAscii == FALSE) { 1256 u8b->bufNILimit = destIx; 1257 } 1258 u8b->toUCharsMapStart = u8b->bufNativeStart; 1259 1260 // Set UText chunk to refer to this buffer. 1261 ut->chunkContents = buf; 1262 ut->chunkOffset = 0; 1263 ut->chunkLength = u8b->bufLimitIdx; 1264 ut->chunkNativeStart = u8b->bufNativeStart; 1265 ut->chunkNativeLimit = u8b->bufNativeLimit; 1266 ut->nativeIndexingLimit = u8b->bufNILimit; 1267 1268 // For zero terminated strings, keep track of the maximum point 1269 // scanned so far. 1270 if (nulTerminated && srcIx>ut->c) { 1271 ut->c = srcIx; 1272 if (c==0) { 1273 // We scanned to the end. 1274 // Remember the actual length. 1275 ut->b = srcIx; 1276 ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 1277 } 1278 } 1279 return TRUE; 1280 } 1281 1282 1283fillReverse: 1284 { 1285 // Move the incoming index to a code point boundary. 1286 // Can only do this if the incoming index is somewhere in the interior of the string. 1287 // If index is at the end, there is no character there to look at. 1288 if (ix != ut->b) { 1289 U8_SET_CP_START(s8, 0, ix); 1290 } 1291 1292 // Swap the UText buffers. 1293 // We want to fill what was previously the alternate buffer, 1294 // and make what was the current buffer be the new alternate. 1295 UTF8Buf *u8b = (UTF8Buf *)ut->q; 1296 ut->q = ut->p; 1297 ut->p = u8b; 1298 1299 UChar *buf = u8b->buf; 1300 uint8_t *mapToNative = u8b->mapToNative; 1301 uint8_t *mapToUChars = u8b->mapToUChars; 1302 int32_t toUCharsMapStart = ix - (UTF8_TEXT_CHUNK_SIZE*3 + 1); 1303 int32_t destIx = UTF8_TEXT_CHUNK_SIZE+2; // Start in the overflow region 1304 // at end of buffer to leave room 1305 // for a surrogate pair at the 1306 // buffer start. 1307 int32_t srcIx = ix; 1308 int32_t bufNILimit = destIx; 1309 UChar32 c; 1310 1311 // Map to/from Native Indexes, fill in for the position at the end of 1312 // the buffer. 1313 // 1314 mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart); 1315 mapToUChars[srcIx - toUCharsMapStart] = (uint8_t)destIx; 1316 1317 // Fill the chunk buffer 1318 // Work backwards, filling from the end of the buffer towards the front. 1319 // 1320 while (destIx>2 && (srcIx - toUCharsMapStart > 5) && (srcIx > 0)) { 1321 srcIx--; 1322 destIx--; 1323 1324 // Get last byte of the UTF-8 character 1325 c = s8[srcIx]; 1326 if (c<0x80) { 1327 // Special case ASCII range for speed. 1328 buf[destIx] = (UChar)c; 1329 mapToUChars[srcIx - toUCharsMapStart] = (uint8_t)destIx; 1330 mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart); 1331 } else { 1332 // General case, handle everything non-ASCII. 1333 1334 int32_t sIx = srcIx; // ix of last byte of multi-byte u8 char 1335 1336 // Get the full character from the UTF8 string. 1337 // use code derived from tbe macros in utf.8 1338 // Leaves srcIx pointing at the first byte of the UTF-8 char. 1339 // 1340 if (c<=0xbf) { 1341 c=utf8_prevCharSafeBody(s8, 0, &srcIx, c, -1); 1342 // leaves srcIx at first byte of the multi-byte char. 1343 } else { 1344 c=0x0fffd; 1345 } 1346 1347 // Store the character in UTF-16 buffer. 1348 if (c<0x10000) { 1349 buf[destIx] = (UChar)c; 1350 mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart); 1351 } else { 1352 buf[destIx] = U16_TRAIL(c); 1353 mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart); 1354 buf[--destIx] = U16_LEAD(c); 1355 mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart); 1356 } 1357 1358 // Fill in the map from native indexes to UChars buf index. 1359 do { 1360 mapToUChars[sIx-- - toUCharsMapStart] = (uint8_t)destIx; 1361 } while (sIx >= srcIx); 1362 1363 // Set native indexing limit to be the current position. 1364 // We are processing a non-ascii, non-native-indexing char now; 1365 // the limit will be here if the rest of the chars to be 1366 // added to this buffer are ascii. 1367 bufNILimit = destIx; 1368 } 1369 } 1370 u8b->bufNativeStart = srcIx; 1371 u8b->bufNativeLimit = ix; 1372 u8b->bufStartIdx = destIx; 1373 u8b->bufLimitIdx = UTF8_TEXT_CHUNK_SIZE+2; 1374 u8b->bufNILimit = bufNILimit - u8b->bufStartIdx; 1375 u8b->toUCharsMapStart = toUCharsMapStart; 1376 1377 ut->chunkContents = &buf[u8b->bufStartIdx]; 1378 ut->chunkLength = u8b->bufLimitIdx - u8b->bufStartIdx; 1379 ut->chunkOffset = ut->chunkLength; 1380 ut->chunkNativeStart = u8b->bufNativeStart; 1381 ut->chunkNativeLimit = u8b->bufNativeLimit; 1382 ut->nativeIndexingLimit = u8b->bufNILimit; 1383 return TRUE; 1384 } 1385 1386} 1387 1388 1389 1390// 1391// This is a slightly modified copy of u_strFromUTF8, 1392// Inserts a Replacement Char rather than failing on invalid UTF-8 1393// Removes unnecessary features. 1394// 1395static UChar* 1396utext_strFromUTF8(UChar *dest, 1397 int32_t destCapacity, 1398 int32_t *pDestLength, 1399 const char* src, 1400 int32_t srcLength, // required. NUL terminated not supported. 1401 UErrorCode *pErrorCode 1402 ) 1403{ 1404 1405 UChar *pDest = dest; 1406 UChar *pDestLimit = (dest!=NULL)?(dest+destCapacity):NULL; 1407 UChar32 ch=0; 1408 int32_t index = 0; 1409 int32_t reqLength = 0; 1410 uint8_t* pSrc = (uint8_t*) src; 1411 1412 1413 while((index < srcLength)&&(pDest<pDestLimit)){ 1414 ch = pSrc[index++]; 1415 if(ch <=0x7f){ 1416 *pDest++=(UChar)ch; 1417 }else{ 1418 ch=utf8_nextCharSafeBody(pSrc, &index, srcLength, ch, -1); 1419 if(ch<0){ 1420 ch = 0xfffd; 1421 } 1422 if(U_IS_BMP(ch)){ 1423 *(pDest++)=(UChar)ch; 1424 }else{ 1425 *(pDest++)=U16_LEAD(ch); 1426 if(pDest<pDestLimit){ 1427 *(pDest++)=U16_TRAIL(ch); 1428 }else{ 1429 reqLength++; 1430 break; 1431 } 1432 } 1433 } 1434 } 1435 /* donot fill the dest buffer just count the UChars needed */ 1436 while(index < srcLength){ 1437 ch = pSrc[index++]; 1438 if(ch <= 0x7f){ 1439 reqLength++; 1440 }else{ 1441 ch=utf8_nextCharSafeBody(pSrc, &index, srcLength, ch, -1); 1442 if(ch<0){ 1443 ch = 0xfffd; 1444 } 1445 reqLength+=U16_LENGTH(ch); 1446 } 1447 } 1448 1449 reqLength+=(int32_t)(pDest - dest); 1450 1451 if(pDestLength){ 1452 *pDestLength = reqLength; 1453 } 1454 1455 /* Terminate the buffer */ 1456 u_terminateUChars(dest,destCapacity,reqLength,pErrorCode); 1457 1458 return dest; 1459} 1460 1461 1462 1463static int32_t U_CALLCONV 1464utf8TextExtract(UText *ut, 1465 int64_t start, int64_t limit, 1466 UChar *dest, int32_t destCapacity, 1467 UErrorCode *pErrorCode) { 1468 if(U_FAILURE(*pErrorCode)) { 1469 return 0; 1470 } 1471 if(destCapacity<0 || (dest==NULL && destCapacity>0)) { 1472 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1473 return 0; 1474 } 1475 int32_t length = ut->b; 1476 int32_t start32 = pinIndex(start, length); 1477 int32_t limit32 = pinIndex(limit, length); 1478 1479 if(start32>limit32) { 1480 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 1481 return 0; 1482 } 1483 1484 1485 // adjust the incoming indexes to land on code point boundaries if needed. 1486 // adjust by no more than three, because that is the largest number of trail bytes 1487 // in a well formed UTF8 character. 1488 const uint8_t *buf = (const uint8_t *)ut->context; 1489 int i; 1490 if (start32 < ut->chunkNativeLimit) { 1491 for (i=0; i<3; i++) { 1492 if (U8_IS_SINGLE(buf[start32]) || U8_IS_LEAD(buf[start32]) || start32==0) { 1493 break; 1494 } 1495 start32--; 1496 } 1497 } 1498 1499 if (limit32 < ut->chunkNativeLimit) { 1500 for (i=0; i<3; i++) { 1501 if (U8_IS_SINGLE(buf[limit32]) || U8_IS_LEAD(buf[limit32]) || limit32==0) { 1502 break; 1503 } 1504 limit32--; 1505 } 1506 } 1507 1508 // Do the actual extract. 1509 int32_t destLength=0; 1510 utext_strFromUTF8(dest, destCapacity, &destLength, 1511 (const char *)ut->context+start32, limit32-start32, 1512 pErrorCode); 1513 utf8TextAccess(ut, limit32, TRUE); 1514 return destLength; 1515} 1516 1517// 1518// utf8TextMapOffsetToNative 1519// 1520// Map a chunk (UTF-16) offset to a native index. 1521static int64_t U_CALLCONV 1522utf8TextMapOffsetToNative(const UText *ut) { 1523 // 1524 UTF8Buf *u8b = (UTF8Buf *)ut->p; 1525 U_ASSERT(ut->chunkOffset>ut->nativeIndexingLimit && ut->chunkOffset<=ut->chunkLength); 1526 int32_t nativeOffset = u8b->mapToNative[ut->chunkOffset + u8b->bufStartIdx] + u8b->toUCharsMapStart; 1527 U_ASSERT(nativeOffset >= ut->chunkNativeStart && nativeOffset <= ut->chunkNativeLimit); 1528 return nativeOffset; 1529} 1530 1531// 1532// Map a native index to the corrsponding chunk offset 1533// 1534static int32_t U_CALLCONV 1535utf8TextMapIndexToUTF16(const UText *ut, int64_t index64) { 1536 U_ASSERT(index64 <= 0x7fffffff); 1537 int32_t index = (int32_t)index64; 1538 UTF8Buf *u8b = (UTF8Buf *)ut->p; 1539 U_ASSERT(index>=ut->chunkNativeStart+ut->nativeIndexingLimit); 1540 U_ASSERT(index<=ut->chunkNativeLimit); 1541 int32_t mapIndex = index - u8b->toUCharsMapStart; 1542 int32_t offset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx; 1543 U_ASSERT(offset>=0 && offset<=ut->chunkLength); 1544 return offset; 1545} 1546 1547static UText * U_CALLCONV 1548utf8TextClone(UText *dest, const UText *src, UBool deep, UErrorCode *status) 1549{ 1550 // First do a generic shallow clone. Does everything needed for the UText struct itself. 1551 dest = shallowTextClone(dest, src, status); 1552 1553 // For deep clones, make a copy of the string. 1554 // The copied storage is owned by the newly created clone. 1555 // 1556 // TODO: There is an isssue with using utext_nativeLength(). 1557 // That function is non-const in cases where the input was NUL terminated 1558 // and the length has not yet been determined. 1559 // This function (clone()) is const. 1560 // There potentially a thread safety issue lurking here. 1561 // 1562 if (deep && U_SUCCESS(*status)) { 1563 int32_t len = (int32_t)utext_nativeLength((UText *)src); 1564 char *copyStr = (char *)uprv_malloc(len+1); 1565 if (copyStr == NULL) { 1566 *status = U_MEMORY_ALLOCATION_ERROR; 1567 } else { 1568 uprv_memcpy(copyStr, src->context, len+1); 1569 dest->context = copyStr; 1570 dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT); 1571 } 1572 } 1573 return dest; 1574} 1575 1576 1577static void U_CALLCONV 1578utf8TextClose(UText *ut) { 1579 // Most of the work of close is done by the generic UText framework close. 1580 // All that needs to be done here is to delete the UTF8 string if the UText 1581 // owns it. This occurs if the UText was created by cloning. 1582 if (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT)) { 1583 char *s = (char *)ut->context; 1584 uprv_free(s); 1585 ut->context = NULL; 1586 } 1587} 1588 1589U_CDECL_END 1590 1591 1592static const struct UTextFuncs utf8Funcs = 1593{ 1594 sizeof(UTextFuncs), 1595 0, 0, 0, // Reserved alignment padding 1596 utf8TextClone, 1597 utf8TextLength, 1598 utf8TextAccess, 1599 utf8TextExtract, 1600 NULL, /* replace*/ 1601 NULL, /* copy */ 1602 utf8TextMapOffsetToNative, 1603 utf8TextMapIndexToUTF16, 1604 utf8TextClose, 1605 NULL, // spare 1 1606 NULL, // spare 2 1607 NULL // spare 3 1608}; 1609 1610 1611static const char gEmptyString[] = {0}; 1612 1613U_CAPI UText * U_EXPORT2 1614utext_openUTF8(UText *ut, const char *s, int64_t length, UErrorCode *status) { 1615 if(U_FAILURE(*status)) { 1616 return NULL; 1617 } 1618 if(s==NULL && length==0) { 1619 s = gEmptyString; 1620 } 1621 1622 if(s==NULL || length<-1 || length>INT32_MAX) { 1623 *status=U_ILLEGAL_ARGUMENT_ERROR; 1624 return NULL; 1625 } 1626 1627 ut = utext_setup(ut, sizeof(UTF8Buf) * 2, status); 1628 if (U_FAILURE(*status)) { 1629 return ut; 1630 } 1631 1632 ut->pFuncs = &utf8Funcs; 1633 ut->context = s; 1634 ut->b = (int32_t)length; 1635 ut->c = (int32_t)length; 1636 if (ut->c < 0) { 1637 ut->c = 0; 1638 ut->providerProperties |= I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 1639 } 1640 ut->p = ut->pExtra; 1641 ut->q = (char *)ut->pExtra + sizeof(UTF8Buf); 1642 return ut; 1643 1644} 1645 1646 1647 1648 1649 1650 1651 1652 1653//------------------------------------------------------------------------------ 1654// 1655// UText implementation wrapper for Replaceable (read/write) 1656// 1657// Use of UText data members: 1658// context pointer to Replaceable. 1659// p pointer to Replaceable if it is owned by the UText. 1660// 1661//------------------------------------------------------------------------------ 1662 1663 1664 1665// minimum chunk size for this implementation: 3 1666// to allow for possible trimming for code point boundaries 1667enum { REP_TEXT_CHUNK_SIZE=10 }; 1668 1669struct ReplExtra { 1670 /* 1671 * Chunk UChars. 1672 * +1 to simplify filling with surrogate pair at the end. 1673 */ 1674 UChar s[REP_TEXT_CHUNK_SIZE+1]; 1675}; 1676 1677 1678U_CDECL_BEGIN 1679 1680static UText * U_CALLCONV 1681repTextClone(UText *dest, const UText *src, UBool deep, UErrorCode *status) { 1682 // First do a generic shallow clone. Does everything needed for the UText struct itself. 1683 dest = shallowTextClone(dest, src, status); 1684 1685 // For deep clones, make a copy of the Replaceable. 1686 // The copied Replaceable storage is owned by the newly created UText clone. 1687 // A non-NULL pointer in UText.p is the signal to the close() function to delete 1688 // it. 1689 // 1690 if (deep && U_SUCCESS(*status)) { 1691 const Replaceable *replSrc = (const Replaceable *)src->context; 1692 dest->context = replSrc->clone(); 1693 dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT); 1694 1695 // with deep clone, the copy is writable, even when the source is not. 1696 dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_WRITABLE); 1697 } 1698 return dest; 1699} 1700 1701 1702static void U_CALLCONV 1703repTextClose(UText *ut) { 1704 // Most of the work of close is done by the generic UText framework close. 1705 // All that needs to be done here is delete the Replaceable if the UText 1706 // owns it. This occurs if the UText was created by cloning. 1707 if (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT)) { 1708 Replaceable *rep = (Replaceable *)ut->context; 1709 delete rep; 1710 ut->context = NULL; 1711 } 1712} 1713 1714 1715static int64_t U_CALLCONV 1716repTextLength(UText *ut) { 1717 const Replaceable *replSrc = (const Replaceable *)ut->context; 1718 int32_t len = replSrc->length(); 1719 return len; 1720} 1721 1722 1723static UBool U_CALLCONV 1724repTextAccess(UText *ut, int64_t index, UBool forward) { 1725 const Replaceable *rep=(const Replaceable *)ut->context; 1726 int32_t length=rep->length(); // Full length of the input text (bigger than a chunk) 1727 1728 // clip the requested index to the limits of the text. 1729 int32_t index32 = pinIndex(index, length); 1730 U_ASSERT(index<=INT32_MAX); 1731 1732 1733 /* 1734 * Compute start/limit boundaries around index, for a segment of text 1735 * to be extracted. 1736 * To allow for the possibility that our user gave an index to the trailing 1737 * half of a surrogate pair, we must request one extra preceding UChar when 1738 * going in the forward direction. This will ensure that the buffer has the 1739 * entire code point at the specified index. 1740 */ 1741 if(forward) { 1742 1743 if (index32>=ut->chunkNativeStart && index32<ut->chunkNativeLimit) { 1744 // Buffer already contains the requested position. 1745 ut->chunkOffset = (int32_t)(index - ut->chunkNativeStart); 1746 return TRUE; 1747 } 1748 if (index32>=length && ut->chunkNativeLimit==length) { 1749 // Request for end of string, and buffer already extends up to it. 1750 // Can't get the data, but don't change the buffer. 1751 ut->chunkOffset = length - (int32_t)ut->chunkNativeStart; 1752 return FALSE; 1753 } 1754 1755 ut->chunkNativeLimit = index + REP_TEXT_CHUNK_SIZE - 1; 1756 // Going forward, so we want to have the buffer with stuff at and beyond 1757 // the requested index. The -1 gets us one code point before the 1758 // requested index also, to handle the case of the index being on 1759 // a trail surrogate of a surrogate pair. 1760 if(ut->chunkNativeLimit > length) { 1761 ut->chunkNativeLimit = length; 1762 } 1763 // unless buffer ran off end, start is index-1. 1764 ut->chunkNativeStart = ut->chunkNativeLimit - REP_TEXT_CHUNK_SIZE; 1765 if(ut->chunkNativeStart < 0) { 1766 ut->chunkNativeStart = 0; 1767 } 1768 } else { 1769 // Reverse iteration. Fill buffer with data preceding the requested index. 1770 if (index32>ut->chunkNativeStart && index32<=ut->chunkNativeLimit) { 1771 // Requested position already in buffer. 1772 ut->chunkOffset = index32 - (int32_t)ut->chunkNativeStart; 1773 return TRUE; 1774 } 1775 if (index32==0 && ut->chunkNativeStart==0) { 1776 // Request for start, buffer already begins at start. 1777 // No data, but keep the buffer as is. 1778 ut->chunkOffset = 0; 1779 return FALSE; 1780 } 1781 1782 // Figure out the bounds of the chunk to extract for reverse iteration. 1783 // Need to worry about chunk not splitting surrogate pairs, and while still 1784 // containing the data we need. 1785 // Fix by requesting a chunk that includes an extra UChar at the end. 1786 // If this turns out to be a lead surrogate, we can lop it off and still have 1787 // the data we wanted. 1788 ut->chunkNativeStart = index32 + 1 - REP_TEXT_CHUNK_SIZE; 1789 if (ut->chunkNativeStart < 0) { 1790 ut->chunkNativeStart = 0; 1791 } 1792 1793 ut->chunkNativeLimit = index32 + 1; 1794 if (ut->chunkNativeLimit > length) { 1795 ut->chunkNativeLimit = length; 1796 } 1797 } 1798 1799 // Extract the new chunk of text from the Replaceable source. 1800 ReplExtra *ex = (ReplExtra *)ut->pExtra; 1801 // UnicodeString with its buffer a writable alias to the chunk buffer 1802 UnicodeString buffer(ex->s, 0 /*buffer length*/, REP_TEXT_CHUNK_SIZE /*buffer capacity*/); 1803 rep->extractBetween((int32_t)ut->chunkNativeStart, (int32_t)ut->chunkNativeLimit, buffer); 1804 1805 ut->chunkContents = ex->s; 1806 ut->chunkLength = (int32_t)(ut->chunkNativeLimit - ut->chunkNativeStart); 1807 ut->chunkOffset = (int32_t)(index32 - ut->chunkNativeStart); 1808 1809 // Surrogate pairs from the input text must not span chunk boundaries. 1810 // If end of chunk could be the start of a surrogate, trim it off. 1811 if (ut->chunkNativeLimit < length && 1812 U16_IS_LEAD(ex->s[ut->chunkLength-1])) { 1813 ut->chunkLength--; 1814 ut->chunkNativeLimit--; 1815 if (ut->chunkOffset > ut->chunkLength) { 1816 ut->chunkOffset = ut->chunkLength; 1817 } 1818 } 1819 1820 // if the first UChar in the chunk could be the trailing half of a surrogate pair, 1821 // trim it off. 1822 if(ut->chunkNativeStart>0 && U16_IS_TRAIL(ex->s[0])) { 1823 ++(ut->chunkContents); 1824 ++(ut->chunkNativeStart); 1825 --(ut->chunkLength); 1826 --(ut->chunkOffset); 1827 } 1828 1829 // adjust the index/chunkOffset to a code point boundary 1830 U16_SET_CP_START(ut->chunkContents, 0, ut->chunkOffset); 1831 1832 // Use fast indexing for get/setNativeIndex() 1833 ut->nativeIndexingLimit = ut->chunkLength; 1834 1835 return TRUE; 1836} 1837 1838 1839 1840static int32_t U_CALLCONV 1841repTextExtract(UText *ut, 1842 int64_t start, int64_t limit, 1843 UChar *dest, int32_t destCapacity, 1844 UErrorCode *status) { 1845 const Replaceable *rep=(const Replaceable *)ut->context; 1846 int32_t length=rep->length(); 1847 1848 if(U_FAILURE(*status)) { 1849 return 0; 1850 } 1851 if(destCapacity<0 || (dest==NULL && destCapacity>0)) { 1852 *status=U_ILLEGAL_ARGUMENT_ERROR; 1853 } 1854 if(start>limit) { 1855 *status=U_INDEX_OUTOFBOUNDS_ERROR; 1856 return 0; 1857 } 1858 1859 int32_t start32 = pinIndex(start, length); 1860 int32_t limit32 = pinIndex(limit, length); 1861 1862 // adjust start, limit if they point to trail half of surrogates 1863 if (start32<length && U16_IS_TRAIL(rep->charAt(start32)) && 1864 U_IS_SUPPLEMENTARY(rep->char32At(start32))){ 1865 start32--; 1866 } 1867 if (limit32<length && U16_IS_TRAIL(rep->charAt(limit32)) && 1868 U_IS_SUPPLEMENTARY(rep->char32At(limit32))){ 1869 limit32--; 1870 } 1871 1872 length=limit32-start32; 1873 if(length>destCapacity) { 1874 limit32 = start32 + destCapacity; 1875 } 1876 UnicodeString buffer(dest, 0, destCapacity); // writable alias 1877 rep->extractBetween(start32, limit32, buffer); 1878 repTextAccess(ut, limit32, TRUE); 1879 1880 return u_terminateUChars(dest, destCapacity, length, status); 1881} 1882 1883static int32_t U_CALLCONV 1884repTextReplace(UText *ut, 1885 int64_t start, int64_t limit, 1886 const UChar *src, int32_t length, 1887 UErrorCode *status) { 1888 Replaceable *rep=(Replaceable *)ut->context; 1889 int32_t oldLength; 1890 1891 if(U_FAILURE(*status)) { 1892 return 0; 1893 } 1894 if(src==NULL && length!=0) { 1895 *status=U_ILLEGAL_ARGUMENT_ERROR; 1896 return 0; 1897 } 1898 oldLength=rep->length(); // will subtract from new length 1899 if(start>limit ) { 1900 *status=U_INDEX_OUTOFBOUNDS_ERROR; 1901 return 0; 1902 } 1903 1904 int32_t start32 = pinIndex(start, oldLength); 1905 int32_t limit32 = pinIndex(limit, oldLength); 1906 1907 // Snap start & limit to code point boundaries. 1908 if (start32<oldLength && U16_IS_TRAIL(rep->charAt(start32)) && 1909 start32>0 && U16_IS_LEAD(rep->charAt(start32-1))) 1910 { 1911 start32--; 1912 } 1913 if (limit32<oldLength && U16_IS_LEAD(rep->charAt(limit32-1)) && 1914 U16_IS_TRAIL(rep->charAt(limit32))) 1915 { 1916 limit32++; 1917 } 1918 1919 // Do the actual replace operation using methods of the Replaceable class 1920 UnicodeString replStr((UBool)(length<0), src, length); // read-only alias 1921 rep->handleReplaceBetween(start32, limit32, replStr); 1922 int32_t newLength = rep->length(); 1923 int32_t lengthDelta = newLength - oldLength; 1924 1925 // Is the UText chunk buffer OK? 1926 if (ut->chunkNativeLimit > start32) { 1927 // this replace operation may have impacted the current chunk. 1928 // invalidate it, which will force a reload on the next access. 1929 invalidateChunk(ut); 1930 } 1931 1932 // set the iteration position to the end of the newly inserted replacement text. 1933 int32_t newIndexPos = limit32 + lengthDelta; 1934 repTextAccess(ut, newIndexPos, TRUE); 1935 1936 return lengthDelta; 1937} 1938 1939 1940static void U_CALLCONV 1941repTextCopy(UText *ut, 1942 int64_t start, int64_t limit, 1943 int64_t destIndex, 1944 UBool move, 1945 UErrorCode *status) 1946{ 1947 Replaceable *rep=(Replaceable *)ut->context; 1948 int32_t length=rep->length(); 1949 1950 if(U_FAILURE(*status)) { 1951 return; 1952 } 1953 if (start>limit || (start<destIndex && destIndex<limit)) 1954 { 1955 *status=U_INDEX_OUTOFBOUNDS_ERROR; 1956 return; 1957 } 1958 1959 int32_t start32 = pinIndex(start, length); 1960 int32_t limit32 = pinIndex(limit, length); 1961 int32_t destIndex32 = pinIndex(destIndex, length); 1962 1963 // TODO: snap input parameters to code point boundaries. 1964 1965 if(move) { 1966 // move: copy to destIndex, then replace original with nothing 1967 int32_t segLength=limit32-start32; 1968 rep->copy(start32, limit32, destIndex32); 1969 if(destIndex32<start32) { 1970 start32+=segLength; 1971 limit32+=segLength; 1972 } 1973 rep->handleReplaceBetween(start32, limit32, UnicodeString()); 1974 } else { 1975 // copy 1976 rep->copy(start32, limit32, destIndex32); 1977 } 1978 1979 // If the change to the text touched the region in the chunk buffer, 1980 // invalidate the buffer. 1981 int32_t firstAffectedIndex = destIndex32; 1982 if (move && start32<firstAffectedIndex) { 1983 firstAffectedIndex = start32; 1984 } 1985 if (firstAffectedIndex < ut->chunkNativeLimit) { 1986 // changes may have affected range covered by the chunk 1987 invalidateChunk(ut); 1988 } 1989 1990 // Put iteration position at the newly inserted (moved) block, 1991 int32_t nativeIterIndex = destIndex32 + limit32 - start32; 1992 if (move && destIndex32>start32) { 1993 // moved a block of text towards the end of the string. 1994 nativeIterIndex = destIndex32; 1995 } 1996 1997 // Set position, reload chunk if needed. 1998 repTextAccess(ut, nativeIterIndex, TRUE); 1999} 2000 2001static const struct UTextFuncs repFuncs = 2002{ 2003 sizeof(UTextFuncs), 2004 0, 0, 0, // Reserved alignment padding 2005 repTextClone, 2006 repTextLength, 2007 repTextAccess, 2008 repTextExtract, 2009 repTextReplace, 2010 repTextCopy, 2011 NULL, // MapOffsetToNative, 2012 NULL, // MapIndexToUTF16, 2013 repTextClose, 2014 NULL, // spare 1 2015 NULL, // spare 2 2016 NULL // spare 3 2017}; 2018 2019 2020U_CAPI UText * U_EXPORT2 2021utext_openReplaceable(UText *ut, Replaceable *rep, UErrorCode *status) 2022{ 2023 if(U_FAILURE(*status)) { 2024 return NULL; 2025 } 2026 if(rep==NULL) { 2027 *status=U_ILLEGAL_ARGUMENT_ERROR; 2028 return NULL; 2029 } 2030 ut = utext_setup(ut, sizeof(ReplExtra), status); 2031 2032 ut->providerProperties = I32_FLAG(UTEXT_PROVIDER_WRITABLE); 2033 if(rep->hasMetaData()) { 2034 ut->providerProperties |=I32_FLAG(UTEXT_PROVIDER_HAS_META_DATA); 2035 } 2036 2037 ut->pFuncs = &repFuncs; 2038 ut->context = rep; 2039 return ut; 2040} 2041 2042U_CDECL_END 2043 2044 2045 2046 2047 2048 2049 2050 2051//------------------------------------------------------------------------------ 2052// 2053// UText implementation for UnicodeString (read/write) and 2054// for const UnicodeString (read only) 2055// (same implementation, only the flags are different) 2056// 2057// Use of UText data members: 2058// context pointer to UnicodeString 2059// p pointer to UnicodeString IF this UText owns the string 2060// and it must be deleted on close(). NULL otherwise. 2061// 2062//------------------------------------------------------------------------------ 2063 2064U_CDECL_BEGIN 2065 2066 2067static UText * U_CALLCONV 2068unistrTextClone(UText *dest, const UText *src, UBool deep, UErrorCode *status) { 2069 // First do a generic shallow clone. Does everything needed for the UText struct itself. 2070 dest = shallowTextClone(dest, src, status); 2071 2072 // For deep clones, make a copy of the UnicodeSring. 2073 // The copied UnicodeString storage is owned by the newly created UText clone. 2074 // A non-NULL pointer in UText.p is the signal to the close() function to delete 2075 // the UText. 2076 // 2077 if (deep && U_SUCCESS(*status)) { 2078 const UnicodeString *srcString = (const UnicodeString *)src->context; 2079 dest->context = new UnicodeString(*srcString); 2080 dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT); 2081 2082 // with deep clone, the copy is writable, even when the source is not. 2083 dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_WRITABLE); 2084 } 2085 return dest; 2086} 2087 2088static void U_CALLCONV 2089unistrTextClose(UText *ut) { 2090 // Most of the work of close is done by the generic UText framework close. 2091 // All that needs to be done here is delete the UnicodeString if the UText 2092 // owns it. This occurs if the UText was created by cloning. 2093 if (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT)) { 2094 UnicodeString *str = (UnicodeString *)ut->context; 2095 delete str; 2096 ut->context = NULL; 2097 } 2098} 2099 2100 2101static int64_t U_CALLCONV 2102unistrTextLength(UText *t) { 2103 return ((const UnicodeString *)t->context)->length(); 2104} 2105 2106 2107static UBool U_CALLCONV 2108unistrTextAccess(UText *ut, int64_t index, UBool forward) { 2109 int32_t length = ut->chunkLength; 2110 ut->chunkOffset = pinIndex(index, length); 2111 2112 // Check whether request is at the start or end 2113 UBool retVal = (forward && index<length) || (!forward && index>0); 2114 return retVal; 2115} 2116 2117 2118 2119static int32_t U_CALLCONV 2120unistrTextExtract(UText *t, 2121 int64_t start, int64_t limit, 2122 UChar *dest, int32_t destCapacity, 2123 UErrorCode *pErrorCode) { 2124 const UnicodeString *us=(const UnicodeString *)t->context; 2125 int32_t length=us->length(); 2126 2127 if(U_FAILURE(*pErrorCode)) { 2128 return 0; 2129 } 2130 if(destCapacity<0 || (dest==NULL && destCapacity>0)) { 2131 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 2132 } 2133 if(start<0 || start>limit) { 2134 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 2135 return 0; 2136 } 2137 2138 int32_t start32 = start<length ? us->getChar32Start((int32_t)start) : length; 2139 int32_t limit32 = limit<length ? us->getChar32Start((int32_t)limit) : length; 2140 2141 length=limit32-start32; 2142 if (destCapacity>0 && dest!=NULL) { 2143 int32_t trimmedLength = length; 2144 if(trimmedLength>destCapacity) { 2145 trimmedLength=destCapacity; 2146 } 2147 us->extract(start32, trimmedLength, dest); 2148 t->chunkOffset = start32+trimmedLength; 2149 } else { 2150 t->chunkOffset = start32; 2151 } 2152 u_terminateUChars(dest, destCapacity, length, pErrorCode); 2153 return length; 2154} 2155 2156static int32_t U_CALLCONV 2157unistrTextReplace(UText *ut, 2158 int64_t start, int64_t limit, 2159 const UChar *src, int32_t length, 2160 UErrorCode *pErrorCode) { 2161 UnicodeString *us=(UnicodeString *)ut->context; 2162 int32_t oldLength; 2163 2164 if(U_FAILURE(*pErrorCode)) { 2165 return 0; 2166 } 2167 if(src==NULL && length!=0) { 2168 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 2169 } 2170 if(start>limit) { 2171 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 2172 return 0; 2173 } 2174 oldLength=us->length(); 2175 int32_t start32 = pinIndex(start, oldLength); 2176 int32_t limit32 = pinIndex(limit, oldLength); 2177 if (start32 < oldLength) { 2178 start32 = us->getChar32Start(start32); 2179 } 2180 if (limit32 < oldLength) { 2181 limit32 = us->getChar32Start(limit32); 2182 } 2183 2184 // replace 2185 us->replace(start32, limit32-start32, src, length); 2186 int32_t newLength = us->length(); 2187 2188 // Update the chunk description. 2189 ut->chunkContents = us->getBuffer(); 2190 ut->chunkLength = newLength; 2191 ut->chunkNativeLimit = newLength; 2192 ut->nativeIndexingLimit = newLength; 2193 2194 // Set iteration position to the point just following the newly inserted text. 2195 int32_t lengthDelta = newLength - oldLength; 2196 ut->chunkOffset = limit32 + lengthDelta; 2197 2198 return lengthDelta; 2199} 2200 2201static void U_CALLCONV 2202unistrTextCopy(UText *ut, 2203 int64_t start, int64_t limit, 2204 int64_t destIndex, 2205 UBool move, 2206 UErrorCode *pErrorCode) { 2207 UnicodeString *us=(UnicodeString *)ut->context; 2208 int32_t length=us->length(); 2209 2210 if(U_FAILURE(*pErrorCode)) { 2211 return; 2212 } 2213 int32_t start32 = pinIndex(start, length); 2214 int32_t limit32 = pinIndex(limit, length); 2215 int32_t destIndex32 = pinIndex(destIndex, length); 2216 2217 if( start32>limit32 || (start32<destIndex32 && destIndex32<limit32)) { 2218 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 2219 return; 2220 } 2221 2222 if(move) { 2223 // move: copy to destIndex, then replace original with nothing 2224 int32_t segLength=limit32-start32; 2225 us->copy(start32, limit32, destIndex32); 2226 if(destIndex32<start32) { 2227 start32+=segLength; 2228 } 2229 us->replace(start32, segLength, NULL, 0); 2230 } else { 2231 // copy 2232 us->copy(start32, limit32, destIndex32); 2233 } 2234 2235 // update chunk description, set iteration position. 2236 ut->chunkContents = us->getBuffer(); 2237 if (move==FALSE) { 2238 // copy operation, string length grows 2239 ut->chunkLength += limit32-start32; 2240 ut->chunkNativeLimit = ut->chunkLength; 2241 ut->nativeIndexingLimit = ut->chunkLength; 2242 } 2243 2244 // Iteration position to end of the newly inserted text. 2245 ut->chunkOffset = destIndex32+limit32-start32; 2246 if (move && destIndex32>start32) { 2247 ut->chunkOffset = destIndex32; 2248 } 2249 2250} 2251 2252static const struct UTextFuncs unistrFuncs = 2253{ 2254 sizeof(UTextFuncs), 2255 0, 0, 0, // Reserved alignment padding 2256 unistrTextClone, 2257 unistrTextLength, 2258 unistrTextAccess, 2259 unistrTextExtract, 2260 unistrTextReplace, 2261 unistrTextCopy, 2262 NULL, // MapOffsetToNative, 2263 NULL, // MapIndexToUTF16, 2264 unistrTextClose, 2265 NULL, // spare 1 2266 NULL, // spare 2 2267 NULL // spare 3 2268}; 2269 2270 2271 2272U_CDECL_END 2273 2274 2275U_CAPI UText * U_EXPORT2 2276utext_openUnicodeString(UText *ut, UnicodeString *s, UErrorCode *status) { 2277 ut = utext_openConstUnicodeString(ut, s, status); 2278 if (U_SUCCESS(*status)) { 2279 ut->providerProperties |= I32_FLAG(UTEXT_PROVIDER_WRITABLE); 2280 } 2281 return ut; 2282} 2283 2284 2285 2286U_CAPI UText * U_EXPORT2 2287utext_openConstUnicodeString(UText *ut, const UnicodeString *s, UErrorCode *status) { 2288 if (U_SUCCESS(*status) && s->isBogus()) { 2289 // The UnicodeString is bogus, but we still need to detach the UText 2290 // from whatever it was hooked to before, if anything. 2291 utext_openUChars(ut, NULL, 0, status); 2292 *status = U_ILLEGAL_ARGUMENT_ERROR; 2293 return ut; 2294 } 2295 ut = utext_setup(ut, 0, status); 2296 // note: use the standard (writable) function table for UnicodeString. 2297 // The flag settings disable writing, so having the functions in 2298 // the table is harmless. 2299 if (U_SUCCESS(*status)) { 2300 ut->pFuncs = &unistrFuncs; 2301 ut->context = s; 2302 ut->providerProperties = I32_FLAG(UTEXT_PROVIDER_STABLE_CHUNKS); 2303 ut->chunkContents = s->getBuffer(); 2304 ut->chunkLength = s->length(); 2305 ut->chunkNativeStart = 0; 2306 ut->chunkNativeLimit = ut->chunkLength; 2307 ut->nativeIndexingLimit = ut->chunkLength; 2308 } 2309 return ut; 2310} 2311 2312//------------------------------------------------------------------------------ 2313// 2314// UText implementation for const UChar * strings 2315// 2316// Use of UText data members: 2317// context pointer to UnicodeString 2318// a length. -1 if not yet known. 2319// 2320// TODO: support 64 bit lengths. 2321// 2322//------------------------------------------------------------------------------ 2323 2324U_CDECL_BEGIN 2325 2326 2327static UText * U_CALLCONV 2328ucstrTextClone(UText *dest, const UText * src, UBool deep, UErrorCode * status) { 2329 // First do a generic shallow clone. 2330 dest = shallowTextClone(dest, src, status); 2331 2332 // For deep clones, make a copy of the string. 2333 // The copied storage is owned by the newly created clone. 2334 // A non-NULL pointer in UText.p is the signal to the close() function to delete 2335 // it. 2336 // 2337 if (deep && U_SUCCESS(*status)) { 2338 U_ASSERT(utext_nativeLength(dest) < INT32_MAX); 2339 int32_t len = (int32_t)utext_nativeLength(dest); 2340 2341 // The cloned string IS going to be NUL terminated, whether or not the original was. 2342 const UChar *srcStr = (const UChar *)src->context; 2343 UChar *copyStr = (UChar *)uprv_malloc((len+1) * sizeof(UChar)); 2344 if (copyStr == NULL) { 2345 *status = U_MEMORY_ALLOCATION_ERROR; 2346 } else { 2347 int64_t i; 2348 for (i=0; i<len; i++) { 2349 copyStr[i] = srcStr[i]; 2350 } 2351 copyStr[len] = 0; 2352 dest->context = copyStr; 2353 dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT); 2354 } 2355 } 2356 return dest; 2357} 2358 2359 2360static void U_CALLCONV 2361ucstrTextClose(UText *ut) { 2362 // Most of the work of close is done by the generic UText framework close. 2363 // All that needs to be done here is delete the string if the UText 2364 // owns it. This occurs if the UText was created by cloning. 2365 if (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT)) { 2366 UChar *s = (UChar *)ut->context; 2367 uprv_free(s); 2368 ut->context = NULL; 2369 } 2370} 2371 2372 2373 2374static int64_t U_CALLCONV 2375ucstrTextLength(UText *ut) { 2376 if (ut->a < 0) { 2377 // null terminated, we don't yet know the length. Scan for it. 2378 // Access is not convenient for doing this 2379 // because the current interation postion can't be changed. 2380 const UChar *str = (const UChar *)ut->context; 2381 for (;;) { 2382 if (str[ut->chunkNativeLimit] == 0) { 2383 break; 2384 } 2385 ut->chunkNativeLimit++; 2386 } 2387 ut->a = ut->chunkNativeLimit; 2388 ut->chunkLength = (int32_t)ut->chunkNativeLimit; 2389 ut->nativeIndexingLimit = ut->chunkLength; 2390 ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 2391 } 2392 return ut->a; 2393} 2394 2395 2396static UBool U_CALLCONV 2397ucstrTextAccess(UText *ut, int64_t index, UBool forward) { 2398 const UChar *str = (const UChar *)ut->context; 2399 2400 // pin the requested index to the bounds of the string, 2401 // and set current iteration position. 2402 if (index<0) { 2403 index = 0; 2404 } else if (index < ut->chunkNativeLimit) { 2405 // The request data is within the chunk as it is known so far. 2406 // Put index on a code point boundary. 2407 U16_SET_CP_START(str, 0, index); 2408 } else if (ut->a >= 0) { 2409 // We know the length of this string, and the user is requesting something 2410 // at or beyond the length. Pin the requested index to the length. 2411 index = ut->a; 2412 } else { 2413 // Null terminated string, length not yet known, and the requested index 2414 // is beyond where we have scanned so far. 2415 // Scan to 32 UChars beyond the requested index. The strategy here is 2416 // to avoid fully scanning a long string when the caller only wants to 2417 // see a few characters at its beginning. 2418 int32_t scanLimit = (int32_t)index + 32; 2419 if ((index + 32)>INT32_MAX || (index + 32)<0 ) { // note: int64 expression 2420 scanLimit = INT32_MAX; 2421 } 2422 2423 int32_t chunkLimit = (int32_t)ut->chunkNativeLimit; 2424 for (; chunkLimit<scanLimit; chunkLimit++) { 2425 if (str[chunkLimit] == 0) { 2426 // We found the end of the string. Remember it, pin the requested index to it, 2427 // and bail out of here. 2428 ut->a = chunkLimit; 2429 ut->chunkLength = chunkLimit; 2430 ut->nativeIndexingLimit = chunkLimit; 2431 if (index >= chunkLimit) { 2432 index = chunkLimit; 2433 } else { 2434 U16_SET_CP_START(str, 0, index); 2435 } 2436 2437 ut->chunkNativeLimit = chunkLimit; 2438 ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 2439 goto breakout; 2440 } 2441 } 2442 // We scanned through the next batch of UChars without finding the end. 2443 U16_SET_CP_START(str, 0, index); 2444 if (chunkLimit == INT32_MAX) { 2445 // Scanned to the limit of a 32 bit length. 2446 // Forceably trim the overlength string back so length fits in int32 2447 // TODO: add support for 64 bit strings. 2448 ut->a = chunkLimit; 2449 ut->chunkLength = chunkLimit; 2450 ut->nativeIndexingLimit = chunkLimit; 2451 if (index > chunkLimit) { 2452 index = chunkLimit; 2453 } 2454 ut->chunkNativeLimit = chunkLimit; 2455 ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 2456 } else { 2457 // The endpoint of a chunk must not be left in the middle of a surrogate pair. 2458 // If the current end is on a lead surrogate, back the end up by one. 2459 // It doesn't matter if the end char happens to be an unpaired surrogate, 2460 // and it's simpler not to worry about it. 2461 if (U16_IS_LEAD(str[chunkLimit-1])) { 2462 --chunkLimit; 2463 } 2464 // Null-terminated chunk with end still unknown. 2465 // Update the chunk length to reflect what has been scanned thus far. 2466 // That the full length is still unknown is (still) flagged by 2467 // ut->a being < 0. 2468 ut->chunkNativeLimit = chunkLimit; 2469 ut->nativeIndexingLimit = chunkLimit; 2470 ut->chunkLength = chunkLimit; 2471 } 2472 2473 } 2474breakout: 2475 U_ASSERT(index<=INT32_MAX); 2476 ut->chunkOffset = (int32_t)index; 2477 2478 // Check whether request is at the start or end 2479 UBool retVal = (forward && index<ut->chunkNativeLimit) || (!forward && index>0); 2480 return retVal; 2481} 2482 2483 2484 2485static int32_t U_CALLCONV 2486ucstrTextExtract(UText *ut, 2487 int64_t start, int64_t limit, 2488 UChar *dest, int32_t destCapacity, 2489 UErrorCode *pErrorCode) 2490{ 2491 if(U_FAILURE(*pErrorCode)) { 2492 return 0; 2493 } 2494 if(destCapacity<0 || (dest==NULL && destCapacity>0) || start>limit) { 2495 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 2496 return 0; 2497 } 2498 2499 //const UChar *s=(const UChar *)ut->context; 2500 int32_t si, di; 2501 2502 int32_t start32; 2503 int32_t limit32; 2504 2505 // Access the start. Does two things we need: 2506 // Pins 'start' to the length of the string, if it came in out-of-bounds. 2507 // Snaps 'start' to the beginning of a code point. 2508 ucstrTextAccess(ut, start, TRUE); 2509 const UChar *s=ut->chunkContents; 2510 start32 = ut->chunkOffset; 2511 2512 int32_t strLength=(int32_t)ut->a; 2513 if (strLength >= 0) { 2514 limit32 = pinIndex(limit, strLength); 2515 } else { 2516 limit32 = pinIndex(limit, INT32_MAX); 2517 } 2518 di = 0; 2519 for (si=start32; si<limit32; si++) { 2520 if (strLength<0 && s[si]==0) { 2521 // Just hit the end of a null-terminated string. 2522 ut->a = si; // set string length for this UText 2523 ut->chunkNativeLimit = si; 2524 ut->chunkLength = si; 2525 ut->nativeIndexingLimit = si; 2526 strLength = si; 2527 break; 2528 } 2529 U_ASSERT(di>=0); /* to ensure di never exceeds INT32_MAX, which must not happen logically */ 2530 if (di<destCapacity) { 2531 // only store if there is space. 2532 dest[di] = s[si]; 2533 } else { 2534 if (strLength>=0) { 2535 // We have filled the destination buffer, and the string length is known. 2536 // Cut the loop short. There is no need to scan string termination. 2537 di = limit32 - start32; 2538 si = limit32; 2539 break; 2540 } 2541 } 2542 di++; 2543 } 2544 2545 // If the limit index points to a lead surrogate of a pair, 2546 // add the corresponding trail surrogate to the destination. 2547 if (si>0 && U16_IS_LEAD(s[si-1]) && 2548 ((si<strLength || strLength<0) && U16_IS_TRAIL(s[si]))) 2549 { 2550 if (di<destCapacity) { 2551 // store only if there is space in the output buffer. 2552 dest[di++] = s[si++]; 2553 } 2554 } 2555 2556 // Put iteration position at the point just following the extracted text 2557 ut->chunkOffset = uprv_min(strLength, start32 + destCapacity); 2558 2559 // Add a terminating NUL if space in the buffer permits, 2560 // and set the error status as required. 2561 u_terminateUChars(dest, destCapacity, di, pErrorCode); 2562 return di; 2563} 2564 2565static const struct UTextFuncs ucstrFuncs = 2566{ 2567 sizeof(UTextFuncs), 2568 0, 0, 0, // Reserved alignment padding 2569 ucstrTextClone, 2570 ucstrTextLength, 2571 ucstrTextAccess, 2572 ucstrTextExtract, 2573 NULL, // Replace 2574 NULL, // Copy 2575 NULL, // MapOffsetToNative, 2576 NULL, // MapIndexToUTF16, 2577 ucstrTextClose, 2578 NULL, // spare 1 2579 NULL, // spare 2 2580 NULL, // spare 3 2581}; 2582 2583U_CDECL_END 2584 2585static const UChar gEmptyUString[] = {0}; 2586 2587U_CAPI UText * U_EXPORT2 2588utext_openUChars(UText *ut, const UChar *s, int64_t length, UErrorCode *status) { 2589 if (U_FAILURE(*status)) { 2590 return NULL; 2591 } 2592 if(s==NULL && length==0) { 2593 s = gEmptyUString; 2594 } 2595 if (s==NULL || length < -1 || length>INT32_MAX) { 2596 *status = U_ILLEGAL_ARGUMENT_ERROR; 2597 return NULL; 2598 } 2599 ut = utext_setup(ut, 0, status); 2600 if (U_SUCCESS(*status)) { 2601 ut->pFuncs = &ucstrFuncs; 2602 ut->context = s; 2603 ut->providerProperties = I32_FLAG(UTEXT_PROVIDER_STABLE_CHUNKS); 2604 if (length==-1) { 2605 ut->providerProperties |= I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE); 2606 } 2607 ut->a = length; 2608 ut->chunkContents = s; 2609 ut->chunkNativeStart = 0; 2610 ut->chunkNativeLimit = length>=0? length : 0; 2611 ut->chunkLength = (int32_t)ut->chunkNativeLimit; 2612 ut->chunkOffset = 0; 2613 ut->nativeIndexingLimit = ut->chunkLength; 2614 } 2615 return ut; 2616} 2617 2618 2619//------------------------------------------------------------------------------ 2620// 2621// UText implementation for text from ICU CharacterIterators 2622// 2623// Use of UText data members: 2624// context pointer to the CharacterIterator 2625// a length of the full text. 2626// p pointer to buffer 1 2627// b start index of local buffer 1 contents 2628// q pointer to buffer 2 2629// c start index of local buffer 2 contents 2630// r pointer to the character iterator if the UText owns it. 2631// Null otherwise. 2632// 2633//------------------------------------------------------------------------------ 2634#define CIBufSize 16 2635 2636U_CDECL_BEGIN 2637static void U_CALLCONV 2638charIterTextClose(UText *ut) { 2639 // Most of the work of close is done by the generic UText framework close. 2640 // All that needs to be done here is delete the CharacterIterator if the UText 2641 // owns it. This occurs if the UText was created by cloning. 2642 CharacterIterator *ci = (CharacterIterator *)ut->r; 2643 delete ci; 2644 ut->r = NULL; 2645} 2646 2647static int64_t U_CALLCONV 2648charIterTextLength(UText *ut) { 2649 return (int32_t)ut->a; 2650} 2651 2652static UBool U_CALLCONV 2653charIterTextAccess(UText *ut, int64_t index, UBool forward) { 2654 CharacterIterator *ci = (CharacterIterator *)ut->context; 2655 2656 int32_t clippedIndex = (int32_t)index; 2657 if (clippedIndex<0) { 2658 clippedIndex=0; 2659 } else if (clippedIndex>=ut->a) { 2660 clippedIndex=(int32_t)ut->a; 2661 } 2662 int32_t neededIndex = clippedIndex; 2663 if (!forward && neededIndex>0) { 2664 // reverse iteration, want the position just before what was asked for. 2665 neededIndex--; 2666 } else if (forward && neededIndex==ut->a && neededIndex>0) { 2667 // Forward iteration, don't ask for something past the end of the text. 2668 neededIndex--; 2669 } 2670 2671 // Find the native index of the start of the buffer containing what we want. 2672 neededIndex -= neededIndex % CIBufSize; 2673 2674 UChar *buf = NULL; 2675 UBool needChunkSetup = TRUE; 2676 int i; 2677 if (ut->chunkNativeStart == neededIndex) { 2678 // The buffer we want is already the current chunk. 2679 needChunkSetup = FALSE; 2680 } else if (ut->b == neededIndex) { 2681 // The first buffer (buffer p) has what we need. 2682 buf = (UChar *)ut->p; 2683 } else if (ut->c == neededIndex) { 2684 // The second buffer (buffer q) has what we need. 2685 buf = (UChar *)ut->q; 2686 } else { 2687 // Neither buffer already has what we need. 2688 // Load new data from the character iterator. 2689 // Use the buf that is not the current buffer. 2690 buf = (UChar *)ut->p; 2691 if (ut->p == ut->chunkContents) { 2692 buf = (UChar *)ut->q; 2693 } 2694 ci->setIndex(neededIndex); 2695 for (i=0; i<CIBufSize; i++) { 2696 buf[i] = ci->nextPostInc(); 2697 if (i+neededIndex > ut->a) { 2698 break; 2699 } 2700 } 2701 } 2702 2703 // We have a buffer with the data we need. 2704 // Set it up as the current chunk, if it wasn't already. 2705 if (needChunkSetup) { 2706 ut->chunkContents = buf; 2707 ut->chunkLength = CIBufSize; 2708 ut->chunkNativeStart = neededIndex; 2709 ut->chunkNativeLimit = neededIndex + CIBufSize; 2710 if (ut->chunkNativeLimit > ut->a) { 2711 ut->chunkNativeLimit = ut->a; 2712 ut->chunkLength = (int32_t)(ut->chunkNativeLimit)-(int32_t)(ut->chunkNativeStart); 2713 } 2714 ut->nativeIndexingLimit = ut->chunkLength; 2715 U_ASSERT(ut->chunkOffset>=0 && ut->chunkOffset<=CIBufSize); 2716 } 2717 ut->chunkOffset = clippedIndex - (int32_t)ut->chunkNativeStart; 2718 UBool success = (forward? ut->chunkOffset<ut->chunkLength : ut->chunkOffset>0); 2719 return success; 2720} 2721 2722static UText * U_CALLCONV 2723charIterTextClone(UText *dest, const UText *src, UBool deep, UErrorCode * status) { 2724 if (U_FAILURE(*status)) { 2725 return NULL; 2726 } 2727 2728 if (deep) { 2729 // There is no CharacterIterator API for cloning the underlying text storage. 2730 *status = U_UNSUPPORTED_ERROR; 2731 return NULL; 2732 } else { 2733 CharacterIterator *srcCI =(CharacterIterator *)src->context; 2734 srcCI = srcCI->clone(); 2735 dest = utext_openCharacterIterator(dest, srcCI, status); 2736 // cast off const on getNativeIndex. 2737 // For CharacterIterator based UTexts, this is safe, the operation is const. 2738 int64_t ix = utext_getNativeIndex((UText *)src); 2739 utext_setNativeIndex(dest, ix); 2740 dest->r = srcCI; // flags that this UText owns the CharacterIterator 2741 } 2742 return dest; 2743} 2744 2745static int32_t U_CALLCONV 2746charIterTextExtract(UText *ut, 2747 int64_t start, int64_t limit, 2748 UChar *dest, int32_t destCapacity, 2749 UErrorCode *status) 2750{ 2751 if(U_FAILURE(*status)) { 2752 return 0; 2753 } 2754 if(destCapacity<0 || (dest==NULL && destCapacity>0) || start>limit) { 2755 *status=U_ILLEGAL_ARGUMENT_ERROR; 2756 return 0; 2757 } 2758 int32_t length = (int32_t)ut->a; 2759 int32_t start32 = pinIndex(start, length); 2760 int32_t limit32 = pinIndex(limit, length); 2761 int32_t desti = 0; 2762 int32_t srci; 2763 int32_t copyLimit; 2764 2765 CharacterIterator *ci = (CharacterIterator *)ut->context; 2766 ci->setIndex32(start32); // Moves ix to lead of surrogate pair, if needed. 2767 srci = ci->getIndex(); 2768 copyLimit = srci; 2769 while (srci<limit32) { 2770 UChar32 c = ci->next32PostInc(); 2771 int32_t len = U16_LENGTH(c); 2772 U_ASSERT(desti+len>0); /* to ensure desti+len never exceeds MAX_INT32, which must not happen logically */ 2773 if (desti+len <= destCapacity) { 2774 U16_APPEND_UNSAFE(dest, desti, c); 2775 copyLimit = srci+len; 2776 } else { 2777 desti += len; 2778 *status = U_BUFFER_OVERFLOW_ERROR; 2779 } 2780 srci += len; 2781 } 2782 2783 charIterTextAccess(ut, copyLimit, TRUE); 2784 2785 u_terminateUChars(dest, destCapacity, desti, status); 2786 return desti; 2787} 2788 2789static const struct UTextFuncs charIterFuncs = 2790{ 2791 sizeof(UTextFuncs), 2792 0, 0, 0, // Reserved alignment padding 2793 charIterTextClone, 2794 charIterTextLength, 2795 charIterTextAccess, 2796 charIterTextExtract, 2797 NULL, // Replace 2798 NULL, // Copy 2799 NULL, // MapOffsetToNative, 2800 NULL, // MapIndexToUTF16, 2801 charIterTextClose, 2802 NULL, // spare 1 2803 NULL, // spare 2 2804 NULL // spare 3 2805}; 2806U_CDECL_END 2807 2808 2809U_CAPI UText * U_EXPORT2 2810utext_openCharacterIterator(UText *ut, CharacterIterator *ci, UErrorCode *status) { 2811 if (U_FAILURE(*status)) { 2812 return NULL; 2813 } 2814 2815 if (ci->startIndex() > 0) { 2816 // No support for CharacterIterators that do not start indexing from zero. 2817 *status = U_UNSUPPORTED_ERROR; 2818 return NULL; 2819 } 2820 2821 // Extra space in UText for 2 buffers of CIBufSize UChars each. 2822 int32_t extraSpace = 2 * CIBufSize * sizeof(UChar); 2823 ut = utext_setup(ut, extraSpace, status); 2824 if (U_SUCCESS(*status)) { 2825 ut->pFuncs = &charIterFuncs; 2826 ut->context = ci; 2827 ut->providerProperties = 0; 2828 ut->a = ci->endIndex(); // Length of text 2829 ut->p = ut->pExtra; // First buffer 2830 ut->b = -1; // Native index of first buffer contents 2831 ut->q = (UChar*)ut->pExtra+CIBufSize; // Second buffer 2832 ut->c = -1; // Native index of second buffer contents 2833 2834 // Initialize current chunk contents to be empty. 2835 // First access will fault something in. 2836 // Note: The initial nativeStart and chunkOffset must sum to zero 2837 // so that getNativeIndex() will correctly compute to zero 2838 // if no call to Access() has ever been made. They can't be both 2839 // zero without Access() thinking that the chunk is valid. 2840 ut->chunkContents = (UChar *)ut->p; 2841 ut->chunkNativeStart = -1; 2842 ut->chunkOffset = 1; 2843 ut->chunkNativeLimit = 0; 2844 ut->chunkLength = 0; 2845 ut->nativeIndexingLimit = ut->chunkOffset; // enables native indexing 2846 } 2847 return ut; 2848} 2849 2850 2851 2852