| OLD | NEW |
| 1 /* | 1 /* |
| 2 ********************************************************************** | 2 ********************************************************************** |
| 3 * Copyright (C) 2009-2012, International Business Machines | 3 * Copyright (C) 2009-2014, International Business Machines |
| 4 * Corporation and others. All Rights Reserved. | 4 * Corporation and others. All Rights Reserved. |
| 5 ********************************************************************** | 5 ********************************************************************** |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "unicode/utypes.h" | 8 #include "unicode/utypes.h" |
| 9 #include "unicode/ures.h" | 9 #include "unicode/ures.h" |
| 10 #include "unicode/putil.h" | 10 #include "unicode/putil.h" |
| 11 #include "unicode/uloc.h" | 11 #include "unicode/uloc.h" |
| 12 #include "ustr_imp.h" | 12 #include "ustr_imp.h" |
| 13 #include "cmemory.h" | 13 #include "cmemory.h" |
| 14 #include "cstring.h" | 14 #include "cstring.h" |
| 15 #include "putilimp.h" | 15 #include "putilimp.h" |
| 16 #include "uinvchar.h" | 16 #include "uinvchar.h" |
| 17 #include "ulocimp.h" | 17 #include "ulocimp.h" |
| 18 #include "uassert.h" | 18 #include "uassert.h" |
| 19 | 19 |
| 20 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) | |
| 21 | |
| 22 /* struct holding a single variant */ | 20 /* struct holding a single variant */ |
| 23 typedef struct VariantListEntry { | 21 typedef struct VariantListEntry { |
| 24 const char *variant; | 22 const char *variant; |
| 25 struct VariantListEntry *next; | 23 struct VariantListEntry *next; |
| 26 } VariantListEntry; | 24 } VariantListEntry; |
| 27 | 25 |
| 28 /* struct holding a single attribute value */ | 26 /* struct holding a single attribute value */ |
| 29 typedef struct AttributeListEntry { | 27 typedef struct AttributeListEntry { |
| 30 const char *attribute; | 28 const char *attribute; |
| 31 struct AttributeListEntry *next; | 29 struct AttributeListEntry *next; |
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 403 pSubtag = p; | 401 pSubtag = p; |
| 404 } | 402 } |
| 405 p++; | 403 p++; |
| 406 } | 404 } |
| 407 if (pSubtag == NULL) { | 405 if (pSubtag == NULL) { |
| 408 return FALSE; | 406 return FALSE; |
| 409 } | 407 } |
| 410 return _isPrivateuseValueSubtag(pSubtag, (int32_t)(p - pSubtag)); | 408 return _isPrivateuseValueSubtag(pSubtag, (int32_t)(p - pSubtag)); |
| 411 } | 409 } |
| 412 | 410 |
| 413 static UBool | 411 U_CFUNC UBool |
| 414 _isLDMLKey(const char* s, int32_t len) { | 412 ultag_isUnicodeLocaleKey(const char* s, int32_t len) { |
| 415 if (len < 0) { | 413 if (len < 0) { |
| 416 len = (int32_t)uprv_strlen(s); | 414 len = (int32_t)uprv_strlen(s); |
| 417 } | 415 } |
| 418 if (len == 2 && _isAlphaNumericString(s, len)) { | 416 if (len == 2 && _isAlphaNumericString(s, len)) { |
| 419 return TRUE; | 417 return TRUE; |
| 420 } | 418 } |
| 421 return FALSE; | 419 return FALSE; |
| 422 } | 420 } |
| 423 | 421 |
| 424 static UBool | 422 U_CFUNC UBool |
| 425 _isLDMLType(const char* s, int32_t len) { | 423 ultag_isUnicodeLocaleType(const char*s, int32_t len) { |
| 424 const char* p; |
| 425 int32_t subtagLen = 0; |
| 426 |
| 426 if (len < 0) { | 427 if (len < 0) { |
| 427 len = (int32_t)uprv_strlen(s); | 428 len = (int32_t)uprv_strlen(s); |
| 428 } | 429 } |
| 429 if (len >= 3 && len <= 8 && _isAlphaNumericString(s, len)) { | 430 |
| 430 return TRUE; | 431 for (p = s; len > 0; p++, len--) { |
| 432 if (*p == SEP) { |
| 433 if (subtagLen < 3) { |
| 434 return FALSE; |
| 435 } |
| 436 subtagLen = 0; |
| 437 } else if (ISALPHA(*p) || ISNUMERIC(*p)) { |
| 438 subtagLen++; |
| 439 if (subtagLen > 8) { |
| 440 return FALSE; |
| 441 } |
| 442 } else { |
| 443 return FALSE; |
| 444 } |
| 431 } | 445 } |
| 432 return FALSE; | 446 |
| 447 return (subtagLen >= 3); |
| 433 } | 448 } |
| 434 | |
| 435 /* | 449 /* |
| 436 * ------------------------------------------------- | 450 * ------------------------------------------------- |
| 437 * | 451 * |
| 438 * Helper functions | 452 * Helper functions |
| 439 * | 453 * |
| 440 * ------------------------------------------------- | 454 * ------------------------------------------------- |
| 441 */ | 455 */ |
| 442 | 456 |
| 443 static UBool | 457 static UBool |
| 444 _addVariantToList(VariantListEntry **first, VariantListEntry *var) { | 458 _addVariantToList(VariantListEntry **first, VariantListEntry *var) { |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 603 langtag->script = EMPTY; | 617 langtag->script = EMPTY; |
| 604 langtag->region = EMPTY; | 618 langtag->region = EMPTY; |
| 605 | 619 |
| 606 langtag->variants = NULL; | 620 langtag->variants = NULL; |
| 607 langtag->extensions = NULL; | 621 langtag->extensions = NULL; |
| 608 | 622 |
| 609 langtag->grandfathered = EMPTY; | 623 langtag->grandfathered = EMPTY; |
| 610 langtag->privateuse = EMPTY; | 624 langtag->privateuse = EMPTY; |
| 611 } | 625 } |
| 612 | 626 |
| 613 #define KEYTYPEDATA "keyTypeData" | |
| 614 #define KEYMAP "keyMap" | |
| 615 #define TYPEMAP "typeMap" | |
| 616 #define TYPEALIAS "typeAlias" | |
| 617 #define MAX_BCP47_SUBTAG_LEN 9 /* including null terminator */ | |
| 618 #define MAX_LDML_KEY_LEN 22 | |
| 619 #define MAX_LDML_TYPE_LEN 32 | |
| 620 | |
| 621 static int32_t | |
| 622 _ldmlKeyToBCP47(const char* key, int32_t keyLen, | |
| 623 char* bcpKey, int32_t bcpKeyCapacity, | |
| 624 UErrorCode *status) { | |
| 625 UResourceBundle *rb; | |
| 626 char keyBuf[MAX_LDML_KEY_LEN]; | |
| 627 char bcpKeyBuf[MAX_BCP47_SUBTAG_LEN]; | |
| 628 int32_t resultLen = 0; | |
| 629 int32_t i; | |
| 630 UErrorCode tmpStatus = U_ZERO_ERROR; | |
| 631 const UChar *uBcpKey; | |
| 632 int32_t bcpKeyLen; | |
| 633 | |
| 634 if (keyLen < 0) { | |
| 635 keyLen = (int32_t)uprv_strlen(key); | |
| 636 } | |
| 637 | |
| 638 if (keyLen >= sizeof(keyBuf)) { | |
| 639 /* no known valid LDML key exceeding 21 */ | |
| 640 *status = U_ILLEGAL_ARGUMENT_ERROR; | |
| 641 return 0; | |
| 642 } | |
| 643 | |
| 644 uprv_memcpy(keyBuf, key, keyLen); | |
| 645 keyBuf[keyLen] = 0; | |
| 646 | |
| 647 /* to lower case */ | |
| 648 for (i = 0; i < keyLen; i++) { | |
| 649 keyBuf[i] = uprv_tolower(keyBuf[i]); | |
| 650 } | |
| 651 | |
| 652 rb = ures_openDirect(NULL, KEYTYPEDATA, status); | |
| 653 ures_getByKey(rb, KEYMAP, rb, status); | |
| 654 | |
| 655 if (U_FAILURE(*status)) { | |
| 656 ures_close(rb); | |
| 657 return 0; | |
| 658 } | |
| 659 | |
| 660 uBcpKey = ures_getStringByKey(rb, keyBuf, &bcpKeyLen, &tmpStatus); | |
| 661 if (U_SUCCESS(tmpStatus)) { | |
| 662 u_UCharsToChars(uBcpKey, bcpKeyBuf, bcpKeyLen); | |
| 663 bcpKeyBuf[bcpKeyLen] = 0; | |
| 664 resultLen = bcpKeyLen; | |
| 665 } else { | |
| 666 if (_isLDMLKey(key, keyLen)) { | |
| 667 uprv_memcpy(bcpKeyBuf, key, keyLen); | |
| 668 bcpKeyBuf[keyLen] = 0; | |
| 669 resultLen = keyLen; | |
| 670 } else { | |
| 671 /* mapping not availabe */ | |
| 672 *status = U_ILLEGAL_ARGUMENT_ERROR; | |
| 673 } | |
| 674 } | |
| 675 ures_close(rb); | |
| 676 | |
| 677 if (U_FAILURE(*status)) { | |
| 678 return 0; | |
| 679 } | |
| 680 | |
| 681 uprv_memcpy(bcpKey, bcpKeyBuf, uprv_min(resultLen, bcpKeyCapacity)); | |
| 682 return u_terminateChars(bcpKey, bcpKeyCapacity, resultLen, status); | |
| 683 } | |
| 684 | |
| 685 static int32_t | |
| 686 _bcp47ToLDMLKey(const char* bcpKey, int32_t bcpKeyLen, | |
| 687 char* key, int32_t keyCapacity, | |
| 688 UErrorCode *status) { | |
| 689 UResourceBundle *rb; | |
| 690 char bcpKeyBuf[MAX_BCP47_SUBTAG_LEN]; | |
| 691 int32_t resultLen = 0; | |
| 692 int32_t i; | |
| 693 const char *resKey = NULL; | |
| 694 UResourceBundle *mapData; | |
| 695 | |
| 696 if (bcpKeyLen < 0) { | |
| 697 bcpKeyLen = (int32_t)uprv_strlen(bcpKey); | |
| 698 } | |
| 699 | |
| 700 if (bcpKeyLen >= sizeof(bcpKeyBuf)) { | |
| 701 *status = U_ILLEGAL_ARGUMENT_ERROR; | |
| 702 return 0; | |
| 703 } | |
| 704 | |
| 705 uprv_memcpy(bcpKeyBuf, bcpKey, bcpKeyLen); | |
| 706 bcpKeyBuf[bcpKeyLen] = 0; | |
| 707 | |
| 708 /* to lower case */ | |
| 709 for (i = 0; i < bcpKeyLen; i++) { | |
| 710 bcpKeyBuf[i] = uprv_tolower(bcpKeyBuf[i]); | |
| 711 } | |
| 712 | |
| 713 rb = ures_openDirect(NULL, KEYTYPEDATA, status); | |
| 714 ures_getByKey(rb, KEYMAP, rb, status); | |
| 715 if (U_FAILURE(*status)) { | |
| 716 ures_close(rb); | |
| 717 return 0; | |
| 718 } | |
| 719 | |
| 720 mapData = ures_getNextResource(rb, NULL, status); | |
| 721 while (U_SUCCESS(*status)) { | |
| 722 const UChar *uBcpKey; | |
| 723 char tmpBcpKeyBuf[MAX_BCP47_SUBTAG_LEN]; | |
| 724 int32_t tmpBcpKeyLen; | |
| 725 | |
| 726 uBcpKey = ures_getString(mapData, &tmpBcpKeyLen, status); | |
| 727 if (U_FAILURE(*status)) { | |
| 728 break; | |
| 729 } | |
| 730 u_UCharsToChars(uBcpKey, tmpBcpKeyBuf, tmpBcpKeyLen); | |
| 731 tmpBcpKeyBuf[tmpBcpKeyLen] = 0; | |
| 732 if (uprv_compareInvCharsAsAscii(bcpKeyBuf, tmpBcpKeyBuf) == 0) { | |
| 733 /* found a matching BCP47 key */ | |
| 734 resKey = ures_getKey(mapData); | |
| 735 resultLen = (int32_t)uprv_strlen(resKey); | |
| 736 break; | |
| 737 } | |
| 738 if (!ures_hasNext(rb)) { | |
| 739 break; | |
| 740 } | |
| 741 ures_getNextResource(rb, mapData, status); | |
| 742 } | |
| 743 ures_close(mapData); | |
| 744 ures_close(rb); | |
| 745 | |
| 746 if (U_FAILURE(*status)) { | |
| 747 return 0; | |
| 748 } | |
| 749 | |
| 750 if (resKey == NULL) { | |
| 751 resKey = bcpKeyBuf; | |
| 752 resultLen = bcpKeyLen; | |
| 753 } | |
| 754 | |
| 755 uprv_memcpy(key, resKey, uprv_min(resultLen, keyCapacity)); | |
| 756 return u_terminateChars(key, keyCapacity, resultLen, status); | |
| 757 } | |
| 758 | |
| 759 static int32_t | |
| 760 _ldmlTypeToBCP47(const char* key, int32_t keyLen, | |
| 761 const char* type, int32_t typeLen, | |
| 762 char* bcpType, int32_t bcpTypeCapacity, | |
| 763 UErrorCode *status) { | |
| 764 UResourceBundle *rb, *keyTypeData, *typeMapForKey; | |
| 765 char keyBuf[MAX_LDML_KEY_LEN]; | |
| 766 char typeBuf[MAX_LDML_TYPE_LEN]; | |
| 767 char bcpTypeBuf[MAX_BCP47_SUBTAG_LEN]; | |
| 768 int32_t resultLen = 0; | |
| 769 int32_t i; | |
| 770 UErrorCode tmpStatus = U_ZERO_ERROR; | |
| 771 const UChar *uBcpType, *uCanonicalType; | |
| 772 int32_t bcpTypeLen, canonicalTypeLen; | |
| 773 UBool isTimezone = FALSE; | |
| 774 | |
| 775 if (keyLen < 0) { | |
| 776 keyLen = (int32_t)uprv_strlen(key); | |
| 777 } | |
| 778 if (keyLen >= sizeof(keyBuf)) { | |
| 779 /* no known valid LDML key exceeding 21 */ | |
| 780 *status = U_ILLEGAL_ARGUMENT_ERROR; | |
| 781 return 0; | |
| 782 } | |
| 783 uprv_memcpy(keyBuf, key, keyLen); | |
| 784 keyBuf[keyLen] = 0; | |
| 785 | |
| 786 /* to lower case */ | |
| 787 for (i = 0; i < keyLen; i++) { | |
| 788 keyBuf[i] = uprv_tolower(keyBuf[i]); | |
| 789 } | |
| 790 if (uprv_compareInvCharsAsAscii(keyBuf, "timezone") == 0) { | |
| 791 isTimezone = TRUE; | |
| 792 } | |
| 793 | |
| 794 if (typeLen < 0) { | |
| 795 typeLen = (int32_t)uprv_strlen(type); | |
| 796 } | |
| 797 if (typeLen >= sizeof(typeBuf)) { | |
| 798 *status = U_ILLEGAL_ARGUMENT_ERROR; | |
| 799 return 0; | |
| 800 } | |
| 801 | |
| 802 if (isTimezone) { | |
| 803 /* replace '/' with ':' */ | |
| 804 for (i = 0; i < typeLen; i++) { | |
| 805 if (*(type + i) == '/') { | |
| 806 typeBuf[i] = ':'; | |
| 807 } else { | |
| 808 typeBuf[i] = *(type + i); | |
| 809 } | |
| 810 } | |
| 811 typeBuf[typeLen] = 0; | |
| 812 type = &typeBuf[0]; | |
| 813 } | |
| 814 | |
| 815 keyTypeData = ures_openDirect(NULL, KEYTYPEDATA, status); | |
| 816 rb = ures_getByKey(keyTypeData, TYPEMAP, NULL, status); | |
| 817 if (U_FAILURE(*status)) { | |
| 818 ures_close(rb); | |
| 819 ures_close(keyTypeData); | |
| 820 return 0; | |
| 821 } | |
| 822 | |
| 823 typeMapForKey = ures_getByKey(rb, keyBuf, NULL, &tmpStatus); | |
| 824 uBcpType = ures_getStringByKey(typeMapForKey, type, &bcpTypeLen, &tmpStatus)
; | |
| 825 if (U_SUCCESS(tmpStatus)) { | |
| 826 u_UCharsToChars(uBcpType, bcpTypeBuf, bcpTypeLen); | |
| 827 resultLen = bcpTypeLen; | |
| 828 } else if (tmpStatus == U_MISSING_RESOURCE_ERROR) { | |
| 829 /* is this type alias? */ | |
| 830 tmpStatus = U_ZERO_ERROR; | |
| 831 ures_getByKey(keyTypeData, TYPEALIAS, rb, &tmpStatus); | |
| 832 ures_getByKey(rb, keyBuf, rb, &tmpStatus); | |
| 833 uCanonicalType = ures_getStringByKey(rb, type, &canonicalTypeLen, &tmpSt
atus); | |
| 834 if (U_SUCCESS(tmpStatus)) { | |
| 835 u_UCharsToChars(uCanonicalType, typeBuf, canonicalTypeLen); | |
| 836 if (isTimezone) { | |
| 837 /* replace '/' with ':' */ | |
| 838 for (i = 0; i < canonicalTypeLen; i++) { | |
| 839 if (typeBuf[i] == '/') { | |
| 840 typeBuf[i] = ':'; | |
| 841 } | |
| 842 } | |
| 843 } | |
| 844 typeBuf[canonicalTypeLen] = 0; | |
| 845 | |
| 846 /* look up the canonical type */ | |
| 847 uBcpType = ures_getStringByKey(typeMapForKey, typeBuf, &bcpTypeLen,
&tmpStatus); | |
| 848 if (U_SUCCESS(tmpStatus)) { | |
| 849 u_UCharsToChars(uBcpType, bcpTypeBuf, bcpTypeLen); | |
| 850 resultLen = bcpTypeLen; | |
| 851 } | |
| 852 } | |
| 853 if (tmpStatus == U_MISSING_RESOURCE_ERROR) { | |
| 854 if (_isLDMLType(type, typeLen)) { | |
| 855 uprv_memcpy(bcpTypeBuf, type, typeLen); | |
| 856 resultLen = typeLen; | |
| 857 } else { | |
| 858 /* mapping not availabe */ | |
| 859 *status = U_ILLEGAL_ARGUMENT_ERROR; | |
| 860 } | |
| 861 } | |
| 862 } else { | |
| 863 *status = tmpStatus; | |
| 864 } | |
| 865 ures_close(rb); | |
| 866 ures_close(typeMapForKey); | |
| 867 ures_close(keyTypeData); | |
| 868 | |
| 869 if (U_FAILURE(*status)) { | |
| 870 return 0; | |
| 871 } | |
| 872 | |
| 873 uprv_memcpy(bcpType, bcpTypeBuf, uprv_min(resultLen, bcpTypeCapacity)); | |
| 874 return u_terminateChars(bcpType, bcpTypeCapacity, resultLen, status); | |
| 875 } | |
| 876 | |
| 877 static int32_t | |
| 878 _bcp47ToLDMLType(const char* key, int32_t keyLen, | |
| 879 const char* bcpType, int32_t bcpTypeLen, | |
| 880 char* type, int32_t typeCapacity, | |
| 881 UErrorCode *status) { | |
| 882 UResourceBundle *rb; | |
| 883 char keyBuf[MAX_LDML_KEY_LEN]; | |
| 884 char bcpTypeBuf[ULOC_KEYWORDS_CAPACITY]; /* ensure buffter is large enough f
or multiple values (e.g. buddhist-greg) */ | |
| 885 int32_t resultLen = 0; | |
| 886 int32_t i, typeSize; | |
| 887 const char *resType = NULL; | |
| 888 UResourceBundle *mapData; | |
| 889 UErrorCode tmpStatus = U_ZERO_ERROR; | |
| 890 int32_t copyLen; | |
| 891 | |
| 892 if (keyLen < 0) { | |
| 893 keyLen = (int32_t)uprv_strlen(key); | |
| 894 } | |
| 895 | |
| 896 if (keyLen >= sizeof(keyBuf)) { | |
| 897 /* no known valid LDML key exceeding 21 */ | |
| 898 *status = U_ILLEGAL_ARGUMENT_ERROR; | |
| 899 return 0; | |
| 900 } | |
| 901 uprv_memcpy(keyBuf, key, keyLen); | |
| 902 keyBuf[keyLen] = 0; | |
| 903 | |
| 904 /* to lower case */ | |
| 905 for (i = 0; i < keyLen; i++) { | |
| 906 keyBuf[i] = uprv_tolower(keyBuf[i]); | |
| 907 } | |
| 908 | |
| 909 | |
| 910 if (bcpTypeLen < 0) { | |
| 911 bcpTypeLen = (int32_t)uprv_strlen(bcpType); | |
| 912 } | |
| 913 | |
| 914 typeSize = 0; | |
| 915 for (i = 0; i < bcpTypeLen; i++) { | |
| 916 if (bcpType[i] == SEP) { | |
| 917 if (typeSize >= MAX_BCP47_SUBTAG_LEN) { | |
| 918 *status = U_ILLEGAL_ARGUMENT_ERROR; | |
| 919 return 0; | |
| 920 } | |
| 921 typeSize = 0; | |
| 922 } else { | |
| 923 typeSize++; | |
| 924 } | |
| 925 } | |
| 926 | |
| 927 uprv_memcpy(bcpTypeBuf, bcpType, bcpTypeLen); | |
| 928 bcpTypeBuf[bcpTypeLen] = 0; | |
| 929 | |
| 930 /* to lower case */ | |
| 931 for (i = 0; i < bcpTypeLen; i++) { | |
| 932 bcpTypeBuf[i] = uprv_tolower(bcpTypeBuf[i]); | |
| 933 } | |
| 934 | |
| 935 rb = ures_openDirect(NULL, KEYTYPEDATA, status); | |
| 936 ures_getByKey(rb, TYPEMAP, rb, status); | |
| 937 if (U_FAILURE(*status)) { | |
| 938 ures_close(rb); | |
| 939 return 0; | |
| 940 } | |
| 941 | |
| 942 ures_getByKey(rb, keyBuf, rb, &tmpStatus); | |
| 943 mapData = ures_getNextResource(rb, NULL, &tmpStatus); | |
| 944 while (U_SUCCESS(tmpStatus)) { | |
| 945 const UChar *uBcpType; | |
| 946 char tmpBcpTypeBuf[MAX_BCP47_SUBTAG_LEN]; | |
| 947 int32_t tmpBcpTypeLen; | |
| 948 | |
| 949 uBcpType = ures_getString(mapData, &tmpBcpTypeLen, &tmpStatus); | |
| 950 if (U_FAILURE(tmpStatus)) { | |
| 951 break; | |
| 952 } | |
| 953 u_UCharsToChars(uBcpType, tmpBcpTypeBuf, tmpBcpTypeLen); | |
| 954 tmpBcpTypeBuf[tmpBcpTypeLen] = 0; | |
| 955 if (uprv_compareInvCharsAsAscii(bcpTypeBuf, tmpBcpTypeBuf) == 0) { | |
| 956 /* found a matching BCP47 type */ | |
| 957 resType = ures_getKey(mapData); | |
| 958 resultLen = (int32_t)uprv_strlen(resType); | |
| 959 break; | |
| 960 } | |
| 961 if (!ures_hasNext(rb)) { | |
| 962 break; | |
| 963 } | |
| 964 ures_getNextResource(rb, mapData, &tmpStatus); | |
| 965 } | |
| 966 ures_close(mapData); | |
| 967 ures_close(rb); | |
| 968 | |
| 969 if (U_FAILURE(tmpStatus) && tmpStatus != U_MISSING_RESOURCE_ERROR) { | |
| 970 *status = tmpStatus; | |
| 971 return 0; | |
| 972 } | |
| 973 | |
| 974 if (resType == NULL) { | |
| 975 resType = bcpTypeBuf; | |
| 976 resultLen = bcpTypeLen; | |
| 977 } | |
| 978 | |
| 979 copyLen = uprv_min(resultLen, typeCapacity); | |
| 980 uprv_memcpy(type, resType, copyLen); | |
| 981 | |
| 982 if (uprv_compareInvCharsAsAscii(keyBuf, "timezone") == 0) { | |
| 983 for (i = 0; i < copyLen; i++) { | |
| 984 if (*(type + i) == ':') { | |
| 985 *(type + i) = '/'; | |
| 986 } | |
| 987 } | |
| 988 } | |
| 989 | |
| 990 return u_terminateChars(type, typeCapacity, resultLen, status); | |
| 991 } | |
| 992 | |
| 993 static int32_t | 627 static int32_t |
| 994 _appendLanguageToLanguageTag(const char* localeID, char* appendAt, int32_t capac
ity, UBool strict, UErrorCode* status) { | 628 _appendLanguageToLanguageTag(const char* localeID, char* appendAt, int32_t capac
ity, UBool strict, UErrorCode* status) { |
| 995 char buf[ULOC_LANG_CAPACITY]; | 629 char buf[ULOC_LANG_CAPACITY]; |
| 996 UErrorCode tmpStatus = U_ZERO_ERROR; | 630 UErrorCode tmpStatus = U_ZERO_ERROR; |
| 997 int32_t len, i; | 631 int32_t len, i; |
| 998 int32_t reslen = 0; | 632 int32_t reslen = 0; |
| 999 | 633 |
| 1000 if (U_FAILURE(*status)) { | 634 if (U_FAILURE(*status)) { |
| 1001 return 0; | 635 return 0; |
| 1002 } | 636 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1022 if (strict) { | 656 if (strict) { |
| 1023 *status = U_ILLEGAL_ARGUMENT_ERROR; | 657 *status = U_ILLEGAL_ARGUMENT_ERROR; |
| 1024 return 0; | 658 return 0; |
| 1025 } | 659 } |
| 1026 if (reslen < capacity) { | 660 if (reslen < capacity) { |
| 1027 uprv_memcpy(appendAt + reslen, LANG_UND, uprv_min(LANG_UND_LEN, capa
city - reslen)); | 661 uprv_memcpy(appendAt + reslen, LANG_UND, uprv_min(LANG_UND_LEN, capa
city - reslen)); |
| 1028 } | 662 } |
| 1029 reslen += LANG_UND_LEN; | 663 reslen += LANG_UND_LEN; |
| 1030 } else { | 664 } else { |
| 1031 /* resolve deprecated */ | 665 /* resolve deprecated */ |
| 1032 for (i = 0; i < LENGTHOF(DEPRECATEDLANGS); i += 2) { | 666 for (i = 0; i < UPRV_LENGTHOF(DEPRECATEDLANGS); i += 2) { |
| 1033 if (uprv_compareInvCharsAsAscii(buf, DEPRECATEDLANGS[i]) == 0) { | 667 if (uprv_compareInvCharsAsAscii(buf, DEPRECATEDLANGS[i]) == 0) { |
| 1034 uprv_strcpy(buf, DEPRECATEDLANGS[i + 1]); | 668 uprv_strcpy(buf, DEPRECATEDLANGS[i + 1]); |
| 1035 len = (int32_t)uprv_strlen(buf); | 669 len = (int32_t)uprv_strlen(buf); |
| 1036 break; | 670 break; |
| 1037 } | 671 } |
| 1038 } | 672 } |
| 1039 if (reslen < capacity) { | 673 if (reslen < capacity) { |
| 1040 uprv_memcpy(appendAt + reslen, buf, uprv_min(len, capacity - reslen)
); | 674 uprv_memcpy(appendAt + reslen, buf, uprv_min(len, capacity - reslen)
); |
| 1041 } | 675 } |
| 1042 reslen += len; | 676 reslen += len; |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1275 ExtensionListEntry *ext; | 909 ExtensionListEntry *ext; |
| 1276 AttributeListEntry *firstAttr = NULL; | 910 AttributeListEntry *firstAttr = NULL; |
| 1277 AttributeListEntry *attr; | 911 AttributeListEntry *attr; |
| 1278 char *attrValue; | 912 char *attrValue; |
| 1279 char extBuf[ULOC_KEYWORD_AND_VALUES_CAPACITY]; | 913 char extBuf[ULOC_KEYWORD_AND_VALUES_CAPACITY]; |
| 1280 char *pExtBuf = extBuf; | 914 char *pExtBuf = extBuf; |
| 1281 int32_t extBufCapacity = sizeof(extBuf); | 915 int32_t extBufCapacity = sizeof(extBuf); |
| 1282 const char *bcpKey, *bcpValue; | 916 const char *bcpKey, *bcpValue; |
| 1283 UErrorCode tmpStatus = U_ZERO_ERROR; | 917 UErrorCode tmpStatus = U_ZERO_ERROR; |
| 1284 int32_t keylen; | 918 int32_t keylen; |
| 1285 UBool isLDMLKeyword; | 919 UBool isBcpUExt; |
| 1286 | 920 |
| 1287 while (TRUE) { | 921 while (TRUE) { |
| 1288 isAttribute = FALSE; | 922 isAttribute = FALSE; |
| 1289 key = uenum_next(keywordEnum, NULL, status); | 923 key = uenum_next(keywordEnum, NULL, status); |
| 1290 if (key == NULL) { | 924 if (key == NULL) { |
| 1291 break; | 925 break; |
| 1292 } | 926 } |
| 1293 len = uloc_getKeywordValue(localeID, key, buf, sizeof(buf), &tmpStat
us); | 927 len = uloc_getKeywordValue(localeID, key, buf, sizeof(buf), &tmpStat
us); |
| 1294 if (U_FAILURE(tmpStatus)) { | 928 /* buf must be null-terminated */ |
| 929 if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WAR
NING) { |
| 1295 if (strict) { | 930 if (strict) { |
| 1296 *status = U_ILLEGAL_ARGUMENT_ERROR; | 931 *status = U_ILLEGAL_ARGUMENT_ERROR; |
| 1297 break; | 932 break; |
| 1298 } | 933 } |
| 1299 /* ignore this keyword */ | 934 /* ignore this keyword */ |
| 1300 tmpStatus = U_ZERO_ERROR; | 935 tmpStatus = U_ZERO_ERROR; |
| 1301 continue; | 936 continue; |
| 1302 } | 937 } |
| 1303 | 938 |
| 1304 keylen = (int32_t)uprv_strlen(key); | 939 keylen = (int32_t)uprv_strlen(key); |
| 1305 isLDMLKeyword = (keylen > 1); | 940 isBcpUExt = (keylen > 1); |
| 1306 | 941 |
| 1307 /* special keyword used for representing Unicode locale attributes *
/ | 942 /* special keyword used for representing Unicode locale attributes *
/ |
| 1308 if (uprv_strcmp(key, LOCALE_ATTRIBUTE_KEY) == 0) { | 943 if (uprv_strcmp(key, LOCALE_ATTRIBUTE_KEY) == 0) { |
| 1309 isAttribute = TRUE; | 944 isAttribute = TRUE; |
| 1310 if (len > 0) { | 945 if (len > 0) { |
| 1311 int32_t i = 0; | 946 int32_t i = 0; |
| 1312 while (TRUE) { | 947 while (TRUE) { |
| 1313 attrBufLength = 0; | 948 attrBufLength = 0; |
| 1314 for (; i < len; i++) { | 949 for (; i < len; i++) { |
| 1315 if (buf[i] != '-') { | 950 if (buf[i] != '-') { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1343 if (!_addAttributeToList(&firstAttr, attr)) { | 978 if (!_addAttributeToList(&firstAttr, attr)) { |
| 1344 uprv_free(attr); | 979 uprv_free(attr); |
| 1345 uprv_free(attrValue); | 980 uprv_free(attrValue); |
| 1346 if (strict) { | 981 if (strict) { |
| 1347 *status = U_ILLEGAL_ARGUMENT_ERROR; | 982 *status = U_ILLEGAL_ARGUMENT_ERROR; |
| 1348 break; | 983 break; |
| 1349 } | 984 } |
| 1350 } | 985 } |
| 1351 } | 986 } |
| 1352 } | 987 } |
| 1353 } else if (isLDMLKeyword) { | 988 } else if (isBcpUExt) { |
| 1354 int32_t modKeyLen; | 989 bcpKey = uloc_toUnicodeLocaleKey(key); |
| 1355 | 990 if (bcpKey == NULL) { |
| 1356 /* transform key and value to bcp47 style */ | |
| 1357 modKeyLen = _ldmlKeyToBCP47(key, keylen, pExtBuf, extBufCapacity
, &tmpStatus); | |
| 1358 if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED
_WARNING) { | |
| 1359 if (strict) { | 991 if (strict) { |
| 1360 *status = U_ILLEGAL_ARGUMENT_ERROR; | 992 *status = U_ILLEGAL_ARGUMENT_ERROR; |
| 1361 break; | 993 break; |
| 1362 } | 994 } |
| 1363 tmpStatus = U_ZERO_ERROR; | |
| 1364 continue; | 995 continue; |
| 1365 } | 996 } |
| 1366 | 997 |
| 1367 bcpKey = pExtBuf; | 998 /* we've checked buf is null-terminated above */ |
| 1368 pExtBuf += (modKeyLen + 1); | 999 bcpValue = uloc_toUnicodeLocaleType(key, buf); |
| 1369 extBufCapacity -= (modKeyLen + 1); | 1000 if (bcpValue == NULL) { |
| 1370 | |
| 1371 len = _ldmlTypeToBCP47(key, keylen, buf, len, pExtBuf, extBufCap
acity, &tmpStatus); | |
| 1372 if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED
_WARNING) { | |
| 1373 if (strict) { | 1001 if (strict) { |
| 1374 *status = U_ILLEGAL_ARGUMENT_ERROR; | 1002 *status = U_ILLEGAL_ARGUMENT_ERROR; |
| 1375 break; | 1003 break; |
| 1376 } | 1004 } |
| 1377 tmpStatus = U_ZERO_ERROR; | |
| 1378 continue; | 1005 continue; |
| 1379 } | 1006 } |
| 1380 bcpValue = pExtBuf; | 1007 if (bcpValue == buf) { |
| 1381 pExtBuf += (len + 1); | 1008 /* |
| 1382 extBufCapacity -= (len + 1); | 1009 When uloc_toUnicodeLocaleType(key, buf) returns the |
| 1010 input value as is, the value is well-formed, but has |
| 1011 no known mapping. This implementation normalizes the |
| 1012 the value to lower case |
| 1013 */ |
| 1014 int32_t bcpValueLen = uprv_strlen(bcpValue); |
| 1015 if (bcpValueLen < extBufCapacity) { |
| 1016 uprv_strcpy(pExtBuf, bcpValue); |
| 1017 T_CString_toLowerCase(pExtBuf); |
| 1018 |
| 1019 bcpValue = pExtBuf; |
| 1020 |
| 1021 pExtBuf += (bcpValueLen + 1); |
| 1022 extBufCapacity -= (bcpValueLen + 1); |
| 1023 } else { |
| 1024 if (strict) { |
| 1025 *status = U_ILLEGAL_ARGUMENT_ERROR; |
| 1026 break; |
| 1027 } |
| 1028 continue; |
| 1029 } |
| 1030 } |
| 1383 } else { | 1031 } else { |
| 1384 if (*key == PRIVATEUSE) { | 1032 if (*key == PRIVATEUSE) { |
| 1385 if (!_isPrivateuseValueSubtags(buf, len)) { | 1033 if (!_isPrivateuseValueSubtags(buf, len)) { |
| 1386 if (strict) { | 1034 if (strict) { |
| 1387 *status = U_ILLEGAL_ARGUMENT_ERROR; | 1035 *status = U_ILLEGAL_ARGUMENT_ERROR; |
| 1388 break; | 1036 break; |
| 1389 } | 1037 } |
| 1390 continue; | 1038 continue; |
| 1391 } | 1039 } |
| 1392 } else { | 1040 } else { |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1564 *posixVariant = FALSE; | 1212 *posixVariant = FALSE; |
| 1565 | 1213 |
| 1566 pTag = ldmlext; | 1214 pTag = ldmlext; |
| 1567 pKwds = NULL; | 1215 pKwds = NULL; |
| 1568 | 1216 |
| 1569 /* Iterate through u extension attributes */ | 1217 /* Iterate through u extension attributes */ |
| 1570 while (*pTag) { | 1218 while (*pTag) { |
| 1571 /* locate next separator char */ | 1219 /* locate next separator char */ |
| 1572 for (len = 0; *(pTag + len) && *(pTag + len) != SEP; len++); | 1220 for (len = 0; *(pTag + len) && *(pTag + len) != SEP; len++); |
| 1573 | 1221 |
| 1574 if (_isLDMLKey(pTag, len)) { | 1222 if (ultag_isUnicodeLocaleKey(pTag, len)) { |
| 1575 pKwds = pTag; | 1223 pKwds = pTag; |
| 1576 break; | 1224 break; |
| 1577 } | 1225 } |
| 1578 | 1226 |
| 1579 /* add this attribute to the list */ | 1227 /* add this attribute to the list */ |
| 1580 attr = (AttributeListEntry*)uprv_malloc(sizeof(AttributeListEntry)); | 1228 attr = (AttributeListEntry*)uprv_malloc(sizeof(AttributeListEntry)); |
| 1581 if (attr == NULL) { | 1229 if (attr == NULL) { |
| 1582 *status = U_MEMORY_ALLOCATION_ERROR; | 1230 *status = U_MEMORY_ALLOCATION_ERROR; |
| 1583 goto cleanup; | 1231 goto cleanup; |
| 1584 } | 1232 } |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1672 /* BCP47 representation of LDML key/type pairs */ | 1320 /* BCP47 representation of LDML key/type pairs */ |
| 1673 while (!isDone) { | 1321 while (!isDone) { |
| 1674 const char *pNextBcpKey = NULL; | 1322 const char *pNextBcpKey = NULL; |
| 1675 int32_t nextBcpKeyLen; | 1323 int32_t nextBcpKeyLen; |
| 1676 UBool emitKeyword = FALSE; | 1324 UBool emitKeyword = FALSE; |
| 1677 | 1325 |
| 1678 if (*pTag) { | 1326 if (*pTag) { |
| 1679 /* locate next separator char */ | 1327 /* locate next separator char */ |
| 1680 for (len = 0; *(pTag + len) && *(pTag + len) != SEP; len++); | 1328 for (len = 0; *(pTag + len) && *(pTag + len) != SEP; len++); |
| 1681 | 1329 |
| 1682 if (_isLDMLKey(pTag, len)) { | 1330 if (ultag_isUnicodeLocaleKey(pTag, len)) { |
| 1683 if (pBcpKey) { | 1331 if (pBcpKey) { |
| 1684 emitKeyword = TRUE; | 1332 emitKeyword = TRUE; |
| 1685 pNextBcpKey = pTag; | 1333 pNextBcpKey = pTag; |
| 1686 nextBcpKeyLen = len; | 1334 nextBcpKeyLen = len; |
| 1687 } else { | 1335 } else { |
| 1688 pBcpKey = pTag; | 1336 pBcpKey = pTag; |
| 1689 bcpKeyLen = len; | 1337 bcpKeyLen = len; |
| 1690 } | 1338 } |
| 1691 } else { | 1339 } else { |
| 1692 U_ASSERT(pBcpKey != NULL); | 1340 U_ASSERT(pBcpKey != NULL); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1708 } else { | 1356 } else { |
| 1709 /* processing last one */ | 1357 /* processing last one */ |
| 1710 emitKeyword = TRUE; | 1358 emitKeyword = TRUE; |
| 1711 isDone = TRUE; | 1359 isDone = TRUE; |
| 1712 } | 1360 } |
| 1713 | 1361 |
| 1714 if (emitKeyword) { | 1362 if (emitKeyword) { |
| 1715 const char *pKey = NULL; /* LDML key */ | 1363 const char *pKey = NULL; /* LDML key */ |
| 1716 const char *pType = NULL; /* LDML type */ | 1364 const char *pType = NULL; /* LDML type */ |
| 1717 | 1365 |
| 1366 char bcpKeyBuf[9]; /* BCP key length is always 2 for no
w */ |
| 1367 |
| 1718 U_ASSERT(pBcpKey != NULL); | 1368 U_ASSERT(pBcpKey != NULL); |
| 1719 | 1369 |
| 1720 /* u extension key to LDML key */ | 1370 if (bcpKeyLen >= sizeof(bcpKeyBuf)) { |
| 1721 len = _bcp47ToLDMLKey(pBcpKey, bcpKeyLen, buf + bufIdx, bufSize
- bufIdx - 1, status); | 1371 /* the BCP key is invalid */ |
| 1722 if (U_FAILURE(*status)) { | 1372 *status = U_ILLEGAL_ARGUMENT_ERROR; |
| 1723 goto cleanup; | 1373 goto cleanup; |
| 1724 } | 1374 } |
| 1725 pKey = buf + bufIdx; | 1375 |
| 1726 bufIdx += len; | 1376 uprv_strncpy(bcpKeyBuf, pBcpKey, bcpKeyLen); |
| 1727 *(buf + bufIdx) = 0; | 1377 bcpKeyBuf[bcpKeyLen] = 0; |
| 1728 bufIdx++; | 1378 |
| 1379 /* u extension key to LDML key */ |
| 1380 pKey = uloc_toLegacyKey(bcpKeyBuf); |
| 1381 if (pKey == NULL) { |
| 1382 *status = U_ILLEGAL_ARGUMENT_ERROR; |
| 1383 goto cleanup; |
| 1384 } |
| 1385 if (pKey == bcpKeyBuf) { |
| 1386 /* |
| 1387 The key returned by toLegacyKey points to the input buffer. |
| 1388 We normalize the result key to lower case. |
| 1389 */ |
| 1390 T_CString_toLowerCase(bcpKeyBuf); |
| 1391 if (bufSize - bufIdx - 1 >= bcpKeyLen) { |
| 1392 uprv_memcpy(buf + bufIdx, bcpKeyBuf, bcpKeyLen); |
| 1393 pKey = buf + bufIdx; |
| 1394 bufIdx += bcpKeyLen; |
| 1395 *(buf + bufIdx) = 0; |
| 1396 bufIdx++; |
| 1397 } else { |
| 1398 *status = U_BUFFER_OVERFLOW_ERROR; |
| 1399 goto cleanup; |
| 1400 } |
| 1401 } |
| 1729 | 1402 |
| 1730 if (pBcpType) { | 1403 if (pBcpType) { |
| 1731 /* BCP type to locale type */ | 1404 char bcpTypeBuf[128]; /* practically long enough even
considering multiple subtag type */ |
| 1732 len = _bcp47ToLDMLType(pKey, -1, pBcpType, bcpTypeLen, buf +
bufIdx, bufSize - bufIdx - 1, status); | 1405 if (bcpTypeLen >= sizeof(bcpTypeBuf)) { |
| 1733 if (U_FAILURE(*status)) { | 1406 /* the BCP type is too long */ |
| 1407 *status = U_ILLEGAL_ARGUMENT_ERROR; |
| 1734 goto cleanup; | 1408 goto cleanup; |
| 1735 } | 1409 } |
| 1736 pType = buf + bufIdx; | 1410 |
| 1737 bufIdx += len; | 1411 uprv_strncpy(bcpTypeBuf, pBcpType, bcpTypeLen); |
| 1738 *(buf + bufIdx) = 0; | 1412 bcpTypeBuf[bcpTypeLen] = 0; |
| 1739 bufIdx++; | 1413 |
| 1414 /* BCP type to locale type */ |
| 1415 pType = uloc_toLegacyType(pKey, bcpTypeBuf); |
| 1416 if (pType == NULL) { |
| 1417 *status = U_ILLEGAL_ARGUMENT_ERROR; |
| 1418 goto cleanup; |
| 1419 } |
| 1420 if (pType == bcpTypeBuf) { |
| 1421 /* |
| 1422 The type returned by toLegacyType points to the input bu
ffer. |
| 1423 We normalize the result type to lower case. |
| 1424 */ |
| 1425 /* normalize to lower case */ |
| 1426 T_CString_toLowerCase(bcpTypeBuf); |
| 1427 if (bufSize - bufIdx - 1 >= bcpTypeLen) { |
| 1428 uprv_memcpy(buf + bufIdx, bcpTypeBuf, bcpTypeLen); |
| 1429 pType = buf + bufIdx; |
| 1430 bufIdx += bcpTypeLen; |
| 1431 *(buf + bufIdx) = 0; |
| 1432 bufIdx++; |
| 1433 } else { |
| 1434 *status = U_BUFFER_OVERFLOW_ERROR; |
| 1435 goto cleanup; |
| 1436 } |
| 1437 } |
| 1740 } else { | 1438 } else { |
| 1741 /* typeless - default type value is "yes" */ | 1439 /* typeless - default type value is "yes" */ |
| 1742 pType = LOCALE_TYPE_YES; | 1440 pType = LOCALE_TYPE_YES; |
| 1743 } | 1441 } |
| 1744 | 1442 |
| 1745 /* Special handling for u-va-posix, since we want to treat this
as a variant, | 1443 /* Special handling for u-va-posix, since we want to treat this
as a variant, |
| 1746 not as a keyword */ | 1444 not as a keyword */ |
| 1747 if (!variantExists && !uprv_strcmp(pKey, POSIX_KEY) && !uprv_str
cmp(pType, POSIX_VALUE) ) { | 1445 if (!variantExists && !uprv_strcmp(pKey, POSIX_KEY) && !uprv_str
cmp(pType, POSIX_VALUE) ) { |
| 1748 *posixVariant = TRUE; | 1446 *posixVariant = TRUE; |
| 1749 } else { | 1447 } else { |
| (...skipping 1053 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2803 } | 2501 } |
| 2804 len = _appendKeywords(lt, localeID + reslen, localeIDCapacity - reslen,
status); | 2502 len = _appendKeywords(lt, localeID + reslen, localeIDCapacity - reslen,
status); |
| 2805 reslen += len; | 2503 reslen += len; |
| 2806 } | 2504 } |
| 2807 | 2505 |
| 2808 ultag_close(lt); | 2506 ultag_close(lt); |
| 2809 return u_terminateChars(localeID, localeIDCapacity, reslen, status); | 2507 return u_terminateChars(localeID, localeIDCapacity, reslen, status); |
| 2810 } | 2508 } |
| 2811 | 2509 |
| 2812 | 2510 |
| OLD | NEW |