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 |