1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 30 авг. 2017 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #include <core/types.h> 23 #include <core/stdlib/stdio.h> 24 #include <core/stdlib/string.h> 25 26 #include <stdlib.h> 27 #include <errno.h> 28 #include <wctype.h> 29 #include <stdarg.h> 30 31 #include <core/io/charset.h> 32 #include <core/LSPString.h> 33 34 #define GRANULARITY 0x20 35 #define BUF_SIZE 0x200 36 //#define BUF_SIZE 16 37 38 #define XSAFE_TRANS(index, length, result) \ 39 if (index < 0) \ 40 { \ 41 if ((index += (length)) < 0) \ 42 return result; \ 43 } \ 44 else if (size_t(index) > (length)) \ 45 return result; 46 47 #define XSAFE_ITRANS(index, length, result) \ 48 if (index < 0) \ 49 { \ 50 if ((index += (length)) < 0) \ 51 return result; \ 52 } \ 53 else if (size_t(index) >= (length)) \ 54 return result; 55 56 namespace lsp 57 { 58 static lsp_utf16_t UTF16_NULL = 0; 59 is_space(lsp_wchar_t c)60 static bool is_space(lsp_wchar_t c) 61 { 62 switch (c) 63 { 64 case ' ': 65 case '\t': 66 case '\n': 67 case '\r': 68 case '\v': 69 return true; 70 default: 71 return false; 72 } 73 } 74 LSPString()75 LSPString::LSPString() 76 { 77 nLength = 0; 78 nCapacity = 0; 79 pData = NULL; 80 pTemp = NULL; 81 } 82 ~LSPString()83 LSPString::~LSPString() 84 { 85 truncate(); 86 } 87 88 #ifndef ARCH_LE xcmp(const lsp_wchar_t * a,const lsp_wchar_t * b,size_t n)89 int LSPString::xcmp(const lsp_wchar_t *a, const lsp_wchar_t *b, size_t n) 90 { 91 while (n--) 92 { 93 int32_t retval = int32_t(*(a++)) - int32_t(*(b++)); 94 if (retval != 0) 95 return (retval > 0) ? 1 : -1; 96 } 97 return 0; 98 } 99 #endif /* ARCH_LE */ 100 xlen(const lsp_wchar_t * s)101 inline size_t LSPString::xlen(const lsp_wchar_t *s) 102 { 103 const lsp_wchar_t *p = s; 104 while (*p != '\0') 105 ++p; 106 return p - s; 107 } 108 xcasecmp(const lsp_wchar_t * a,const lsp_wchar_t * b,size_t n)109 int LSPString::xcasecmp(const lsp_wchar_t *a, const lsp_wchar_t *b, size_t n) 110 { 111 while (n--) 112 { 113 int32_t retval = int32_t(towlower(*(a++))) - int32_t(towlower(*(b++))); 114 if (retval != 0) 115 return (retval > 0) ? 1 : -1; 116 } 117 return 0; 118 } 119 acopy(lsp_wchar_t * dst,const char * src,size_t n)120 void LSPString::acopy(lsp_wchar_t *dst, const char *src, size_t n) 121 { 122 while (n--) 123 *(dst++) = uint8_t(*(src++)); 124 } 125 drop_temp()126 void LSPString::drop_temp() 127 { 128 if (pTemp == NULL) 129 return; 130 131 if (pTemp->pData != NULL) 132 ::free(pTemp->pData); 133 134 ::free(pTemp); 135 pTemp = NULL; 136 } 137 clear()138 void LSPString::clear() 139 { 140 drop_temp(); 141 nLength = 0; 142 } 143 truncate()144 void LSPString::truncate() 145 { 146 drop_temp(); 147 148 nLength = 0; 149 nCapacity = 0; 150 if (pData == NULL) 151 return; 152 153 xfree(pData); 154 pData = NULL; 155 } 156 truncate(size_t size)157 bool LSPString::truncate(size_t size) 158 { 159 drop_temp(); 160 if (size > nCapacity) 161 return true; 162 if (nLength > size) 163 nLength = size; 164 165 lsp_wchar_t *v = xrealloc(pData, size); 166 if ((v == NULL) && (size > 0)) 167 return false; 168 169 pData = (size > 0) ? v : NULL; 170 nCapacity = size; 171 return true; 172 } 173 set_length(size_t length)174 size_t LSPString::set_length(size_t length) 175 { 176 if (nLength <= length) 177 return length; 178 drop_temp(); 179 return nLength = length; 180 } 181 size_reserve(size_t size)182 bool LSPString::size_reserve(size_t size) 183 { 184 if (size > 0) 185 { 186 lsp_wchar_t *v = xrealloc(pData, size); 187 if (v == NULL) 188 return false; 189 pData = v; 190 } 191 else if (pData != NULL) 192 { 193 ::free(pData); 194 pData = NULL; 195 } 196 197 nCapacity = size; 198 return true; 199 } 200 cap_reserve(size_t size)201 inline bool LSPString::cap_reserve(size_t size) 202 { 203 size_t ncap = (size + (GRANULARITY-1)) & (~(GRANULARITY-1)); 204 return (ncap > nCapacity) ? size_reserve(ncap) : true; 205 } 206 cap_grow(size_t delta)207 inline bool LSPString::cap_grow(size_t delta) 208 { 209 size_t avail = nCapacity - nLength; 210 if (delta <= avail) 211 return true; 212 avail = nCapacity >> 1; 213 if (avail < delta) 214 avail = delta; 215 return size_reserve(nCapacity + ((avail + (GRANULARITY-1)) & (~(GRANULARITY-1)))); 216 } 217 reduce()218 void LSPString::reduce() 219 { 220 drop_temp(); 221 if (nCapacity <= nLength) 222 return; 223 lsp_wchar_t *v = xrealloc(pData, nLength); 224 if ((v == NULL) && (nLength > 0)) 225 return; 226 pData = (nLength > 0) ? v : NULL; 227 nCapacity = nLength; 228 } 229 trim()230 void LSPString::trim() 231 { 232 if ((pData == NULL) || (nLength <= 0)) 233 return; 234 235 // Cut tail first 236 lsp_wchar_t *p = &pData[nLength]; 237 while (nLength > 0) 238 { 239 if (!is_space(*(--p))) 240 break; 241 nLength--; 242 } 243 if (nLength <= 0) 244 return; 245 246 // Cut head 247 p = pData; 248 while (true) 249 { 250 if (!is_space(*p)) 251 break; 252 p++; 253 } 254 if (p > pData) 255 nLength -= (p - pData); 256 if (nLength <= 0) 257 return; 258 259 xmove(pData, p, nLength); 260 } 261 swap(LSPString * src)262 void LSPString::swap(LSPString *src) 263 { 264 size_t len = src->nLength; 265 size_t cap = src->nCapacity; 266 lsp_wchar_t *c = src->pData; 267 268 src->nLength = nLength; 269 src->nCapacity = nCapacity; 270 src->pData = pData; 271 272 nLength = len; 273 nCapacity = cap; 274 pData = c; 275 } 276 swap(ssize_t idx1,ssize_t idx2)277 bool LSPString::swap(ssize_t idx1, ssize_t idx2) 278 { 279 XSAFE_ITRANS(idx1, nLength, false); 280 XSAFE_ITRANS(idx2, nLength, false); 281 if (idx1 == idx2) 282 return true; 283 284 // Swap characters 285 lsp_wchar_t c = pData[idx1]; 286 pData[idx1] = pData[idx2]; 287 pData[idx2] = c; 288 289 return true; 290 } 291 take(LSPString * src)292 void LSPString::take(LSPString *src) 293 { 294 drop_temp(); 295 if (pData != NULL) 296 xfree(pData); 297 298 nLength = src->nLength; 299 nCapacity = src->nCapacity; 300 pData = src->pData; 301 302 src->nLength = 0; 303 src->nCapacity = 0; 304 src->pData = NULL; 305 } 306 copy() const307 LSPString *LSPString::copy() const 308 { 309 LSPString *s = new LSPString(); 310 if (s == NULL) 311 return s; 312 313 s->nLength = nLength; 314 s->nCapacity = nLength; 315 if (s->nLength > 0) 316 { 317 s->pData = xmalloc(nLength); 318 if (s->pData == NULL) 319 { 320 delete s; 321 return NULL; 322 } 323 324 xmove(s->pData, pData, nLength); 325 } 326 else 327 s->pData = NULL; 328 329 return s; 330 } 331 release()332 LSPString *LSPString::release() 333 { 334 LSPString *str = new LSPString(); 335 if (str != NULL) 336 str->swap(this); 337 return str; 338 } 339 copy(ssize_t first) const340 LSPString *LSPString::copy(ssize_t first) const 341 { 342 LSPString *s = new LSPString(); 343 if (s != NULL) 344 { 345 if (!s->set(this, first)) 346 { 347 delete s; 348 s = NULL; 349 } 350 } 351 352 return s; 353 } 354 copy(ssize_t first,ssize_t last) const355 LSPString *LSPString::copy(ssize_t first, ssize_t last) const 356 { 357 LSPString *s = new LSPString(); 358 if (s != NULL) 359 { 360 if (!s->set(this, first, last)) 361 { 362 delete s; 363 s = NULL; 364 } 365 } 366 367 return s; 368 } 369 at(ssize_t index) const370 lsp_wchar_t LSPString::at(ssize_t index) const 371 { 372 if (index < 0) 373 { 374 if ((index += nLength) < 0) 375 return 0; 376 } 377 else if (size_t(index) >= nLength) 378 return 0; 379 380 return pData[index]; 381 } 382 first() const383 lsp_wchar_t LSPString::first() const 384 { 385 return (nLength > 0) ? pData[0] : 0; 386 } 387 last() const388 lsp_wchar_t LSPString::last() const 389 { 390 return (nLength > 0) ? pData[nLength-1] : 0; 391 } 392 set(lsp_wchar_t ch)393 bool LSPString::set(lsp_wchar_t ch) 394 { 395 drop_temp(); 396 397 if (nCapacity == 0) 398 { 399 lsp_wchar_t *v = xmalloc(GRANULARITY); 400 if (v == NULL) 401 return false; 402 v[0] = ch; 403 pData = v; 404 nCapacity = GRANULARITY; 405 } 406 else 407 pData[0] = ch; 408 409 nLength = 1; 410 return true; 411 } 412 set(const lsp_wchar_t * arr)413 bool LSPString::set(const lsp_wchar_t *arr) 414 { 415 return set(arr, xlen(arr)); 416 } 417 set(const lsp_wchar_t * arr,size_t n)418 bool LSPString::set(const lsp_wchar_t *arr, size_t n) 419 { 420 drop_temp(); 421 422 if (!cap_reserve(n)) 423 return false; 424 425 xmove(pData, arr, n); 426 nLength = n; 427 return true; 428 } 429 set(ssize_t first,lsp_wchar_t ch)430 bool LSPString::set(ssize_t first, lsp_wchar_t ch) 431 { 432 XSAFE_ITRANS(first, nLength, false); 433 pData[first] = ch; 434 return true; 435 } 436 set(const LSPString * src)437 bool LSPString::set(const LSPString *src) 438 { 439 if (src == this) 440 return true; 441 drop_temp(); 442 443 if (!cap_reserve(src->nLength)) 444 return false; 445 if (src->nLength > 0) 446 xmove(pData, src->pData, src->nLength); 447 nLength = src->nLength; 448 return true; 449 } 450 set(const LSPString * src,ssize_t first)451 bool LSPString::set(const LSPString *src, ssize_t first) 452 { 453 drop_temp(); 454 455 XSAFE_TRANS(first, src->nLength, false); 456 ssize_t length = src->nLength - first; 457 458 if (length > 0) 459 { 460 if (!cap_reserve(length)) 461 return false; 462 xmove(pData, &src->pData[first], length); 463 nLength = length; 464 } 465 else 466 nLength = 0; 467 return true; 468 } 469 set(const LSPString * src,ssize_t first,ssize_t last)470 bool LSPString::set(const LSPString *src, ssize_t first, ssize_t last) 471 { 472 drop_temp(); 473 474 XSAFE_TRANS(first, src->nLength, false); 475 XSAFE_TRANS(last, src->nLength, false); 476 477 ssize_t length = last - first; 478 if (length > 0) 479 { 480 if (!cap_reserve(length)) 481 return false; 482 xmove(pData, &src->pData[first], length); 483 nLength = length; 484 } 485 else 486 nLength = 0; 487 488 return true; 489 } 490 insert(ssize_t pos,lsp_wchar_t ch)491 bool LSPString::insert(ssize_t pos, lsp_wchar_t ch) 492 { 493 XSAFE_TRANS(pos, nLength, false); 494 495 if (!cap_grow(1)) 496 return false; 497 498 ssize_t length = nLength - pos; 499 if (length > 0) 500 xmove(&pData[pos+1], &pData[pos], length); 501 502 pData[pos] = ch; 503 nLength++; 504 return true; 505 } 506 insert(ssize_t pos,const lsp_wchar_t * arr,ssize_t n)507 bool LSPString::insert(ssize_t pos, const lsp_wchar_t *arr, ssize_t n) 508 { 509 XSAFE_TRANS(pos, nLength, false); 510 if (!cap_grow(n)) 511 return false; 512 513 ssize_t count = nLength - pos; 514 if (count > 0) 515 xmove(&pData[pos+n], &pData[pos], count); 516 xmove(&pData[pos], arr, n); 517 nLength += n; 518 519 return true; 520 } 521 insert(ssize_t pos,const LSPString * src)522 bool LSPString::insert(ssize_t pos, const LSPString *src) 523 { 524 if (src->nLength <= 0) 525 return true; 526 527 XSAFE_TRANS(pos, nLength, false); 528 if (!cap_grow(src->nLength)) 529 return false; 530 531 ssize_t count = nLength - pos; 532 if (count > 0) 533 xmove(&pData[pos+src->nLength], &pData[pos], count); 534 xmove(&pData[pos], src->pData, src->nLength); 535 nLength += src->nLength; 536 537 return true; 538 } 539 insert(ssize_t pos,const LSPString * src,ssize_t first)540 bool LSPString::insert(ssize_t pos, const LSPString *src, ssize_t first) 541 { 542 XSAFE_TRANS(first, src->nLength, false); 543 ssize_t length = src->nLength - first; 544 if (length <= 0) 545 return true; 546 547 XSAFE_TRANS(pos, nLength, false); 548 if (!cap_grow(length)) 549 return false; 550 551 ssize_t count = nLength - pos; 552 if (count > 0) 553 xmove(&pData[pos+length], &pData[pos], count); 554 xmove(&pData[pos], &src->pData[first], length); 555 nLength += length; 556 557 return true; 558 } 559 insert(ssize_t pos,const LSPString * src,ssize_t first,ssize_t last)560 bool LSPString::insert(ssize_t pos, const LSPString *src, ssize_t first, ssize_t last) 561 { 562 XSAFE_TRANS(first, src->nLength, false); 563 XSAFE_TRANS(last, src->nLength, false); 564 ssize_t length = last - first; 565 if (length <= 0) 566 return true; 567 568 XSAFE_TRANS(pos, nLength, false); 569 if (!cap_grow(length)) 570 return false; 571 572 ssize_t count = nLength - pos; 573 if (count > 0) 574 xmove(&pData[pos+length], &pData[pos], count); 575 xmove(&pData[pos], &src->pData[first], length); 576 nLength += length; 577 578 return true; 579 } 580 append(char ch)581 bool LSPString::append(char ch) 582 { 583 if (!cap_grow(1)) 584 return false; 585 pData[nLength++] = uint8_t(ch); 586 return true; 587 } 588 append(lsp_wchar_t ch)589 bool LSPString::append(lsp_wchar_t ch) 590 { 591 if (!cap_grow(1)) 592 return false; 593 pData[nLength++] = ch; 594 return true; 595 } 596 append(lsp_swchar_t ch)597 bool LSPString::append(lsp_swchar_t ch) 598 { 599 if (!cap_grow(1)) 600 return false; 601 pData[nLength++] = ch; 602 return true; 603 } 604 append(const lsp_wchar_t * arr,size_t n)605 bool LSPString::append(const lsp_wchar_t *arr, size_t n) 606 { 607 if (!cap_grow(n)) 608 return false; 609 xmove(&pData[nLength], arr, n); 610 nLength += n; 611 return true; 612 } 613 append_ascii(const char * arr,size_t n)614 bool LSPString::append_ascii(const char *arr, size_t n) 615 { 616 if (!cap_grow(n)) 617 return false; 618 acopy(&pData[nLength], arr, n); 619 nLength += n; 620 return true; 621 } 622 append_utf8(const char * arr,size_t n)623 bool LSPString::append_utf8(const char *arr, size_t n) 624 { 625 if (nLength <= 0) 626 return set_utf8(arr, n); 627 628 LSPString tmp; 629 if (!tmp.set_utf8(arr, n)) 630 return false; 631 return append(&tmp); 632 } 633 append(const LSPString * src)634 bool LSPString::append(const LSPString *src) 635 { 636 if (src->nLength <= 0) 637 return true; 638 if (!cap_grow(src->nLength)) 639 return false; 640 xmove(&pData[nLength], src->pData, src->nLength); 641 nLength += src->nLength; 642 return true; 643 } 644 append(const LSPString * src,ssize_t first)645 bool LSPString::append(const LSPString *src, ssize_t first) 646 { 647 XSAFE_TRANS(first, src->nLength, false); 648 ssize_t length = src->nLength - first; 649 if (length <= 0) 650 return true; 651 652 if (!cap_grow(length)) 653 return false; 654 xmove(&pData[nLength], &src->pData[first], length); 655 nLength += length; 656 return true; 657 } 658 append(const LSPString * src,ssize_t first,ssize_t last)659 bool LSPString::append(const LSPString *src, ssize_t first, ssize_t last) 660 { 661 XSAFE_TRANS(first, src->nLength, false); 662 XSAFE_TRANS(last, src->nLength, false); 663 ssize_t length = last - first; 664 if (length <= 0) 665 return true; 666 667 if (!cap_grow(length)) 668 return false; 669 xmove(&pData[nLength], &src->pData[first], length); 670 nLength += length; 671 return true; 672 } 673 prepend(lsp_wchar_t ch)674 bool LSPString::prepend(lsp_wchar_t ch) 675 { 676 if (!cap_grow(1)) 677 return false; 678 if (nLength > 0) 679 xmove(&pData[1], pData, nLength); 680 pData[0] = ch; 681 nLength ++; 682 return true; 683 } 684 prepend(const lsp_wchar_t * arr,size_t n)685 bool LSPString::prepend(const lsp_wchar_t *arr, size_t n) 686 { 687 if (n <= 0) 688 return true; 689 if (!cap_grow(n)) 690 return false; 691 if (nLength > 0) 692 xmove(&pData[n], pData, nLength); 693 xmove(pData, arr, n); 694 nLength += n; 695 return true; 696 } 697 prepend_ascii(const char * arr,size_t n)698 bool LSPString::prepend_ascii(const char *arr, size_t n) 699 { 700 if (n <= 0) 701 return true; 702 if (!cap_grow(n)) 703 return false; 704 if (nLength > 0) 705 xmove(&pData[n], pData, nLength); 706 acopy(pData, arr, n); 707 nLength += n; 708 return true; 709 } 710 prepend_utf8(const char * arr,size_t n)711 bool LSPString::prepend_utf8(const char *arr, size_t n) 712 { 713 if (nLength <= 0) 714 return set_utf8(arr, n); 715 716 LSPString tmp; 717 if (!tmp.set_utf8(arr, n)) 718 return false; 719 return prepend(&tmp); 720 } 721 prepend(const LSPString * src)722 bool LSPString::prepend(const LSPString *src) 723 { 724 if (src->nLength <= 0) 725 return true; 726 if (!cap_grow(src->nLength)) 727 return false; 728 if (nLength > 0) 729 xmove(&pData[src->nLength], pData, nLength); 730 xmove(pData, src->pData, src->nLength); 731 nLength += src->nLength; 732 return true; 733 } 734 prepend(const LSPString * src,ssize_t first)735 bool LSPString::prepend(const LSPString *src, ssize_t first) 736 { 737 XSAFE_TRANS(first, src->nLength, false); 738 ssize_t length = src->nLength - first; 739 if (length <= 0) 740 return true; 741 742 if (!cap_grow(length)) 743 return false; 744 if (nLength > 0) 745 xmove(&pData[length], pData, nLength); 746 xmove(pData, &src->pData[first], length); 747 nLength += length; 748 return true; 749 } 750 prepend(const LSPString * src,ssize_t first,ssize_t last)751 bool LSPString::prepend(const LSPString *src, ssize_t first, ssize_t last) 752 { 753 XSAFE_TRANS(first, src->nLength, false); 754 XSAFE_TRANS(last, src->nLength, false); 755 ssize_t length = last - first; 756 if (length <= 0) 757 return true; 758 759 if (!cap_grow(length)) 760 return false; 761 if (nLength > 0) 762 xmove(&pData[length], pData, nLength); 763 xmove(pData, &src->pData[first], length); 764 nLength += length; 765 return true; 766 } 767 ends_with(lsp_wchar_t ch) const768 bool LSPString::ends_with(lsp_wchar_t ch) const 769 { 770 return (nLength > 0) ? pData[nLength-1] == ch : false; 771 } 772 ends_with_nocase(lsp_wchar_t ch) const773 bool LSPString::ends_with_nocase(lsp_wchar_t ch) const 774 { 775 if (nLength <= 0) 776 return false; 777 return towlower(pData[nLength-1]) == towlower(ch); 778 } 779 ends_with(const LSPString * src) const780 bool LSPString::ends_with(const LSPString *src) const 781 { 782 if (src->nLength <= 0) 783 return true; 784 785 ssize_t offset = nLength - src->nLength; 786 if (offset < 0) 787 return false; 788 789 return xcmp(&pData[offset], src->pData, src->nLength) == 0; 790 } 791 ends_with_nocase(const LSPString * src) const792 bool LSPString::ends_with_nocase(const LSPString *src) const 793 { 794 if (src->nLength <= 0) 795 return true; 796 797 ssize_t offset = nLength - src->nLength; 798 if (offset < 0) 799 return false; 800 801 return xcasecmp(&pData[offset], src->pData, src->nLength) == 0; 802 } 803 starts_with(lsp_wchar_t ch) const804 bool LSPString::starts_with(lsp_wchar_t ch) const 805 { 806 return (nLength > 0) ? pData[0] == ch : false; 807 } 808 starts_with(lsp_wchar_t ch,size_t offset) const809 bool LSPString::starts_with(lsp_wchar_t ch, size_t offset) const 810 { 811 return (offset < nLength) ? pData[offset] == ch : false; 812 } 813 starts_with_nocase(lsp_wchar_t ch) const814 bool LSPString::starts_with_nocase(lsp_wchar_t ch) const 815 { 816 if (nLength <= 0) 817 return false; 818 return towlower(pData[0]) == towlower(ch); 819 } 820 starts_with_nocase(lsp_wchar_t ch,size_t offset) const821 bool LSPString::starts_with_nocase(lsp_wchar_t ch, size_t offset) const 822 { 823 if (offset < nLength) 824 return false; 825 return towlower(pData[offset]) == towlower(ch); 826 } 827 starts_with(const LSPString * src) const828 bool LSPString::starts_with(const LSPString *src) const 829 { 830 if (src->nLength <= 0) 831 return true; 832 833 if (nLength < src->nLength) 834 return false; 835 836 return xcasecmp(pData, src->pData, src->nLength) == 0; 837 } 838 starts_with_ascii(const char * str) const839 bool LSPString::starts_with_ascii(const char *str) const 840 { 841 for (size_t i=0, n=nLength; (i < n); ++i) 842 { 843 lsp_wchar_t c = uint8_t(*(str++)); 844 if (c == 0) 845 return true; 846 else if (c != pData[i]) 847 return false; 848 } 849 return (*str == '\0'); 850 } 851 starts_with(const LSPString * src,size_t offset) const852 bool LSPString::starts_with(const LSPString *src, size_t offset) const 853 { 854 if (src->nLength <= 0) 855 return true; 856 857 if (nLength < (src->nLength + offset)) 858 return false; 859 860 return xcasecmp(&pData[offset], src->pData, src->nLength) == 0; 861 } 862 starts_with_ascii(const char * str,size_t offset) const863 bool LSPString::starts_with_ascii(const char *str, size_t offset) const 864 { 865 for (size_t i=offset, n=nLength; (i < n); ++i) 866 { 867 lsp_wchar_t c = uint8_t(*(str++)); 868 if (c == 0) 869 return true; 870 else if (c != pData[i]) 871 return false; 872 } 873 return (*str == '\0'); 874 } 875 starts_with_nocase(const LSPString * src) const876 bool LSPString::starts_with_nocase(const LSPString *src) const 877 { 878 if (src->nLength <= 0) 879 return true; 880 881 if (nLength < src->nLength) 882 return false; 883 884 return xcasecmp(pData, src->pData, src->nLength) == 0; 885 } 886 starts_with_nocase(const LSPString * src,size_t offset) const887 bool LSPString::starts_with_nocase(const LSPString *src, size_t offset) const 888 { 889 if (src->nLength <= 0) 890 return true; 891 892 if (nLength < (offset + src->nLength)) 893 return false; 894 895 return xcasecmp(&pData[offset], src->pData, src->nLength) == 0; 896 } 897 starts_with_ascii_nocase(const char * str) const898 bool LSPString::starts_with_ascii_nocase(const char *str) const 899 { 900 for (size_t i=0, n=nLength; (i < n); ++i) 901 { 902 lsp_wchar_t c = uint8_t(*(str++)); 903 if (c == 0) 904 return true; 905 else if (towlower(c) != towlower(pData[i])) 906 return false; 907 } 908 return (*str == '\0'); 909 } 910 starts_with_ascii_nocase(const char * str,size_t offset) const911 bool LSPString::starts_with_ascii_nocase(const char *str, size_t offset) const 912 { 913 for (size_t i=offset, n=nLength; (i < n); ++i) 914 { 915 lsp_wchar_t c = uint8_t(*(str++)); 916 if (c == 0) 917 return true; 918 else if (towlower(c) != towlower(pData[i])) 919 return false; 920 } 921 return (*str == '\0'); 922 } 923 remove()924 bool LSPString::remove() 925 { 926 drop_temp(); 927 nLength = 0; 928 return true; 929 } 930 remove(ssize_t first)931 bool LSPString::remove(ssize_t first) 932 { 933 XSAFE_TRANS(first, nLength, false); 934 nLength = first; 935 return true; 936 } 937 remove(ssize_t first,ssize_t last)938 bool LSPString::remove(ssize_t first, ssize_t last) 939 { 940 XSAFE_TRANS(first, nLength, false); 941 XSAFE_TRANS(last, nLength, false); 942 ssize_t length = last - first; 943 if (length <= 0) 944 return true; 945 946 ssize_t count = nLength - last; 947 if (count > 0) 948 xmove(&pData[first], &pData[last], count); 949 950 nLength -= length; 951 return true; 952 } 953 remove_last()954 bool LSPString::remove_last() 955 { 956 if (nLength <= 0) 957 return false; 958 --nLength; 959 return true; 960 } 961 reverse()962 void LSPString::reverse() 963 { 964 drop_temp(); 965 966 size_t n = (nLength >> 1); 967 lsp_wchar_t *h = pData, *t = &pData[nLength]; 968 while (n--) 969 { 970 lsp_wchar_t c = *h; 971 *(h++) = *(--t); 972 *t = c; 973 } 974 } 975 shuffle()976 void LSPString::shuffle() 977 { 978 if (nLength < 2) 979 return; 980 981 size_t n = nLength * 2; 982 size_t idx1 = rand() % nLength, idx2; 983 984 while (n--) 985 { 986 // Generate random indexes 987 idx1 = (idx1 + rand()) % nLength; 988 idx2 = (idx1 + rand()) % nLength; 989 if (idx1 == idx2) 990 continue; 991 992 // Swap characters 993 lsp_wchar_t c = pData[idx1]; 994 pData[idx1] = pData[idx2]; 995 pData[idx2] = c; 996 } 997 } 998 replace(ssize_t pos,lsp_wchar_t ch)999 bool LSPString::replace(ssize_t pos, lsp_wchar_t ch) 1000 { 1001 XSAFE_TRANS(pos, nLength, false); 1002 1003 if (size_t(pos) < nLength) 1004 { 1005 pData[pos] = ch; 1006 nLength = pos; 1007 1008 return true; 1009 } 1010 1011 // Append at the tail 1012 return append(ch); 1013 } 1014 replace(ssize_t pos,const lsp_wchar_t * arr,size_t n)1015 bool LSPString::replace(ssize_t pos, const lsp_wchar_t *arr, size_t n) 1016 { 1017 XSAFE_TRANS(pos, nLength, false); 1018 1019 if (!cap_reserve(pos + n)) 1020 return false; 1021 1022 xmove(&pData[pos], arr, n); 1023 nLength = pos + n; 1024 return true; 1025 } 1026 replace(ssize_t pos,const LSPString * src)1027 bool LSPString::replace(ssize_t pos, const LSPString *src) 1028 { 1029 XSAFE_TRANS(pos, nLength, false); 1030 1031 if (!cap_reserve(pos + src->nLength)) 1032 return false; 1033 1034 xmove(&pData[pos], src->pData, src->nLength); 1035 nLength = pos + src->nLength; 1036 return true; 1037 } 1038 replace(ssize_t pos,const LSPString * src,ssize_t first)1039 bool LSPString::replace(ssize_t pos, const LSPString *src, ssize_t first) 1040 { 1041 XSAFE_TRANS(pos, nLength, false); 1042 XSAFE_TRANS(first, src->nLength, false); 1043 ssize_t length = src->nLength - first; 1044 1045 if (length > 0) 1046 { 1047 if (!cap_reserve(pos + length)) 1048 return false; 1049 1050 xmove(&pData[pos], &src->pData[first], length); 1051 } 1052 nLength = pos + length; 1053 return true; 1054 } 1055 replace(ssize_t pos,const LSPString * src,ssize_t first,ssize_t last)1056 bool LSPString::replace(ssize_t pos, const LSPString *src, ssize_t first, ssize_t last) 1057 { 1058 XSAFE_TRANS(pos, nLength, false); 1059 XSAFE_TRANS(first, src->nLength, false); 1060 ssize_t length = src->nLength - first; 1061 1062 if (!cap_reserve(pos + length)) 1063 return false; 1064 1065 xmove(&pData[pos], &src->pData[first], length); 1066 nLength = pos + length; 1067 return true; 1068 } 1069 replace(ssize_t first,ssize_t last,lsp_wchar_t ch)1070 bool LSPString::replace(ssize_t first, ssize_t last, lsp_wchar_t ch) 1071 { 1072 XSAFE_TRANS(first, nLength, false); 1073 XSAFE_TRANS(last, nLength, false); 1074 ssize_t count = last - first; 1075 if (count < 0) 1076 count = 0; 1077 1078 if (!cap_reserve(nLength - count + 1)) 1079 return false; 1080 1081 ssize_t tail = nLength - first - count; 1082 if (tail > 0) 1083 xmove(&pData[first + 1], &pData[tail], nLength - tail); 1084 pData[first] = ch; 1085 1086 nLength = nLength - count + 1; 1087 return true; 1088 } 1089 replace(ssize_t first,ssize_t last,const lsp_wchar_t * arr,size_t n)1090 bool LSPString::replace(ssize_t first, ssize_t last, const lsp_wchar_t *arr, size_t n) 1091 { 1092 XSAFE_TRANS(first, nLength, false); 1093 XSAFE_TRANS(last, nLength, false); 1094 ssize_t count = last - first; 1095 if (count < 0) 1096 count = 0; 1097 1098 if (!cap_reserve(nLength - count + n)) 1099 return false; 1100 1101 ssize_t tail = nLength - first - count; 1102 if (tail > 0) 1103 xmove(&pData[first + n], &pData[tail], nLength - tail); 1104 if (n > 0) 1105 xmove(&pData[first], arr, n); 1106 nLength = nLength - count + n; 1107 return true; 1108 } 1109 replace(ssize_t first,ssize_t last,const LSPString * src)1110 bool LSPString::replace(ssize_t first, ssize_t last, const LSPString *src) 1111 { 1112 XSAFE_TRANS(first, nLength, false); 1113 XSAFE_TRANS(last, nLength, false); 1114 ssize_t count = last - first; 1115 if (count < 0) 1116 count = 0; 1117 1118 if (!cap_reserve(nLength - count + src->nLength)) 1119 return false; 1120 1121 ssize_t tail = nLength - first - count; 1122 if (tail > 0) 1123 xmove(&pData[first + src->nLength], &pData[tail], nLength - tail); 1124 if (src->nLength > 0) 1125 xmove(&pData[first], src->pData, src->nLength); 1126 nLength = nLength - count + src->nLength; 1127 return true; 1128 } 1129 replace(ssize_t first,ssize_t last,const LSPString * src,ssize_t sfirst)1130 bool LSPString::replace(ssize_t first, ssize_t last, const LSPString *src, ssize_t sfirst) 1131 { 1132 XSAFE_TRANS(first, nLength, false); 1133 XSAFE_TRANS(last, nLength, false); 1134 ssize_t count = last - first; 1135 if (count < 0) 1136 count = 0; 1137 1138 XSAFE_TRANS(sfirst, src->nLength, false); 1139 ssize_t scount = src->nLength - sfirst; 1140 1141 if (!cap_reserve(nLength - count + scount)) 1142 return false; 1143 1144 ssize_t tail = nLength - first - count; 1145 if (tail > 0) 1146 xmove(&pData[first + scount], &pData[tail], nLength - tail); 1147 if (scount > 0) 1148 xmove(&pData[first], &src->pData[sfirst], scount); 1149 nLength = nLength - count + scount; 1150 return true; 1151 } 1152 replace(ssize_t first,ssize_t last,const LSPString * src,ssize_t sfirst,ssize_t slast)1153 bool LSPString::replace(ssize_t first, ssize_t last, const LSPString *src, ssize_t sfirst, ssize_t slast) 1154 { 1155 XSAFE_TRANS(first, nLength, false); 1156 XSAFE_TRANS(last, nLength, false); 1157 ssize_t count = last - first; 1158 if (count < 0) 1159 count = 0; 1160 1161 XSAFE_TRANS(sfirst, src->nLength, false); 1162 XSAFE_TRANS(slast, src->nLength, false); 1163 ssize_t scount = slast - sfirst; 1164 if (scount < 0) 1165 scount = 0; 1166 1167 if (!cap_reserve(nLength - count + scount)) 1168 return false; 1169 1170 ssize_t tail = nLength - first - count; 1171 if (tail > 0) 1172 xmove(&pData[first + scount], &pData[tail], nLength - tail); 1173 if (scount > 0) 1174 xmove(&pData[first], &src->pData[sfirst], scount); 1175 nLength = nLength - count + scount; 1176 return true; 1177 } 1178 replace_all(lsp_wchar_t ch,lsp_wchar_t rep)1179 size_t LSPString::replace_all(lsp_wchar_t ch, lsp_wchar_t rep) 1180 { 1181 size_t n = 0; 1182 for (size_t i=0; i<nLength; ++i) 1183 { 1184 if (pData[i] == ch) 1185 { 1186 pData[i] = rep; 1187 ++n; 1188 } 1189 } 1190 return n; 1191 } 1192 index_of(ssize_t start,const LSPString * str) const1193 ssize_t LSPString::index_of(ssize_t start, const LSPString *str) const 1194 { 1195 XSAFE_TRANS(start, nLength, -1); 1196 if (str->nLength <= 0) 1197 return start; 1198 1199 ssize_t last = nLength - str->nLength; 1200 while (start < last) 1201 { 1202 if (xcmp(&pData[start], str->pData, str->nLength) == 0) 1203 return start; 1204 start ++; 1205 } 1206 return -1; 1207 } 1208 index_of(const LSPString * str) const1209 ssize_t LSPString::index_of(const LSPString *str) const 1210 { 1211 if (str->nLength <= 0) 1212 return 0; 1213 1214 ssize_t start = 0, last = nLength - str->nLength; 1215 while (start < last) 1216 { 1217 if (xcmp(&pData[start], str->pData, str->nLength) == 0) 1218 return start; 1219 start ++; 1220 } 1221 return -1; 1222 } 1223 index_of(ssize_t start,lsp_wchar_t ch) const1224 ssize_t LSPString::index_of(ssize_t start, lsp_wchar_t ch) const 1225 { 1226 XSAFE_TRANS(start, nLength, -1); 1227 1228 ssize_t length = nLength; 1229 while (start < length) 1230 { 1231 if (pData[start] == ch) 1232 return start; 1233 start ++; 1234 } 1235 1236 return -1; 1237 } 1238 index_of(lsp_wchar_t ch) const1239 ssize_t LSPString::index_of(lsp_wchar_t ch) const 1240 { 1241 for (size_t start = 0; start < nLength; ++start) 1242 { 1243 if (pData[start] == ch) 1244 return start; 1245 } 1246 return -1; 1247 } 1248 rindex_of(ssize_t start,const LSPString * str) const1249 ssize_t LSPString::rindex_of(ssize_t start, const LSPString *str) const 1250 { 1251 XSAFE_ITRANS(start, nLength, -1); 1252 if (str->nLength <= 0) 1253 return start; 1254 1255 start -= str->nLength; 1256 while (start >= 0) 1257 { 1258 if (xcmp(&pData[start], str->pData, str->nLength) == 0) 1259 return start; 1260 start --; 1261 } 1262 return -1; 1263 } 1264 rindex_of(const LSPString * str) const1265 ssize_t LSPString::rindex_of(const LSPString *str) const 1266 { 1267 if (str->nLength <= 0) 1268 return 0; 1269 1270 ssize_t start = nLength - str->nLength - 1; 1271 while (start >= 0) 1272 { 1273 if (xcmp(&pData[start], str->pData, str->nLength) == 0) 1274 return start; 1275 start --; 1276 } 1277 return -1; 1278 } 1279 rindex_of(ssize_t start,lsp_wchar_t ch) const1280 ssize_t LSPString::rindex_of(ssize_t start, lsp_wchar_t ch) const 1281 { 1282 XSAFE_ITRANS(start, nLength, -1); 1283 1284 while (start >= 0) 1285 { 1286 if (pData[start] == ch) 1287 return start; 1288 start --; 1289 } 1290 1291 return -1; 1292 } 1293 rindex_of(lsp_wchar_t ch) const1294 ssize_t LSPString::rindex_of(lsp_wchar_t ch) const 1295 { 1296 for (ssize_t start=nLength-1; start >= 0; --start) 1297 { 1298 if (pData[start] == ch) 1299 return start; 1300 } 1301 return -1; 1302 } 1303 substring(ssize_t first) const1304 LSPString *LSPString::substring(ssize_t first) const 1305 { 1306 XSAFE_TRANS(first, nLength, NULL); 1307 ssize_t length = nLength - first; 1308 1309 LSPString *s = new LSPString(); 1310 if (s == NULL) 1311 return s; 1312 1313 s->nLength = length; 1314 s->nCapacity = length; 1315 1316 if (length > 0) 1317 { 1318 s->pData = xmalloc(length); 1319 if (s->pData == NULL) 1320 { 1321 delete s; 1322 return NULL; 1323 } 1324 1325 xmove(s->pData, &pData[first], length); 1326 } 1327 else 1328 s->pData = NULL; 1329 1330 return s; 1331 } 1332 substring(ssize_t first,ssize_t last) const1333 LSPString *LSPString::substring(ssize_t first, ssize_t last) const 1334 { 1335 XSAFE_TRANS(first, nLength, NULL); 1336 XSAFE_TRANS(last, nLength, NULL); 1337 ssize_t length = last - first; 1338 if (length < 0) 1339 length = 0; 1340 1341 LSPString *s = new LSPString(); 1342 if (s == NULL) 1343 return s; 1344 1345 s->nLength = length; 1346 s->nCapacity = length; 1347 1348 if (length > 0) 1349 { 1350 s->pData = xmalloc(length); 1351 if (s->pData == NULL) 1352 { 1353 delete s; 1354 return NULL; 1355 } 1356 1357 xmove(s->pData, &pData[first], length); 1358 } 1359 else 1360 s->pData = NULL; 1361 1362 return s; 1363 } 1364 compare_to(const lsp_wchar_t * src) const1365 int LSPString::compare_to(const lsp_wchar_t *src) const 1366 { 1367 return compare_to(src, xlen(src)); 1368 } 1369 compare_to(const lsp_wchar_t * src,size_t len) const1370 int LSPString::compare_to(const lsp_wchar_t *src, size_t len) const 1371 { 1372 ssize_t n = (nLength > len) ? len : nLength; 1373 const lsp_wchar_t *a = pData, *b = src; 1374 1375 while (n--) 1376 { 1377 int retval = int(*(a++)) - int(*(b++)); 1378 if (retval != 0) 1379 return retval; 1380 } 1381 1382 if (a < &pData[nLength]) 1383 return int(*a); 1384 else if (b < &src[len]) 1385 return -int(*b); 1386 1387 return 0; 1388 } 1389 compare_to_ascii(const char * src) const1390 int LSPString::compare_to_ascii(const char *src) const 1391 { 1392 size_t i=0; 1393 for ( ; i<nLength; ++i) 1394 { 1395 if (src[i] == '\0') 1396 return pData[i]; 1397 int retval = int(pData[i]) - uint8_t(src[i]); 1398 if (retval != 0) 1399 return retval; 1400 } 1401 return -int(uint8_t(src[i])); 1402 } 1403 compare_to_utf8(const char * src) const1404 int LSPString::compare_to_utf8(const char *src) const 1405 { 1406 LSPString tmp; 1407 return (tmp.set_utf8(src)) ? compare_to(&tmp) : 0; 1408 } 1409 compare_to_ascii_nocase(const char * src) const1410 int LSPString::compare_to_ascii_nocase(const char *src) const 1411 { 1412 size_t i=0; 1413 for ( ; i<nLength; ++i) 1414 { 1415 if (src[i] == '\0') 1416 return pData[i]; 1417 int retval = int(::towlower(pData[i])) - ::towlower(uint8_t(src[i])); 1418 if (retval != 0) 1419 return retval; 1420 } 1421 return -int(uint8_t(src[i])); 1422 } 1423 compare_to_nocase(const lsp_wchar_t * src,size_t len) const1424 int LSPString::compare_to_nocase(const lsp_wchar_t *src, size_t len) const 1425 { 1426 ssize_t n = (nLength > len) ? len : nLength; 1427 const lsp_wchar_t *a = pData, *b = src; 1428 1429 while (n--) 1430 { 1431 int retval = int(::towlower(*(a++))) - int(::towlower(*(b++))); 1432 if (retval != 0) 1433 return retval; 1434 } 1435 1436 if (a < &pData[nLength]) 1437 return int(*a); 1438 else if (b < &src[len]) 1439 return -int(*b); 1440 1441 return 0; 1442 } 1443 compare_to_nocase(const lsp_wchar_t * src) const1444 int LSPString::compare_to_nocase(const lsp_wchar_t *src) const 1445 { 1446 return compare_to_nocase(src, xlen(src)); 1447 } 1448 compare_to_utf8_nocase(const char * src) const1449 int LSPString::compare_to_utf8_nocase(const char *src) const 1450 { 1451 LSPString tmp; 1452 return (tmp.set_utf8(src)) ? compare_to_nocase(&tmp) : 0; 1453 } 1454 tolower()1455 size_t LSPString::tolower() 1456 { 1457 for (size_t i=0; i<nLength; ++i) 1458 pData[i] = towlower(pData[i]); 1459 return nLength; 1460 } 1461 tolower(ssize_t first)1462 size_t LSPString::tolower(ssize_t first) 1463 { 1464 XSAFE_TRANS(first, nLength, 0); 1465 ssize_t n = nLength - first; 1466 lsp_wchar_t *ptr = &pData[first]; 1467 for (ssize_t i=0; i<n; ++i) 1468 ptr[i] = towlower(ptr[i]); 1469 return (n >= 0) ? n : 0; 1470 } 1471 tolower(ssize_t first,ssize_t last)1472 size_t LSPString::tolower(ssize_t first, ssize_t last) 1473 { 1474 XSAFE_TRANS(first, nLength, 0); 1475 XSAFE_TRANS(last, nLength, 0); 1476 if (last < first) 1477 { 1478 ssize_t tmp = last; 1479 last = first; 1480 first = tmp; 1481 } 1482 ssize_t n = last - first; 1483 lsp_wchar_t *ptr = &pData[first]; 1484 for (; first < last; ++first) 1485 ptr[first] = towlower(ptr[first]); 1486 return n; 1487 } 1488 toupper()1489 size_t LSPString::toupper() 1490 { 1491 for (size_t i=0; i<nLength; ++i) 1492 pData[i] = towupper(pData[i]); 1493 return nLength; 1494 } 1495 toupper(ssize_t first)1496 size_t LSPString::toupper(ssize_t first) 1497 { 1498 XSAFE_TRANS(first, nLength, 0); 1499 ssize_t n = nLength - first; 1500 lsp_wchar_t *ptr = &pData[first]; 1501 for (ssize_t i=0; i<n; ++i) 1502 ptr[i] = towupper(ptr[i]); 1503 return (n >= 0) ? n : 0; 1504 } 1505 toupper(ssize_t first,ssize_t last)1506 size_t LSPString::toupper(ssize_t first, ssize_t last) 1507 { 1508 XSAFE_TRANS(first, nLength, 0); 1509 XSAFE_TRANS(last, nLength, 0); 1510 if (last < first) 1511 { 1512 ssize_t tmp = last; 1513 last = first; 1514 first = tmp; 1515 } 1516 ssize_t n = last - first; 1517 lsp_wchar_t *ptr = &pData[first]; 1518 for (; first < last; ++first) 1519 ptr[first] = towupper(ptr[first]); 1520 return n; 1521 } 1522 equals(const lsp_wchar_t * src,size_t len) const1523 bool LSPString::equals(const lsp_wchar_t *src, size_t len) const 1524 { 1525 if (nLength != len) 1526 return false; 1527 if (nLength <= 0) 1528 return true; 1529 1530 return xcmp(pData, src, nLength) == 0; 1531 } 1532 equals(const lsp_wchar_t * src) const1533 bool LSPString::equals(const lsp_wchar_t *src) const 1534 { 1535 return equals(src, xlen(src)); 1536 } 1537 equals_nocase(const lsp_wchar_t * src,size_t len) const1538 bool LSPString::equals_nocase(const lsp_wchar_t *src, size_t len) const 1539 { 1540 if (nLength != len) 1541 return false; 1542 1543 const lsp_wchar_t *a = pData, *b = src; 1544 for (size_t i=nLength; i>0; --i) 1545 { 1546 if (towlower(*(a++)) != towlower(*(b++))) 1547 return false; 1548 } 1549 1550 return true; 1551 } 1552 equals_nocase(const lsp_wchar_t * src) const1553 bool LSPString::equals_nocase(const lsp_wchar_t *src) const 1554 { 1555 return equals_nocase(src, xlen(src)); 1556 } 1557 set_utf8(const char * s,size_t n)1558 bool LSPString::set_utf8(const char *s, size_t n) 1559 { 1560 LSPString tmp; 1561 lsp_wchar_t ch; 1562 1563 while (lsp_utf32_t(ch = read_utf8_streaming(&s, &n, true)) != LSP_UTF32_EOF) 1564 { 1565 // Append code point 1566 if (!tmp.append(ch)) 1567 return false; 1568 } 1569 if (n > 0) 1570 return false; 1571 1572 tmp.swap(this); 1573 return true; 1574 } 1575 set_utf16(const lsp_utf16_t * s)1576 bool LSPString::set_utf16(const lsp_utf16_t *s) 1577 { 1578 size_t len = 0; 1579 while (s[len] != 0) 1580 ++len; 1581 1582 return set_utf16(s, len); 1583 } 1584 set_utf16(const lsp_utf16_t * s,size_t n)1585 bool LSPString::set_utf16(const lsp_utf16_t *s, size_t n) 1586 { 1587 LSPString tmp; 1588 lsp_wchar_t ch; 1589 1590 while (lsp_utf32_t(ch = read_utf16_streaming(&s, &n, true)) != LSP_UTF32_EOF) 1591 { 1592 // Append code point 1593 if (!tmp.append(ch)) 1594 return false; 1595 } 1596 if (n > 0) 1597 return false; 1598 1599 tmp.swap(this); 1600 return true; 1601 } 1602 1603 #if defined(PLATFORM_WINDOWS) set_native(const char * s,size_t n,const char * charset)1604 bool LSPString::set_native(const char *s, size_t n, const char *charset) 1605 { 1606 if (s == NULL) 1607 return false; 1608 else if (n == 0) 1609 { 1610 nLength = 0; 1611 return true; 1612 } 1613 1614 // Get codepage 1615 ssize_t cp = codepage_from_name(charset); 1616 if (cp < 0) 1617 return false; 1618 1619 // Estimate size of string in memory 1620 ssize_t slen = multibyte_to_widechar(cp, const_cast<CHAR *>(s), &n, NULL, NULL); 1621 if (slen <= 0) 1622 return false; 1623 1624 // Perform native -> utf-16 encoding 1625 WCHAR *buf = reinterpret_cast<WCHAR *>(::malloc(slen * sizeof(WCHAR))); 1626 if (buf == NULL) 1627 return false; 1628 1629 size_t bytes = slen; 1630 slen = multibyte_to_widechar(cp, const_cast<CHAR *>(s), &n, buf, &bytes); 1631 if (slen <= 0) 1632 { 1633 free(buf); 1634 return false; 1635 } 1636 1637 // Set encoded utf-16 values 1638 bool res = set_utf16(buf, slen >> 1); 1639 free(buf); 1640 1641 return res; 1642 } 1643 #else set_native(const char * s,size_t n,const char * charset)1644 bool LSPString::set_native(const char *s, size_t n, const char *charset) 1645 { 1646 if (s == NULL) 1647 return false; 1648 else if (n == 0) 1649 { 1650 nLength = 0; 1651 return true; 1652 } 1653 1654 char buf[BUF_SIZE]; 1655 LSPString temp; 1656 1657 // Open conversion 1658 iconv_t cd = init_iconv_to_wchar_t(charset); 1659 if (cd == iconv_t(-1)) 1660 return set_utf8(s, n); 1661 1662 size_t insize = (n < 0) ? strlen(s) : n; 1663 size_t outsize = BUF_SIZE; 1664 char *inbuf = const_cast<char *>(s); 1665 char *outbuf = buf; 1666 1667 while (insize > 0) 1668 { 1669 // Do the conversion 1670 size_t nconv = iconv(cd, &inbuf, &insize, &outbuf, &outsize); 1671 1672 if (nconv == (size_t) -1) 1673 { 1674 switch (errno) 1675 { 1676 case E2BIG: 1677 case EINVAL: 1678 break; 1679 default: 1680 iconv_close(cd); 1681 return false; 1682 } 1683 } 1684 1685 // Append set of converted characters to string 1686 ssize_t n_chars = (BUF_SIZE - outsize) / sizeof(lsp_wchar_t); 1687 if (n_chars > 0) 1688 { 1689 if (!temp.append(reinterpret_cast<lsp_wchar_t *>(&buf[0]), n_chars)) 1690 { 1691 iconv_close(cd); 1692 return false; 1693 } 1694 } 1695 1696 size_t right = n_chars * sizeof(lsp_wchar_t); 1697 ssize_t tail = (outsize - right) % sizeof(lsp_wchar_t); 1698 if (tail > 0) 1699 { 1700 // If there is a tail, copy it to the start of buffer 1701 ::memmove(buf, &buf[right], tail); 1702 outbuf = &buf[tail]; 1703 outsize = BUF_SIZE - tail; 1704 } 1705 else 1706 { 1707 // Otherwise just reset buffer's pointer 1708 outbuf = buf; 1709 outsize = BUF_SIZE; 1710 } 1711 } 1712 1713 // Close descriptor 1714 iconv_close(cd); 1715 take(&temp); 1716 return true; 1717 } 1718 #endif /* PLATFORM_WINDOWS */ 1719 set_ascii(const char * s,size_t n)1720 bool LSPString::set_ascii(const char *s, size_t n) 1721 { 1722 LSPString tmp; 1723 if (!tmp.reserve(n)) 1724 return false; 1725 1726 acopy(tmp.pData, s, n); 1727 take(&tmp); 1728 nLength = n; 1729 return true; 1730 } 1731 get_utf8(ssize_t first,ssize_t last) const1732 const char *LSPString::get_utf8(ssize_t first, ssize_t last) const 1733 { 1734 XSAFE_TRANS(first, nLength, NULL); 1735 XSAFE_TRANS(last, nLength, NULL); 1736 if (first >= last) 1737 return (last == first) ? "" : NULL; 1738 1739 if (pTemp != NULL) 1740 pTemp->nOffset = 0; 1741 1742 char temp[BUF_SIZE + 16]; 1743 char *th = temp, *tt = &temp[BUF_SIZE]; 1744 1745 for (ssize_t i=first; i<last; ++i) 1746 { 1747 lsp_wchar_t ch = pData[i]; 1748 write_utf8_codepoint(&th, ch); 1749 1750 if (th >= tt) 1751 { 1752 if (!append_temp(temp, th - temp)) 1753 return NULL; 1754 th = temp; 1755 } 1756 } 1757 1758 *(th++) = '\0'; 1759 if (!append_temp(temp, th - temp)) 1760 return NULL; 1761 1762 return pTemp->pData; 1763 } 1764 get_utf16(ssize_t first,ssize_t last) const1765 const lsp_utf16_t *LSPString::get_utf16(ssize_t first, ssize_t last) const 1766 { 1767 XSAFE_TRANS(first, nLength, NULL); 1768 XSAFE_TRANS(last, nLength, NULL); 1769 if (first >= last) 1770 return (last == first) ? &UTF16_NULL : NULL; 1771 1772 if (pTemp != NULL) 1773 pTemp->nOffset = 0; 1774 1775 lsp_utf16_t temp[BUF_SIZE + 8]; 1776 lsp_utf16_t *th = temp, *tt = &temp[BUF_SIZE]; 1777 1778 for (ssize_t i=first; i<last; ++i) 1779 { 1780 lsp_wchar_t ch = pData[i]; 1781 write_utf16_codepoint(&th, ch); 1782 1783 if (th >= tt) 1784 { 1785 if (!append_temp(reinterpret_cast<char *>(temp), (th - temp) * sizeof(lsp_utf16_t))) 1786 return NULL; 1787 th = temp; 1788 } 1789 } 1790 1791 *(th++) = '\0'; 1792 if (!append_temp(reinterpret_cast<char *>(temp), (th - temp) * sizeof(lsp_utf16_t))) 1793 return NULL; 1794 1795 return reinterpret_cast<lsp_utf16_t *>(pTemp->pData); 1796 } 1797 get_ascii(ssize_t first,ssize_t last) const1798 const char *LSPString::get_ascii(ssize_t first, ssize_t last) const 1799 { 1800 XSAFE_TRANS(first, nLength, NULL); 1801 XSAFE_TRANS(last, nLength, NULL); 1802 if (first >= last) 1803 return (last == first) ? "" : NULL; 1804 1805 if (!resize_temp(last - first + 1)) 1806 return NULL; 1807 1808 lsp_wchar_t *p = &pData[first]; 1809 char *dst = pTemp->pData; 1810 1811 for (; first < last; ++first) 1812 { 1813 lsp_wchar_t c = *(p++); 1814 *(dst++) = (c <= 0x7f) ? c : 0xff; 1815 } 1816 1817 *(dst++) = '\0'; 1818 pTemp->nOffset = dst - pTemp->pData; 1819 1820 return pTemp->pData; 1821 } 1822 1823 #if defined(PLATFORM_WINDOWS) get_native(ssize_t first,ssize_t last,const char * charset) const1824 const char *LSPString::get_native(ssize_t first, ssize_t last, const char *charset) const 1825 { 1826 XSAFE_TRANS(first, nLength, NULL); 1827 XSAFE_TRANS(last, nLength, NULL); 1828 ssize_t length = last - first; 1829 if (length <= 0) 1830 return (length == 0) ? "" : NULL; 1831 1832 // Get codepage 1833 ssize_t cp = codepage_from_name(charset); 1834 if (cp < 0) 1835 return NULL; 1836 1837 // Estimate number of bytes required 1838 lsp_utf16_t *buf = const_cast<lsp_utf16_t *>(get_utf16(first, last)); 1839 if (buf == NULL) 1840 return NULL; 1841 1842 // Drop temporary data because it is stored in buf variable and can not be reused 1843 pTemp->pData = NULL; 1844 pTemp->nLength = 0; 1845 pTemp->nOffset = 0; 1846 1847 size_t slen = length; 1848 size_t res = widechar_to_multibyte(cp, buf, &slen, NULL, NULL) + 4; // + terminating 0 1849 if ((res <= 0) || (!resize_temp(res))) 1850 { 1851 free(buf); 1852 return NULL; 1853 } 1854 1855 // We have enough space for saving data 1856 size_t n = res; 1857 res = widechar_to_multibyte(cp, buf, &slen, pTemp->pData, &n); 1858 if (res <= 0) 1859 { 1860 free(buf); 1861 return NULL; 1862 } 1863 1864 // Append terminating zero 1865 pTemp->pData[res++] = '\0'; 1866 pTemp->pData[res++] = '\0'; 1867 pTemp->pData[res++] = '\0'; 1868 pTemp->pData[res] = '\0'; 1869 1870 free(buf); 1871 return pTemp->pData; 1872 } 1873 #else get_native(ssize_t first,ssize_t last,const char * charset) const1874 const char *LSPString::get_native(ssize_t first, ssize_t last, const char *charset) const 1875 { 1876 XSAFE_TRANS(first, nLength, NULL); 1877 XSAFE_TRANS(last, nLength, NULL); 1878 if (first >= last) 1879 return (last == first) ? "" : NULL; 1880 1881 // Open conversion 1882 iconv_t cd = init_iconv_from_wchar_t(charset); 1883 if (cd == iconv_t(-1)) 1884 return get_utf8(first, last); 1885 1886 // Analyze temp 1887 size_t outsize = 0; 1888 char *outbuf = NULL; 1889 if (pTemp != NULL) 1890 { 1891 pTemp->nOffset = 0; 1892 outsize = pTemp->nLength; 1893 outbuf = pTemp->pData; 1894 } 1895 1896 size_t insize = (last - first) * sizeof(lsp_wchar_t); 1897 char *inbuf = reinterpret_cast<char *>(const_cast<lsp_wchar_t *>(&pData[first])); 1898 1899 while (insize > 0) 1900 { 1901 // Reserve space if there is not enough space 1902 if (outsize < 16) 1903 { 1904 // Try to grow the temprary buffer 1905 if (!grow_temp(BUF_SIZE)) 1906 { 1907 iconv_close(cd); 1908 return NULL; 1909 } 1910 1911 // Initialize location of buffers to store data 1912 outsize = pTemp->nLength - pTemp->nOffset; 1913 outbuf = &pTemp->pData[pTemp->nOffset]; 1914 } 1915 1916 // Do the conversion 1917 size_t nconv = iconv(cd, &inbuf, &insize, &outbuf, &outsize); 1918 if (nconv == (size_t) -1) 1919 { 1920 int err_code = errno; 1921 switch (err_code) 1922 { 1923 case E2BIG: 1924 case EINVAL: 1925 break; 1926 default: 1927 iconv_close (cd); 1928 return NULL; 1929 } 1930 } 1931 1932 // Update pointer 1933 pTemp->nOffset = pTemp->nLength - outsize; 1934 } 1935 1936 // Close the iconv descriptor 1937 iconv_close(cd); 1938 1939 // Append zeros at the end to make compatible with C-strings 1940 if (!append_temp("\x00\x00\x00\x00", 4)) 1941 return NULL; 1942 1943 return pTemp->pData; 1944 } 1945 #endif /* PLATFORM_WINDOWS */ 1946 match(const LSPString * s,size_t index) const1947 size_t LSPString::match(const LSPString *s, size_t index) const 1948 { 1949 if (index >= nLength) 1950 return 0; 1951 size_t i=0, n = lsp_min(s->nLength, nLength - index); 1952 1953 for (; i < n; ++i) 1954 { 1955 if (pData[i] != s->pData[i]) 1956 return i; 1957 } 1958 return i; 1959 } 1960 match_nocase(const LSPString * s,size_t index) const1961 size_t LSPString::match_nocase(const LSPString *s, size_t index) const 1962 { 1963 if (index >= nLength) 1964 return 0; 1965 size_t i=0, n = lsp_min(s->nLength, nLength - index); 1966 1967 for (; i < n; ++i) 1968 { 1969 if (towlower(pData[i]) != towlower(s->pData[i])) 1970 return i; 1971 } 1972 return i; 1973 } 1974 clone_utf8(size_t * bytes,ssize_t first,ssize_t last) const1975 char *LSPString::clone_utf8(size_t *bytes, ssize_t first, ssize_t last) const 1976 { 1977 const char *utf8 = get_utf8(first, last); 1978 size_t offset = (pTemp != NULL) ? pTemp->nOffset : 0; 1979 char *ptr = (utf8 != NULL) ? reinterpret_cast<char *>(lsp_memdup(utf8, offset)) : NULL; 1980 if (bytes != NULL) 1981 *bytes = (ptr != NULL) ? offset : 0; 1982 return ptr; 1983 } 1984 clone_utf16(size_t * bytes,ssize_t first,ssize_t last) const1985 lsp_utf16_t *LSPString::clone_utf16(size_t *bytes, ssize_t first, ssize_t last) const 1986 { 1987 const lsp_utf16_t *utf16 = get_utf16(first, last); 1988 size_t offset = (pTemp != NULL) ? pTemp->nOffset : 0; 1989 lsp_utf16_t *ptr = (utf16 != NULL) ? reinterpret_cast<lsp_utf16_t *>(lsp_memdup(utf16, offset)) : NULL; 1990 if (bytes != NULL) 1991 *bytes = (ptr != NULL) ? offset : 0; 1992 return ptr; 1993 } 1994 clone_ascii(size_t * bytes,ssize_t first,ssize_t last) const1995 char *LSPString::clone_ascii(size_t *bytes, ssize_t first, ssize_t last) const 1996 { 1997 const char *ascii = get_ascii(first, last); 1998 size_t offset = (pTemp != NULL) ? pTemp->nOffset : 0; 1999 char *ptr = (ascii != NULL) ? reinterpret_cast<char *>(lsp_memdup(ascii, offset)) : NULL; 2000 if (bytes != NULL) 2001 *bytes = (ptr != NULL) ? offset : 0; 2002 return ptr; 2003 } 2004 clone_native(size_t * bytes,ssize_t first,ssize_t last,const char * charset) const2005 char *LSPString::clone_native(size_t *bytes, ssize_t first, ssize_t last, const char *charset) const 2006 { 2007 const char *native = get_native(first, last, charset); 2008 size_t offset = (pTemp != NULL) ? pTemp->nOffset : 0; 2009 char *ptr = (native != NULL) ? reinterpret_cast<char *>(lsp_memdup(native, offset)) : NULL; 2010 if (bytes != NULL) 2011 *bytes = (ptr != NULL) ? offset : 0; 2012 return ptr; 2013 } 2014 append_temp(const char * p,size_t n) const2015 bool LSPString::append_temp(const char *p, size_t n) const 2016 { 2017 ssize_t free = (pTemp != NULL) ? pTemp->nLength - pTemp->nOffset : -1; 2018 2019 if (free < ssize_t(n)) 2020 { 2021 size_t resize = n + (n >> 1); 2022 if (pTemp != NULL) 2023 resize += pTemp->nLength; 2024 2025 if (!resize_temp(resize)) 2026 return false; 2027 } 2028 2029 memcpy(&pTemp->pData[pTemp->nOffset], p, n * sizeof(char)); 2030 pTemp->nOffset += n; 2031 2032 return true; 2033 } 2034 grow_temp(size_t n) const2035 bool LSPString::grow_temp(size_t n) const 2036 { 2037 if (pTemp == NULL) 2038 { 2039 pTemp = static_cast<buffer_t *>(malloc(sizeof(buffer_t))); 2040 if (pTemp == NULL) 2041 return false; 2042 pTemp->nLength = 0; 2043 pTemp->nOffset = 0; 2044 pTemp->pData = 0; 2045 } 2046 2047 char *xc = static_cast<char *>(realloc(pTemp->pData, (pTemp->nLength + n)*sizeof(char))); 2048 if (xc == NULL) 2049 return false; 2050 2051 pTemp->pData = xc; 2052 pTemp->nLength += n; 2053 return true; 2054 } 2055 resize_temp(size_t n) const2056 bool LSPString::resize_temp(size_t n) const 2057 { 2058 if (pTemp == NULL) 2059 { 2060 pTemp = static_cast<buffer_t *>(malloc(sizeof(buffer_t))); 2061 if (pTemp == NULL) 2062 return false; 2063 pTemp->nLength = 0; 2064 pTemp->nOffset = 0; 2065 pTemp->pData = 0; 2066 } 2067 2068 char *xc = static_cast<char *>(realloc(pTemp->pData, n*sizeof(char))); 2069 if (xc == NULL) 2070 return false; 2071 2072 pTemp->pData = xc; 2073 pTemp->nLength = n; 2074 return true; 2075 } 2076 count(lsp_wchar_t ch) const2077 size_t LSPString::count(lsp_wchar_t ch) const 2078 { 2079 size_t n = 0; 2080 for (size_t i=0; i<nLength; ++i) 2081 if (pData[i] == ch) 2082 ++n; 2083 return n; 2084 } 2085 count(lsp_wchar_t ch,ssize_t first) const2086 size_t LSPString::count(lsp_wchar_t ch, ssize_t first) const 2087 { 2088 XSAFE_TRANS(first, nLength, 0); 2089 2090 size_t n = 0; 2091 for (size_t i=first; i<nLength; ++i) 2092 if (pData[i] == ch) 2093 ++n; 2094 return n; 2095 } 2096 count(lsp_wchar_t ch,ssize_t first,ssize_t last) const2097 size_t LSPString::count(lsp_wchar_t ch, ssize_t first, ssize_t last) const 2098 { 2099 XSAFE_TRANS(first, nLength, 0); 2100 XSAFE_TRANS(last, nLength, 0); 2101 2102 size_t n = 0; 2103 if (first < last) 2104 { 2105 for (ssize_t i=first; i<last; ++i) 2106 if (pData[i] == ch) 2107 ++n; 2108 } 2109 else 2110 { 2111 for (ssize_t i=last; i<first; ++i) 2112 if (pData[i] == ch) 2113 ++n; 2114 } 2115 return n; 2116 } 2117 fmt_append_native(const char * fmt...)2118 bool LSPString::fmt_append_native(const char *fmt...) 2119 { 2120 LSPString tmp; 2121 va_list vl; 2122 2123 va_start(vl, fmt); 2124 bool res = tmp.vfmt_native(fmt, vl); 2125 va_end(vl); 2126 if (res) 2127 res = append(&tmp); 2128 return res; 2129 } 2130 fmt_preend_native(const char * fmt...)2131 bool LSPString::fmt_preend_native(const char *fmt...) 2132 { 2133 LSPString tmp; 2134 va_list vl; 2135 2136 va_start(vl, fmt); 2137 bool res = tmp.vfmt_native(fmt, vl); 2138 va_end(vl); 2139 if (res) 2140 res = prepend(&tmp); 2141 return res; 2142 } 2143 fmt_native(const char * fmt...)2144 bool LSPString::fmt_native(const char *fmt...) 2145 { 2146 va_list vl; 2147 va_start(vl, fmt); 2148 bool res = vfmt_native(fmt, vl); 2149 va_end(vl); 2150 2151 return res; 2152 } 2153 vfmt_append_native(const char * fmt,va_list args)2154 bool LSPString::vfmt_append_native(const char *fmt, va_list args) 2155 { 2156 LSPString tmp; 2157 if (!tmp.vfmt_native(fmt, args)) 2158 return false; 2159 return append(&tmp); 2160 } 2161 vfmt_preend_native(const char * fmt,va_list args)2162 bool LSPString::vfmt_preend_native(const char *fmt, va_list args) 2163 { 2164 LSPString tmp; 2165 if (!tmp.vfmt_native(fmt, args)) 2166 return false; 2167 return prepend(&tmp); 2168 } 2169 vfmt_native(const char * fmt,va_list args)2170 bool LSPString::vfmt_native(const char *fmt, va_list args) 2171 { 2172 char *ptr = NULL; 2173 int count = vasprintf(&ptr, fmt, args); 2174 if (ptr == NULL) 2175 return false; 2176 2177 bool res = set_native(ptr, count); 2178 free(ptr); 2179 return res; 2180 } 2181 fmt_append_ascii(const char * fmt...)2182 bool LSPString::fmt_append_ascii(const char *fmt...) 2183 { 2184 LSPString tmp; 2185 va_list vl; 2186 2187 va_start(vl, fmt); 2188 bool res = tmp.vfmt_ascii(fmt, vl); 2189 va_end(vl); 2190 if (res) 2191 res = append(&tmp); 2192 return res; 2193 } 2194 fmt_prepend_ascii(const char * fmt...)2195 bool LSPString::fmt_prepend_ascii(const char *fmt...) 2196 { 2197 LSPString tmp; 2198 va_list vl; 2199 2200 va_start(vl, fmt); 2201 bool res = tmp.vfmt_ascii(fmt, vl); 2202 va_end(vl); 2203 if (res) 2204 res = prepend(&tmp); 2205 return res; 2206 } 2207 fmt_ascii(const char * fmt...)2208 bool LSPString::fmt_ascii(const char *fmt...) 2209 { 2210 va_list vl; 2211 va_start(vl, fmt); 2212 bool res = vfmt_ascii(fmt, vl); 2213 va_end(vl); 2214 2215 return res; 2216 } 2217 vfmt_append_ascii(const char * fmt,va_list args)2218 bool LSPString::vfmt_append_ascii(const char *fmt, va_list args) 2219 { 2220 LSPString tmp; 2221 if (!tmp.vfmt_ascii(fmt, args)) 2222 return false; 2223 return append(&tmp); 2224 } 2225 vfmt_prepend_ascii(const char * fmt,va_list args)2226 bool LSPString::vfmt_prepend_ascii(const char *fmt, va_list args) 2227 { 2228 LSPString tmp; 2229 if (!tmp.vfmt_ascii(fmt, args)) 2230 return false; 2231 return prepend(&tmp); 2232 } 2233 vfmt_ascii(const char * fmt,va_list args)2234 bool LSPString::vfmt_ascii(const char *fmt, va_list args) 2235 { 2236 char *ptr = NULL; 2237 int count = vasprintf(&ptr, fmt, args); 2238 if (ptr == NULL) 2239 return false; 2240 2241 bool res = set_ascii(ptr, count); 2242 free(ptr); 2243 return res; 2244 } 2245 fmt_append_utf8(const char * fmt...)2246 bool LSPString::fmt_append_utf8(const char *fmt...) 2247 { 2248 LSPString tmp; 2249 va_list vl; 2250 2251 va_start(vl, fmt); 2252 bool res = tmp.vfmt_utf8(fmt, vl); 2253 va_end(vl); 2254 if (res) 2255 res = append(&tmp); 2256 return res; 2257 } 2258 fmt_prepend_utf8(const char * fmt...)2259 bool LSPString::fmt_prepend_utf8(const char *fmt...) 2260 { 2261 LSPString tmp; 2262 va_list vl; 2263 2264 va_start(vl, fmt); 2265 bool res = tmp.vfmt_utf8(fmt, vl); 2266 va_end(vl); 2267 if (res) 2268 res = prepend(&tmp); 2269 return res; 2270 } 2271 fmt_utf8(const char * fmt...)2272 bool LSPString::fmt_utf8(const char *fmt...) 2273 { 2274 va_list vl; 2275 va_start(vl, fmt); 2276 bool res = vfmt_utf8(fmt, vl); 2277 va_end(vl); 2278 2279 return res; 2280 } 2281 vfmt_append_utf8(const char * fmt,va_list args)2282 bool LSPString::vfmt_append_utf8(const char *fmt, va_list args) 2283 { 2284 LSPString tmp; 2285 if (!tmp.vfmt_utf8(fmt, args)) 2286 return false; 2287 return append(&tmp); 2288 } 2289 vfmt_prepend_utf8(const char * fmt,va_list args)2290 bool LSPString::vfmt_prepend_utf8(const char *fmt, va_list args) 2291 { 2292 LSPString tmp; 2293 if (!tmp.vfmt_utf8(fmt, args)) 2294 return false; 2295 return prepend(&tmp); 2296 } 2297 vfmt_utf8(const char * fmt,va_list args)2298 bool LSPString::vfmt_utf8(const char *fmt, va_list args) 2299 { 2300 char *ptr = NULL; 2301 int count = vasprintf(&ptr, fmt, args); 2302 if (ptr == NULL) 2303 return false; 2304 2305 bool res = set_utf8(ptr, count); 2306 free(ptr); 2307 return res; 2308 } 2309 } /* namespace lsp */ 2310