xref: /aosp_15_r20/external/cronet/third_party/icu/source/common/ulocbuilder.cpp (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // © 2023 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 #include <utility>
5 
6 #include "unicode/bytestream.h"
7 #include "unicode/localebuilder.h"
8 #include "unicode/locid.h"
9 #include "unicode/stringpiece.h"
10 #include "unicode/umachine.h"
11 #include "unicode/ulocbuilder.h"
12 #include "cstring.h"
13 #include "ustr_imp.h"
14 
15 using icu::CheckedArrayByteSink;
16 using icu::StringPiece;
17 
18 #define EXTERNAL(i) (reinterpret_cast<ULocaleBuilder*>(i))
19 #define INTERNAL(e) (reinterpret_cast<icu::LocaleBuilder*>(e))
20 #define CONST_INTERNAL(e) (reinterpret_cast<const icu::LocaleBuilder*>(e))
21 
ulocbld_open()22 ULocaleBuilder* ulocbld_open() {
23     return EXTERNAL(new icu::LocaleBuilder());
24 }
25 
ulocbld_close(ULocaleBuilder * builder)26 void ulocbld_close(ULocaleBuilder* builder) {
27     if (builder == nullptr) return;
28     delete INTERNAL(builder);
29 }
30 
ulocbld_setLocale(ULocaleBuilder * builder,const char * locale,int32_t length)31 void ulocbld_setLocale(ULocaleBuilder* builder, const char* locale, int32_t length) {
32     if (builder == nullptr) return;
33     icu::Locale l;
34     if (length < 0 || locale[length] == '\0') {
35         l = icu::Locale(locale);
36     } else {
37         if (length >= ULOC_FULLNAME_CAPACITY) {
38             l.setToBogus();
39         } else {
40             // locale is not null termined but Locale API require one.
41             // Create a null termined version in buf.
42             char buf[ULOC_FULLNAME_CAPACITY];
43             uprv_memcpy(buf, locale, length);
44             buf[length] = '\0';
45             l = icu::Locale(buf);
46         }
47     }
48     INTERNAL(builder)->setLocale(l);
49 }
50 
51 void
ulocbld_adoptULocale(ULocaleBuilder * builder,ULocale * locale)52 ulocbld_adoptULocale(ULocaleBuilder* builder, ULocale* locale) {
53     if (builder == nullptr) return;
54     INTERNAL(builder)->setLocale(*(reinterpret_cast<const icu::Locale*>(locale)));
55     ulocale_close(locale);
56 }
57 
58 #define STRING_PIECE(s, l) ((l)<0 ? StringPiece(s) : StringPiece((s), (l)))
59 
60 #define IMPL_ULOCBLD_SETTER(N) \
61 void ulocbld_##N(ULocaleBuilder* bld, const char* s, int32_t l) { \
62     if (bld == nullptr) return; \
63     INTERNAL(bld)->N(STRING_PIECE(s,l)); \
64 }
65 
66 IMPL_ULOCBLD_SETTER(setLanguageTag)
IMPL_ULOCBLD_SETTER(setLanguage)67 IMPL_ULOCBLD_SETTER(setLanguage)
68 IMPL_ULOCBLD_SETTER(setScript)
69 IMPL_ULOCBLD_SETTER(setRegion)
70 IMPL_ULOCBLD_SETTER(setVariant)
71 IMPL_ULOCBLD_SETTER(addUnicodeLocaleAttribute)
72 IMPL_ULOCBLD_SETTER(removeUnicodeLocaleAttribute)
73 
74 void ulocbld_setExtension(ULocaleBuilder* builder, char key, const char* value, int32_t length) {
75     if (builder == nullptr) return;
76     INTERNAL(builder)->setExtension(key, STRING_PIECE(value, length));
77 }
78 
ulocbld_setUnicodeLocaleKeyword(ULocaleBuilder * builder,const char * key,int32_t keyLength,const char * type,int32_t typeLength)79 void ulocbld_setUnicodeLocaleKeyword(
80     ULocaleBuilder* builder, const char* key, int32_t keyLength,
81     const char* type, int32_t typeLength) {
82     if (builder == nullptr) return;
83     INTERNAL(builder)->setUnicodeLocaleKeyword(
84         STRING_PIECE(key, keyLength), STRING_PIECE(type, typeLength));
85 }
86 
ulocbld_clear(ULocaleBuilder * builder)87 void ulocbld_clear(ULocaleBuilder* builder) {
88     if (builder == nullptr) return;
89     INTERNAL(builder)->clear();
90 }
91 
ulocbld_clearExtensions(ULocaleBuilder * builder)92 void ulocbld_clearExtensions(ULocaleBuilder* builder) {
93     if (builder == nullptr) return;
94     INTERNAL(builder)->clearExtensions();
95 }
96 
97 
ulocbld_buildULocale(ULocaleBuilder * builder,UErrorCode * err)98 ULocale* ulocbld_buildULocale(ULocaleBuilder* builder, UErrorCode* err) {
99     if (builder == nullptr) {
100         *err = U_ILLEGAL_ARGUMENT_ERROR;
101         return nullptr;
102     }
103     icu::Locale l = INTERNAL(builder)->build(*err);
104     if (U_FAILURE(*err)) return nullptr;
105     icu::Locale* r = l.clone();
106     if (r == nullptr) {
107         *err = U_MEMORY_ALLOCATION_ERROR;
108         return nullptr;
109     }
110     return reinterpret_cast<ULocale*>(r);
111 }
112 
ulocbld_buildLocaleID(ULocaleBuilder * builder,char * buffer,int32_t bufferCapacity,UErrorCode * err)113 int32_t ulocbld_buildLocaleID(ULocaleBuilder* builder,
114                               char* buffer, int32_t bufferCapacity, UErrorCode* err) {
115     if (builder == nullptr) {
116         *err = U_ILLEGAL_ARGUMENT_ERROR;
117         return 0;
118     }
119     icu::Locale l = INTERNAL(builder)->build(*err);
120     if (U_FAILURE(*err)) return 0;
121     int32_t length = (int32_t)(uprv_strlen(l.getName()));
122     if (0 < length && length <= bufferCapacity) {
123         uprv_memcpy(buffer, l.getName(), length);
124     }
125     return u_terminateChars(buffer, bufferCapacity, length, err);
126 }
127 
ulocbld_buildLanguageTag(ULocaleBuilder * builder,char * buffer,int32_t bufferCapacity,UErrorCode * err)128 int32_t ulocbld_buildLanguageTag(ULocaleBuilder* builder,
129                   char* buffer, int32_t bufferCapacity, UErrorCode* err) {
130     if (builder == nullptr) {
131         *err = U_ILLEGAL_ARGUMENT_ERROR;
132         return 0;
133     }
134     icu::Locale l = INTERNAL(builder)->build(*err);
135     if (U_FAILURE(*err)) return 0;
136     CheckedArrayByteSink sink(buffer, bufferCapacity);
137     l.toLanguageTag(sink, *err);
138     int32_t reslen = sink.NumberOfBytesAppended();
139     if (U_FAILURE(*err)) {
140         return reslen;
141     }
142     if (sink.Overflowed()) {
143         *err = U_BUFFER_OVERFLOW_ERROR;
144     } else {
145         u_terminateChars(buffer, bufferCapacity, reslen, err);
146     }
147     return reslen;
148 }
149 
ulocbld_copyErrorTo(const ULocaleBuilder * builder,UErrorCode * outErrorCode)150 UBool ulocbld_copyErrorTo(const ULocaleBuilder* builder, UErrorCode *outErrorCode) {
151     if (builder == nullptr) {
152         *outErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
153         return true;
154     }
155     return CONST_INTERNAL(builder)->copyErrorTo(*outErrorCode);
156 }
157