| File: | root/firefox-clang/intl/icu/source/common/localematcher.cpp |
| Warning: | line 711, column 12 Forming reference to null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // © 2019 and later: Unicode, Inc. and others. | |||
| 2 | // License & terms of use: http://www.unicode.org/copyright.html | |||
| 3 | ||||
| 4 | // localematcher.cpp | |||
| 5 | // created: 2019may08 Markus W. Scherer | |||
| 6 | ||||
| 7 | #include <optional> | |||
| 8 | ||||
| 9 | #include "unicode/utypes.h" | |||
| 10 | #include "unicode/localebuilder.h" | |||
| 11 | #include "unicode/localematcher.h" | |||
| 12 | #include "unicode/locid.h" | |||
| 13 | #include "unicode/stringpiece.h" | |||
| 14 | #include "unicode/uloc.h" | |||
| 15 | #include "unicode/uobject.h" | |||
| 16 | #include "cstring.h" | |||
| 17 | #include "localeprioritylist.h" | |||
| 18 | #include "loclikelysubtags.h" | |||
| 19 | #include "locdistance.h" | |||
| 20 | #include "lsr.h" | |||
| 21 | #include "uassert.h" | |||
| 22 | #include "uhash.h" | |||
| 23 | #include "ustr_imp.h" | |||
| 24 | #include "uvector.h" | |||
| 25 | ||||
| 26 | #define UND_LSRLSR("und", "", "", LSR::EXPLICIT_LSR) LSR("und", "", "", LSR::EXPLICIT_LSR) | |||
| 27 | ||||
| 28 | /** | |||
| 29 | * Indicator for the lifetime of desired-locale objects passed into the LocaleMatcher. | |||
| 30 | * | |||
| 31 | * @draft ICU 65 | |||
| 32 | */ | |||
| 33 | enum ULocMatchLifetime { | |||
| 34 | /** | |||
| 35 | * Locale objects are temporary. | |||
| 36 | * The matcher will make a copy of a locale that will be used beyond one function call. | |||
| 37 | * | |||
| 38 | * @draft ICU 65 | |||
| 39 | */ | |||
| 40 | ULOCMATCH_TEMPORARY_LOCALES, | |||
| 41 | /** | |||
| 42 | * Locale objects are stored at least as long as the matcher is used. | |||
| 43 | * The matcher will keep only a pointer to a locale that will be used beyond one function call, | |||
| 44 | * avoiding a copy. | |||
| 45 | * | |||
| 46 | * @draft ICU 65 | |||
| 47 | */ | |||
| 48 | ULOCMATCH_STORED_LOCALES // TODO: permanent? cached? clone? | |||
| 49 | }; | |||
| 50 | #ifndef U_IN_DOXYGEN | |||
| 51 | typedef enum ULocMatchLifetime ULocMatchLifetime; | |||
| 52 | #endif | |||
| 53 | ||||
| 54 | U_NAMESPACE_BEGINnamespace icu_77 { | |||
| 55 | ||||
| 56 | LocaleMatcher::Result::Result(LocaleMatcher::Result &&src) noexcept : | |||
| 57 | desiredLocale(src.desiredLocale), | |||
| 58 | supportedLocale(src.supportedLocale), | |||
| 59 | desiredIndex(src.desiredIndex), | |||
| 60 | supportedIndex(src.supportedIndex), | |||
| 61 | desiredIsOwned(src.desiredIsOwned) { | |||
| 62 | if (desiredIsOwned) { | |||
| 63 | src.desiredLocale = nullptr; | |||
| 64 | src.desiredIndex = -1; | |||
| 65 | src.desiredIsOwned = false; | |||
| 66 | } | |||
| 67 | } | |||
| 68 | ||||
| 69 | LocaleMatcher::Result::~Result() { | |||
| 70 | if (desiredIsOwned) { | |||
| 71 | delete desiredLocale; | |||
| 72 | } | |||
| 73 | } | |||
| 74 | ||||
| 75 | LocaleMatcher::Result &LocaleMatcher::Result::operator=(LocaleMatcher::Result &&src) noexcept { | |||
| 76 | this->~Result(); | |||
| 77 | ||||
| 78 | desiredLocale = src.desiredLocale; | |||
| 79 | supportedLocale = src.supportedLocale; | |||
| 80 | desiredIndex = src.desiredIndex; | |||
| 81 | supportedIndex = src.supportedIndex; | |||
| 82 | desiredIsOwned = src.desiredIsOwned; | |||
| 83 | ||||
| 84 | if (desiredIsOwned) { | |||
| 85 | src.desiredLocale = nullptr; | |||
| 86 | src.desiredIndex = -1; | |||
| 87 | src.desiredIsOwned = false; | |||
| 88 | } | |||
| 89 | return *this; | |||
| 90 | } | |||
| 91 | ||||
| 92 | Locale LocaleMatcher::Result::makeResolvedLocale(UErrorCode &errorCode) const { | |||
| 93 | if (U_FAILURE(errorCode) || supportedLocale == nullptr) { | |||
| 94 | return Locale::getRoot(); | |||
| 95 | } | |||
| 96 | const Locale *bestDesired = getDesiredLocale(); | |||
| 97 | if (bestDesired == nullptr || *supportedLocale == *bestDesired) { | |||
| 98 | return *supportedLocale; | |||
| 99 | } | |||
| 100 | LocaleBuilder b; | |||
| 101 | b.setLocale(*supportedLocale); | |||
| 102 | ||||
| 103 | // Copy the region from bestDesired, if there is one. | |||
| 104 | const char *region = bestDesired->getCountry(); | |||
| 105 | if (*region != 0) { | |||
| 106 | b.setRegion(region); | |||
| 107 | } | |||
| 108 | ||||
| 109 | // Copy the variants from bestDesired, if there are any. | |||
| 110 | // Note that this will override any supportedLocale variants. | |||
| 111 | // For example, "sco-ulster-fonipa" + "...-fonupa" => "sco-fonupa" (replacing ulster). | |||
| 112 | const char *variants = bestDesired->getVariant(); | |||
| 113 | if (*variants != 0) { | |||
| 114 | b.setVariant(variants); | |||
| 115 | } | |||
| 116 | ||||
| 117 | // Copy the extensions from bestDesired, if there are any. | |||
| 118 | // C++ note: The following note, copied from Java, may not be true, | |||
| 119 | // as long as C++ copies by legacy ICU keyword, not by extension singleton. | |||
| 120 | // Note that this will override any supportedLocale extensions. | |||
| 121 | // For example, "th-u-nu-latn-ca-buddhist" + "...-u-nu-native" => "th-u-nu-native" | |||
| 122 | // (replacing calendar). | |||
| 123 | b.copyExtensionsFrom(*bestDesired, errorCode); | |||
| 124 | return b.build(errorCode); | |||
| 125 | } | |||
| 126 | ||||
| 127 | LocaleMatcher::Builder::Builder(LocaleMatcher::Builder &&src) noexcept : | |||
| 128 | errorCode_(src.errorCode_), | |||
| 129 | supportedLocales_(src.supportedLocales_), | |||
| 130 | thresholdDistance_(src.thresholdDistance_), | |||
| 131 | demotion_(src.demotion_), | |||
| 132 | defaultLocale_(src.defaultLocale_), | |||
| 133 | withDefault_(src.withDefault_), | |||
| 134 | favor_(src.favor_), | |||
| 135 | direction_(src.direction_) { | |||
| 136 | src.supportedLocales_ = nullptr; | |||
| 137 | src.defaultLocale_ = nullptr; | |||
| 138 | } | |||
| 139 | ||||
| 140 | LocaleMatcher::Builder::~Builder() { | |||
| 141 | delete supportedLocales_; | |||
| 142 | delete defaultLocale_; | |||
| 143 | delete maxDistanceDesired_; | |||
| 144 | delete maxDistanceSupported_; | |||
| 145 | } | |||
| 146 | ||||
| 147 | LocaleMatcher::Builder &LocaleMatcher::Builder::operator=(LocaleMatcher::Builder &&src) noexcept { | |||
| 148 | this->~Builder(); | |||
| 149 | ||||
| 150 | errorCode_ = src.errorCode_; | |||
| 151 | supportedLocales_ = src.supportedLocales_; | |||
| 152 | thresholdDistance_ = src.thresholdDistance_; | |||
| 153 | demotion_ = src.demotion_; | |||
| 154 | defaultLocale_ = src.defaultLocale_; | |||
| 155 | withDefault_ = src.withDefault_, | |||
| 156 | favor_ = src.favor_; | |||
| 157 | direction_ = src.direction_; | |||
| 158 | ||||
| 159 | src.supportedLocales_ = nullptr; | |||
| 160 | src.defaultLocale_ = nullptr; | |||
| 161 | return *this; | |||
| 162 | } | |||
| 163 | ||||
| 164 | void LocaleMatcher::Builder::clearSupportedLocales() { | |||
| 165 | if (supportedLocales_ != nullptr) { | |||
| 166 | supportedLocales_->removeAllElements(); | |||
| 167 | } | |||
| 168 | } | |||
| 169 | ||||
| 170 | bool LocaleMatcher::Builder::ensureSupportedLocaleVector() { | |||
| 171 | if (U_FAILURE(errorCode_)) { return false; } | |||
| 172 | if (supportedLocales_ != nullptr) { return true; } | |||
| 173 | LocalPointer<UVector> lpSupportedLocales(new UVector(uprv_deleteUObjectuprv_deleteUObject_77, nullptr, errorCode_), errorCode_); | |||
| 174 | if (U_FAILURE(errorCode_)) { return false; } | |||
| 175 | supportedLocales_ = lpSupportedLocales.orphan(); | |||
| 176 | return true; | |||
| 177 | } | |||
| 178 | ||||
| 179 | LocaleMatcher::Builder &LocaleMatcher::Builder::setSupportedLocalesFromListString( | |||
| 180 | StringPiece locales) { | |||
| 181 | LocalePriorityList list(locales, errorCode_); | |||
| 182 | if (U_FAILURE(errorCode_)) { return *this; } | |||
| 183 | clearSupportedLocales(); | |||
| 184 | if (!ensureSupportedLocaleVector()) { return *this; } | |||
| 185 | int32_t length = list.getLengthIncludingRemoved(); | |||
| 186 | for (int32_t i = 0; i < length; ++i) { | |||
| 187 | Locale *locale = list.orphanLocaleAt(i); | |||
| 188 | if (locale == nullptr) { continue; } | |||
| 189 | supportedLocales_->adoptElement(locale, errorCode_); | |||
| 190 | if (U_FAILURE(errorCode_)) { | |||
| 191 | break; | |||
| 192 | } | |||
| 193 | } | |||
| 194 | return *this; | |||
| 195 | } | |||
| 196 | ||||
| 197 | LocaleMatcher::Builder &LocaleMatcher::Builder::setSupportedLocales(Locale::Iterator &locales) { | |||
| 198 | if (ensureSupportedLocaleVector()) { | |||
| 199 | clearSupportedLocales(); | |||
| 200 | while (locales.hasNext() && U_SUCCESS(errorCode_)) { | |||
| 201 | const Locale &locale = locales.next(); | |||
| 202 | LocalPointer<Locale> clone (locale.clone(), errorCode_); | |||
| 203 | supportedLocales_->adoptElement(clone.orphan(), errorCode_); | |||
| 204 | } | |||
| 205 | } | |||
| 206 | return *this; | |||
| 207 | } | |||
| 208 | ||||
| 209 | LocaleMatcher::Builder &LocaleMatcher::Builder::addSupportedLocale(const Locale &locale) { | |||
| 210 | if (ensureSupportedLocaleVector()) { | |||
| 211 | LocalPointer<Locale> clone(locale.clone(), errorCode_); | |||
| 212 | supportedLocales_->adoptElement(clone.orphan(), errorCode_); | |||
| 213 | } | |||
| 214 | return *this; | |||
| 215 | } | |||
| 216 | ||||
| 217 | LocaleMatcher::Builder &LocaleMatcher::Builder::setNoDefaultLocale() { | |||
| 218 | if (U_FAILURE(errorCode_)) { return *this; } | |||
| 219 | delete defaultLocale_; | |||
| 220 | defaultLocale_ = nullptr; | |||
| 221 | withDefault_ = false; | |||
| 222 | return *this; | |||
| 223 | } | |||
| 224 | ||||
| 225 | LocaleMatcher::Builder &LocaleMatcher::Builder::setDefaultLocale(const Locale *defaultLocale) { | |||
| 226 | if (U_FAILURE(errorCode_)) { return *this; } | |||
| 227 | Locale *clone = nullptr; | |||
| 228 | if (defaultLocale != nullptr) { | |||
| 229 | clone = defaultLocale->clone(); | |||
| 230 | if (clone == nullptr) { | |||
| 231 | errorCode_ = U_MEMORY_ALLOCATION_ERROR; | |||
| 232 | return *this; | |||
| 233 | } | |||
| 234 | } | |||
| 235 | delete defaultLocale_; | |||
| 236 | defaultLocale_ = clone; | |||
| 237 | withDefault_ = true; | |||
| 238 | return *this; | |||
| 239 | } | |||
| 240 | ||||
| 241 | LocaleMatcher::Builder &LocaleMatcher::Builder::setFavorSubtag(ULocMatchFavorSubtag subtag) { | |||
| 242 | if (U_FAILURE(errorCode_)) { return *this; } | |||
| 243 | favor_ = subtag; | |||
| 244 | return *this; | |||
| 245 | } | |||
| 246 | ||||
| 247 | LocaleMatcher::Builder &LocaleMatcher::Builder::setDemotionPerDesiredLocale(ULocMatchDemotion demotion) { | |||
| 248 | if (U_FAILURE(errorCode_)) { return *this; } | |||
| 249 | demotion_ = demotion; | |||
| 250 | return *this; | |||
| 251 | } | |||
| 252 | ||||
| 253 | LocaleMatcher::Builder &LocaleMatcher::Builder::setMaxDistance(const Locale &desired, | |||
| 254 | const Locale &supported) { | |||
| 255 | if (U_FAILURE(errorCode_)) { return *this; } | |||
| 256 | Locale *desiredClone = desired.clone(); | |||
| 257 | Locale *supportedClone = supported.clone(); | |||
| 258 | if (desiredClone == nullptr || supportedClone == nullptr) { | |||
| 259 | delete desiredClone; // in case only one could not be allocated | |||
| 260 | delete supportedClone; | |||
| 261 | errorCode_ = U_MEMORY_ALLOCATION_ERROR; | |||
| 262 | return *this; | |||
| 263 | } | |||
| 264 | delete maxDistanceDesired_; | |||
| 265 | delete maxDistanceSupported_; | |||
| 266 | maxDistanceDesired_ = desiredClone; | |||
| 267 | maxDistanceSupported_ = supportedClone; | |||
| 268 | return *this; | |||
| 269 | } | |||
| 270 | ||||
| 271 | #if 0 | |||
| 272 | /** | |||
| 273 | * <i>Internal only!</i> | |||
| 274 | * | |||
| 275 | * @param thresholdDistance the thresholdDistance to set, with -1 = default | |||
| 276 | * @return this Builder object | |||
| 277 | * @internal | |||
| 278 | * @deprecated This API is ICU internal only. | |||
| 279 | */ | |||
| 280 | @Deprecated | |||
| 281 | LocaleMatcher::Builder &LocaleMatcher::Builder::internalSetThresholdDistance(int32_t thresholdDistance) { | |||
| 282 | if (U_FAILURE(errorCode_)) { return *this; } | |||
| 283 | if (thresholdDistance > 100) { | |||
| 284 | thresholdDistance = 100; | |||
| 285 | } | |||
| 286 | thresholdDistance_ = thresholdDistance; | |||
| 287 | return *this; | |||
| 288 | } | |||
| 289 | #endif | |||
| 290 | ||||
| 291 | UBool LocaleMatcher::Builder::copyErrorTo(UErrorCode &outErrorCode) const { | |||
| 292 | if (U_FAILURE(outErrorCode)) { return true; } | |||
| 293 | if (U_SUCCESS(errorCode_)) { return false; } | |||
| 294 | outErrorCode = errorCode_; | |||
| 295 | return true; | |||
| 296 | } | |||
| 297 | ||||
| 298 | LocaleMatcher LocaleMatcher::Builder::build(UErrorCode &errorCode) const { | |||
| 299 | if (U_SUCCESS(errorCode) && U_FAILURE(errorCode_)) { | |||
| 300 | errorCode = errorCode_; | |||
| 301 | } | |||
| 302 | return LocaleMatcher(*this, errorCode); | |||
| 303 | } | |||
| 304 | ||||
| 305 | namespace { | |||
| 306 | ||||
| 307 | LSR getMaximalLsrOrUnd(const LikelySubtags &likelySubtags, const Locale &locale, | |||
| 308 | UErrorCode &errorCode) { | |||
| 309 | if (U_FAILURE(errorCode) || locale.isBogus() || *locale.getName() == 0 /* "und" */) { | |||
| 310 | return UND_LSRLSR("und", "", "", LSR::EXPLICIT_LSR); | |||
| 311 | } else { | |||
| 312 | return likelySubtags.makeMaximizedLsrFrom(locale, false, errorCode); | |||
| 313 | } | |||
| 314 | } | |||
| 315 | ||||
| 316 | int32_t hashLSR(const UHashTok token) { | |||
| 317 | const LSR *lsr = static_cast<const LSR *>(token.pointer); | |||
| 318 | return lsr->hashCode; | |||
| 319 | } | |||
| 320 | ||||
| 321 | UBool compareLSRs(const UHashTok t1, const UHashTok t2) { | |||
| 322 | const LSR *lsr1 = static_cast<const LSR *>(t1.pointer); | |||
| 323 | const LSR *lsr2 = static_cast<const LSR *>(t2.pointer); | |||
| 324 | return *lsr1 == *lsr2; | |||
| 325 | } | |||
| 326 | ||||
| 327 | } // namespace | |||
| 328 | ||||
| 329 | int32_t LocaleMatcher::putIfAbsent(const LSR &lsr, int32_t i, int32_t suppLength, | |||
| 330 | UErrorCode &errorCode) { | |||
| 331 | if (U_FAILURE(errorCode)) { return suppLength; } | |||
| 332 | if (!uhash_containsKeyuhash_containsKey_77(supportedLsrToIndex, &lsr)) { | |||
| 333 | uhash_putiAllowZerouhash_putiAllowZero_77(supportedLsrToIndex, const_cast<LSR *>(&lsr), i, &errorCode); | |||
| 334 | if (U_SUCCESS(errorCode)) { | |||
| 335 | supportedLSRs[suppLength] = &lsr; | |||
| 336 | supportedIndexes[suppLength++] = i; | |||
| 337 | } | |||
| 338 | } | |||
| 339 | return suppLength; | |||
| 340 | } | |||
| 341 | ||||
| 342 | LocaleMatcher::LocaleMatcher(const Builder &builder, UErrorCode &errorCode) : | |||
| 343 | likelySubtags(*LikelySubtags::getSingleton(errorCode)), | |||
| 344 | localeDistance(*LocaleDistance::getSingleton(errorCode)), | |||
| 345 | thresholdDistance(builder.thresholdDistance_), | |||
| 346 | demotionPerDesiredLocale(0), | |||
| 347 | favorSubtag(builder.favor_), | |||
| 348 | direction(builder.direction_), | |||
| 349 | supportedLocales(nullptr), lsrs(nullptr), supportedLocalesLength(0), | |||
| 350 | supportedLsrToIndex(nullptr), | |||
| 351 | supportedLSRs(nullptr), supportedIndexes(nullptr), supportedLSRsLength(0), | |||
| 352 | ownedDefaultLocale(nullptr), defaultLocale(nullptr) { | |||
| 353 | if (U_FAILURE(errorCode)) { return; } | |||
| 354 | const Locale *def = builder.defaultLocale_; | |||
| 355 | LSR builderDefaultLSR; | |||
| 356 | const LSR *defLSR = nullptr; | |||
| 357 | if (def != nullptr) { | |||
| 358 | ownedDefaultLocale = def->clone(); | |||
| 359 | if (ownedDefaultLocale == nullptr) { | |||
| 360 | errorCode = U_MEMORY_ALLOCATION_ERROR; | |||
| 361 | return; | |||
| 362 | } | |||
| 363 | def = ownedDefaultLocale; | |||
| 364 | builderDefaultLSR = getMaximalLsrOrUnd(likelySubtags, *def, errorCode); | |||
| 365 | if (U_FAILURE(errorCode)) { return; } | |||
| 366 | defLSR = &builderDefaultLSR; | |||
| 367 | } | |||
| 368 | supportedLocalesLength = builder.supportedLocales_ != nullptr ? | |||
| 369 | builder.supportedLocales_->size() : 0; | |||
| 370 | if (supportedLocalesLength
| |||
| 371 | // Store the supported locales in input order, | |||
| 372 | // so that when different types are used (e.g., language tag strings) | |||
| 373 | // we can return those by parallel index. | |||
| 374 | supportedLocales = static_cast<const Locale **>( | |||
| 375 | uprv_mallocuprv_malloc_77(supportedLocalesLength * sizeof(const Locale *))); | |||
| 376 | // Supported LRSs in input order. | |||
| 377 | // In C++, we store these permanently to simplify ownership management | |||
| 378 | // in the hash tables. Duplicate LSRs (if any) are unused overhead. | |||
| 379 | lsrs = new LSR[supportedLocalesLength]; | |||
| 380 | if (supportedLocales == nullptr || lsrs == nullptr) { | |||
| 381 | errorCode = U_MEMORY_ALLOCATION_ERROR; | |||
| 382 | return; | |||
| 383 | } | |||
| 384 | // If the constructor fails partway, we need null pointers for destructibility. | |||
| 385 | uprv_memset(supportedLocales, 0, supportedLocalesLength * sizeof(const Locale *)):: memset(supportedLocales, 0, supportedLocalesLength * sizeof (const Locale *)); | |||
| 386 | for (int32_t i = 0; i < supportedLocalesLength; ++i) { | |||
| 387 | const Locale &locale = *static_cast<Locale *>(builder.supportedLocales_->elementAt(i)); | |||
| 388 | supportedLocales[i] = locale.clone(); | |||
| 389 | if (supportedLocales[i] == nullptr) { | |||
| 390 | errorCode = U_MEMORY_ALLOCATION_ERROR; | |||
| 391 | return; | |||
| 392 | } | |||
| 393 | const Locale &supportedLocale = *supportedLocales[i]; | |||
| 394 | LSR &lsr = lsrs[i] = getMaximalLsrOrUnd(likelySubtags, supportedLocale, errorCode); | |||
| 395 | lsr.setHashCode(); | |||
| 396 | if (U_FAILURE(errorCode)) { return; } | |||
| 397 | } | |||
| 398 | ||||
| 399 | // We need an unordered map from LSR to first supported locale with that LSR, | |||
| 400 | // and an ordered list of (LSR, supported index) for | |||
| 401 | // the supported locales in the following order: | |||
| 402 | // 1. Default locale, if it is supported. | |||
| 403 | // 2. Priority locales (aka "paradigm locales") in builder order. | |||
| 404 | // 3. Remaining locales in builder order. | |||
| 405 | supportedLsrToIndex = uhash_openSizeuhash_openSize_77(hashLSR, compareLSRs, uhash_compareLonguhash_compareLong_77, | |||
| 406 | supportedLocalesLength, &errorCode); | |||
| 407 | if (U_FAILURE(errorCode)) { return; } | |||
| 408 | supportedLSRs = static_cast<const LSR **>( | |||
| 409 | uprv_mallocuprv_malloc_77(supportedLocalesLength * sizeof(const LSR *))); | |||
| 410 | supportedIndexes = static_cast<int32_t *>( | |||
| 411 | uprv_mallocuprv_malloc_77(supportedLocalesLength * sizeof(int32_t))); | |||
| 412 | if (supportedLSRs == nullptr || supportedIndexes == nullptr) { | |||
| 413 | errorCode = U_MEMORY_ALLOCATION_ERROR; | |||
| 414 | return; | |||
| 415 | } | |||
| 416 | int32_t suppLength = 0; | |||
| 417 | // Determine insertion order. | |||
| 418 | // Add locales immediately that are equivalent to the default. | |||
| 419 | MaybeStackArray<int8_t, 100> order(supportedLocalesLength, errorCode); | |||
| 420 | if (U_FAILURE(errorCode)) { return; } | |||
| 421 | int32_t numParadigms = 0; | |||
| 422 | for (int32_t i = 0; i < supportedLocalesLength; ++i) { | |||
| 423 | const Locale &locale = *supportedLocales[i]; | |||
| 424 | const LSR &lsr = lsrs[i]; | |||
| 425 | if (defLSR == nullptr && builder.withDefault_) { | |||
| 426 | // Implicit default locale = first supported locale, if not turned off. | |||
| 427 | U_ASSERT(i == 0)(static_cast <bool> (i == 0) ? void (0) : __assert_fail ("i == 0", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | |||
| 428 | def = &locale; | |||
| 429 | defLSR = &lsr; | |||
| 430 | order[i] = 1; | |||
| 431 | suppLength = putIfAbsent(lsr, 0, suppLength, errorCode); | |||
| 432 | } else if (defLSR != nullptr && lsr.isEquivalentTo(*defLSR)) { | |||
| 433 | order[i] = 1; | |||
| 434 | suppLength = putIfAbsent(lsr, i, suppLength, errorCode); | |||
| 435 | } else if (localeDistance.isParadigmLSR(lsr)) { | |||
| 436 | order[i] = 2; | |||
| 437 | ++numParadigms; | |||
| 438 | } else { | |||
| 439 | order[i] = 3; | |||
| 440 | } | |||
| 441 | if (U_FAILURE(errorCode)) { return; } | |||
| 442 | } | |||
| 443 | // Add supported paradigm locales. | |||
| 444 | int32_t paradigmLimit = suppLength + numParadigms; | |||
| 445 | for (int32_t i = 0; i < supportedLocalesLength && suppLength < paradigmLimit; ++i) { | |||
| 446 | if (order[i] == 2) { | |||
| 447 | suppLength = putIfAbsent(lsrs[i], i, suppLength, errorCode); | |||
| 448 | } | |||
| 449 | } | |||
| 450 | // Add remaining supported locales. | |||
| 451 | for (int32_t i = 0; i < supportedLocalesLength; ++i) { | |||
| 452 | if (order[i] == 3) { | |||
| 453 | suppLength = putIfAbsent(lsrs[i], i, suppLength, errorCode); | |||
| 454 | } | |||
| 455 | } | |||
| 456 | supportedLSRsLength = suppLength; | |||
| 457 | // If supportedLSRsLength < supportedLocalesLength then | |||
| 458 | // we waste as many array slots as there are duplicate supported LSRs, | |||
| 459 | // but the amount of wasted space is small as long as there are few duplicates. | |||
| 460 | } | |||
| 461 | ||||
| 462 | defaultLocale = def; | |||
| 463 | ||||
| 464 | if (builder.demotion_
| |||
| 465 | demotionPerDesiredLocale = localeDistance.getDefaultDemotionPerDesiredLocale(); | |||
| 466 | } | |||
| 467 | ||||
| 468 | if (thresholdDistance
| |||
| 469 | // already copied | |||
| 470 | } else if (builder.maxDistanceDesired_ != nullptr) { | |||
| 471 | LSR suppLSR = getMaximalLsrOrUnd(likelySubtags, *builder.maxDistanceSupported_, errorCode); | |||
| 472 | const LSR *pSuppLSR = &suppLSR; | |||
| 473 | int32_t indexAndDistance = localeDistance.getBestIndexAndDistance( | |||
| 474 | getMaximalLsrOrUnd(likelySubtags, *builder.maxDistanceDesired_, errorCode), | |||
| 475 | &pSuppLSR, 1, | |||
| 476 | LocaleDistance::shiftDistance(100), favorSubtag, direction); | |||
| 477 | if (U_SUCCESS(errorCode)) { | |||
| 478 | // +1 for an exclusive threshold from an inclusive max. | |||
| 479 | thresholdDistance = LocaleDistance::getDistanceFloor(indexAndDistance) + 1; | |||
| 480 | } else { | |||
| 481 | thresholdDistance = 0; | |||
| 482 | } | |||
| 483 | } else { | |||
| 484 | thresholdDistance = localeDistance.getDefaultScriptDistance(); | |||
| 485 | } | |||
| 486 | } | |||
| 487 | ||||
| 488 | LocaleMatcher::LocaleMatcher(LocaleMatcher &&src) noexcept : | |||
| 489 | likelySubtags(src.likelySubtags), | |||
| 490 | localeDistance(src.localeDistance), | |||
| 491 | thresholdDistance(src.thresholdDistance), | |||
| 492 | demotionPerDesiredLocale(src.demotionPerDesiredLocale), | |||
| 493 | favorSubtag(src.favorSubtag), | |||
| 494 | direction(src.direction), | |||
| 495 | supportedLocales(src.supportedLocales), lsrs(src.lsrs), | |||
| 496 | supportedLocalesLength(src.supportedLocalesLength), | |||
| 497 | supportedLsrToIndex(src.supportedLsrToIndex), | |||
| 498 | supportedLSRs(src.supportedLSRs), | |||
| 499 | supportedIndexes(src.supportedIndexes), | |||
| 500 | supportedLSRsLength(src.supportedLSRsLength), | |||
| 501 | ownedDefaultLocale(src.ownedDefaultLocale), defaultLocale(src.defaultLocale) { | |||
| 502 | src.supportedLocales = nullptr; | |||
| 503 | src.lsrs = nullptr; | |||
| 504 | src.supportedLocalesLength = 0; | |||
| 505 | src.supportedLsrToIndex = nullptr; | |||
| 506 | src.supportedLSRs = nullptr; | |||
| 507 | src.supportedIndexes = nullptr; | |||
| 508 | src.supportedLSRsLength = 0; | |||
| 509 | src.ownedDefaultLocale = nullptr; | |||
| 510 | src.defaultLocale = nullptr; | |||
| 511 | } | |||
| 512 | ||||
| 513 | LocaleMatcher::~LocaleMatcher() { | |||
| 514 | for (int32_t i = 0; i < supportedLocalesLength; ++i) { | |||
| 515 | delete supportedLocales[i]; | |||
| 516 | } | |||
| 517 | uprv_freeuprv_free_77(supportedLocales); | |||
| 518 | delete[] lsrs; | |||
| 519 | uhash_closeuhash_close_77(supportedLsrToIndex); | |||
| 520 | uprv_freeuprv_free_77(supportedLSRs); | |||
| 521 | uprv_freeuprv_free_77(supportedIndexes); | |||
| 522 | delete ownedDefaultLocale; | |||
| 523 | } | |||
| 524 | ||||
| 525 | LocaleMatcher &LocaleMatcher::operator=(LocaleMatcher &&src) noexcept { | |||
| 526 | this->~LocaleMatcher(); | |||
| 527 | ||||
| 528 | thresholdDistance = src.thresholdDistance; | |||
| 529 | demotionPerDesiredLocale = src.demotionPerDesiredLocale; | |||
| 530 | favorSubtag = src.favorSubtag; | |||
| 531 | direction = src.direction; | |||
| 532 | supportedLocales = src.supportedLocales; | |||
| 533 | lsrs = src.lsrs; | |||
| 534 | supportedLocalesLength = src.supportedLocalesLength; | |||
| 535 | supportedLsrToIndex = src.supportedLsrToIndex; | |||
| 536 | supportedLSRs = src.supportedLSRs; | |||
| 537 | supportedIndexes = src.supportedIndexes; | |||
| 538 | supportedLSRsLength = src.supportedLSRsLength; | |||
| 539 | ownedDefaultLocale = src.ownedDefaultLocale; | |||
| 540 | defaultLocale = src.defaultLocale; | |||
| 541 | ||||
| 542 | src.supportedLocales = nullptr; | |||
| 543 | src.lsrs = nullptr; | |||
| 544 | src.supportedLocalesLength = 0; | |||
| 545 | src.supportedLsrToIndex = nullptr; | |||
| 546 | src.supportedLSRs = nullptr; | |||
| 547 | src.supportedIndexes = nullptr; | |||
| 548 | src.supportedLSRsLength = 0; | |||
| 549 | src.ownedDefaultLocale = nullptr; | |||
| 550 | src.defaultLocale = nullptr; | |||
| 551 | return *this; | |||
| 552 | } | |||
| 553 | ||||
| 554 | class LocaleLsrIterator { | |||
| 555 | public: | |||
| 556 | LocaleLsrIterator(const LikelySubtags &likelySubtags, Locale::Iterator &locales, | |||
| 557 | ULocMatchLifetime lifetime) : | |||
| 558 | likelySubtags(likelySubtags), locales(locales), lifetime(lifetime) {} | |||
| 559 | ||||
| 560 | ~LocaleLsrIterator() { | |||
| 561 | if (lifetime == ULOCMATCH_TEMPORARY_LOCALES) { | |||
| 562 | delete remembered; | |||
| 563 | } | |||
| 564 | } | |||
| 565 | ||||
| 566 | bool hasNext() const { | |||
| 567 | return locales.hasNext(); | |||
| 568 | } | |||
| 569 | ||||
| 570 | LSR next(UErrorCode &errorCode) { | |||
| 571 | current = &locales.next(); | |||
| 572 | return getMaximalLsrOrUnd(likelySubtags, *current, errorCode); | |||
| 573 | } | |||
| 574 | ||||
| 575 | void rememberCurrent(int32_t desiredIndex, UErrorCode &errorCode) { | |||
| 576 | if (U_FAILURE(errorCode)) { return; } | |||
| 577 | bestDesiredIndex = desiredIndex; | |||
| 578 | if (lifetime == ULOCMATCH_STORED_LOCALES) { | |||
| 579 | remembered = current; | |||
| 580 | } else { | |||
| 581 | // ULOCMATCH_TEMPORARY_LOCALES | |||
| 582 | delete remembered; | |||
| 583 | remembered = new Locale(*current); | |||
| 584 | if (remembered == nullptr) { | |||
| 585 | errorCode = U_MEMORY_ALLOCATION_ERROR; | |||
| 586 | } | |||
| 587 | } | |||
| 588 | } | |||
| 589 | ||||
| 590 | const Locale *orphanRemembered() { | |||
| 591 | const Locale *rem = remembered; | |||
| 592 | remembered = nullptr; | |||
| 593 | return rem; | |||
| 594 | } | |||
| 595 | ||||
| 596 | int32_t getBestDesiredIndex() const { | |||
| 597 | return bestDesiredIndex; | |||
| 598 | } | |||
| 599 | ||||
| 600 | private: | |||
| 601 | const LikelySubtags &likelySubtags; | |||
| 602 | Locale::Iterator &locales; | |||
| 603 | ULocMatchLifetime lifetime; | |||
| 604 | const Locale *current = nullptr, *remembered = nullptr; | |||
| 605 | int32_t bestDesiredIndex = -1; | |||
| 606 | }; | |||
| 607 | ||||
| 608 | const Locale *LocaleMatcher::getBestMatch(const Locale &desiredLocale, UErrorCode &errorCode) const { | |||
| 609 | if (U_FAILURE(errorCode)) { return nullptr; } | |||
| 610 | std::optional<int32_t> suppIndex = getBestSuppIndex( | |||
| 611 | getMaximalLsrOrUnd(likelySubtags, desiredLocale, errorCode), | |||
| 612 | nullptr, errorCode); | |||
| 613 | return U_SUCCESS(errorCode) && suppIndex.has_value() ? supportedLocales[*suppIndex] | |||
| 614 | : defaultLocale; | |||
| 615 | } | |||
| 616 | ||||
| 617 | const Locale *LocaleMatcher::getBestMatch(Locale::Iterator &desiredLocales, | |||
| 618 | UErrorCode &errorCode) const { | |||
| 619 | if (U_FAILURE(errorCode)) { return nullptr; } | |||
| 620 | if (!desiredLocales.hasNext()) { | |||
| 621 | return defaultLocale; | |||
| 622 | } | |||
| 623 | LocaleLsrIterator lsrIter(likelySubtags, desiredLocales, ULOCMATCH_TEMPORARY_LOCALES); | |||
| 624 | std::optional<int32_t> suppIndex = getBestSuppIndex(lsrIter.next(errorCode), &lsrIter, errorCode); | |||
| 625 | return U_SUCCESS(errorCode) && suppIndex.has_value() ? supportedLocales[*suppIndex] | |||
| 626 | : defaultLocale; | |||
| 627 | } | |||
| 628 | ||||
| 629 | const Locale *LocaleMatcher::getBestMatchForListString( | |||
| 630 | StringPiece desiredLocaleList, UErrorCode &errorCode) const { | |||
| 631 | if (U_FAILURE(errorCode)) { return nullptr; } | |||
| 632 | LocalePriorityList list(desiredLocaleList, errorCode); | |||
| 633 | LocalePriorityList::Iterator iter = list.iterator(); | |||
| 634 | return getBestMatch(iter, errorCode); | |||
| 635 | } | |||
| 636 | ||||
| 637 | LocaleMatcher::Result LocaleMatcher::getBestMatchResult( | |||
| 638 | const Locale &desiredLocale, UErrorCode &errorCode) const { | |||
| 639 | if (U_FAILURE(errorCode)) { | |||
| 640 | return Result(nullptr, defaultLocale, -1, -1, false); | |||
| 641 | } | |||
| 642 | std::optional<int32_t> suppIndex = getBestSuppIndex( | |||
| 643 | getMaximalLsrOrUnd(likelySubtags, desiredLocale, errorCode), | |||
| 644 | nullptr, errorCode); | |||
| 645 | if (U_FAILURE(errorCode) || !suppIndex.has_value()) { | |||
| 646 | return Result(nullptr, defaultLocale, -1, -1, false); | |||
| 647 | } else { | |||
| 648 | return Result(&desiredLocale, supportedLocales[*suppIndex], 0, *suppIndex, false); | |||
| 649 | } | |||
| 650 | } | |||
| 651 | ||||
| 652 | LocaleMatcher::Result LocaleMatcher::getBestMatchResult( | |||
| 653 | Locale::Iterator &desiredLocales, UErrorCode &errorCode) const { | |||
| 654 | if (U_FAILURE(errorCode) || !desiredLocales.hasNext()) { | |||
| 655 | return Result(nullptr, defaultLocale, -1, -1, false); | |||
| 656 | } | |||
| 657 | LocaleLsrIterator lsrIter(likelySubtags, desiredLocales, ULOCMATCH_TEMPORARY_LOCALES); | |||
| 658 | std::optional<int32_t> suppIndex = getBestSuppIndex(lsrIter.next(errorCode), &lsrIter, errorCode); | |||
| 659 | if (U_FAILURE(errorCode) || !suppIndex.has_value()) { | |||
| 660 | return Result(nullptr, defaultLocale, -1, -1, false); | |||
| 661 | } else { | |||
| 662 | return Result(lsrIter.orphanRemembered(), supportedLocales[*suppIndex], | |||
| 663 | lsrIter.getBestDesiredIndex(), *suppIndex, true); | |||
| 664 | } | |||
| 665 | } | |||
| 666 | ||||
| 667 | std::optional<int32_t> LocaleMatcher::getBestSuppIndex(LSR desiredLSR, | |||
| 668 | LocaleLsrIterator *remainingIter, | |||
| 669 | UErrorCode &errorCode) const { | |||
| 670 | if (U_FAILURE(errorCode)) { return std::nullopt; } | |||
| 671 | int32_t desiredIndex = 0; | |||
| 672 | int32_t bestSupportedLsrIndex = -1; | |||
| 673 | for (int32_t bestShiftedDistance = LocaleDistance::shiftDistance(thresholdDistance);;) { | |||
| 674 | // Quick check for exact maximized LSR. | |||
| 675 | if (supportedLsrToIndex != nullptr) { | |||
| 676 | desiredLSR.setHashCode(); | |||
| 677 | UBool found = false; | |||
| 678 | int32_t suppIndex = uhash_getiAndFounduhash_getiAndFound_77(supportedLsrToIndex, &desiredLSR, &found); | |||
| 679 | if (found) { | |||
| 680 | if (remainingIter != nullptr) { | |||
| 681 | remainingIter->rememberCurrent(desiredIndex, errorCode); | |||
| 682 | } | |||
| 683 | return suppIndex; | |||
| 684 | } | |||
| 685 | } | |||
| 686 | int32_t bestIndexAndDistance = localeDistance.getBestIndexAndDistance( | |||
| 687 | desiredLSR, supportedLSRs, supportedLSRsLength, | |||
| 688 | bestShiftedDistance, favorSubtag, direction); | |||
| 689 | if (bestIndexAndDistance >= 0) { | |||
| 690 | bestShiftedDistance = LocaleDistance::getShiftedDistance(bestIndexAndDistance); | |||
| 691 | if (remainingIter != nullptr) { | |||
| 692 | remainingIter->rememberCurrent(desiredIndex, errorCode); | |||
| 693 | if (U_FAILURE(errorCode)) { return std::nullopt; } | |||
| 694 | } | |||
| 695 | bestSupportedLsrIndex = LocaleDistance::getIndex(bestIndexAndDistance); | |||
| 696 | } | |||
| 697 | if ((bestShiftedDistance -= LocaleDistance::shiftDistance(demotionPerDesiredLocale)) <= 0) { | |||
| 698 | break; | |||
| 699 | } | |||
| 700 | if (remainingIter == nullptr || !remainingIter->hasNext()) { | |||
| 701 | break; | |||
| 702 | } | |||
| 703 | desiredLSR = remainingIter->next(errorCode); | |||
| 704 | if (U_FAILURE(errorCode)) { return std::nullopt; } | |||
| 705 | ++desiredIndex; | |||
| 706 | } | |||
| 707 | if (bestSupportedLsrIndex < 0) { | |||
| 708 | // no good match | |||
| 709 | return std::nullopt; | |||
| 710 | } | |||
| 711 | return supportedIndexes[bestSupportedLsrIndex]; | |||
| ||||
| 712 | } | |||
| 713 | ||||
| 714 | UBool LocaleMatcher::isMatch(const Locale &desired, const Locale &supported, | |||
| 715 | UErrorCode &errorCode) const { | |||
| 716 | if (U_FAILURE(errorCode)) { return false; } | |||
| 717 | LSR suppLSR = getMaximalLsrOrUnd(likelySubtags, supported, errorCode); | |||
| 718 | if (U_FAILURE(errorCode)) { return false; } | |||
| 719 | const LSR *pSuppLSR = &suppLSR; | |||
| 720 | int32_t indexAndDistance = localeDistance.getBestIndexAndDistance( | |||
| 721 | getMaximalLsrOrUnd(likelySubtags, desired, errorCode), | |||
| 722 | &pSuppLSR, 1, | |||
| 723 | LocaleDistance::shiftDistance(thresholdDistance), favorSubtag, direction); | |||
| 724 | return indexAndDistance >= 0; | |||
| 725 | } | |||
| 726 | ||||
| 727 | double LocaleMatcher::internalMatch(const Locale &desired, const Locale &supported, UErrorCode &errorCode) const { | |||
| 728 | if (U_FAILURE(errorCode)) { return 0.; } | |||
| 729 | // Returns the inverse of the distance: That is, 1-distance(desired, supported). | |||
| 730 | LSR suppLSR = getMaximalLsrOrUnd(likelySubtags, supported, errorCode); | |||
| 731 | if (U_FAILURE(errorCode)) { return 0.; } | |||
| 732 | const LSR *pSuppLSR = &suppLSR; | |||
| 733 | int32_t indexAndDistance = localeDistance.getBestIndexAndDistance( | |||
| 734 | getMaximalLsrOrUnd(likelySubtags, desired, errorCode), | |||
| 735 | &pSuppLSR, 1, | |||
| 736 | LocaleDistance::shiftDistance(thresholdDistance), favorSubtag, direction); | |||
| 737 | double distance = LocaleDistance::getDistanceDouble(indexAndDistance); | |||
| 738 | return (100.0 - distance) / 100.0; | |||
| 739 | } | |||
| 740 | ||||
| 741 | U_NAMESPACE_END} | |||
| 742 | ||||
| 743 | // uloc_acceptLanguage() --------------------------------------------------- *** | |||
| 744 | ||||
| 745 | U_NAMESPACE_USEusing namespace icu_77; | |||
| 746 | ||||
| 747 | namespace { | |||
| 748 | ||||
| 749 | class LocaleFromTag { | |||
| 750 | public: | |||
| 751 | LocaleFromTag() : locale(Locale::getRoot()) {} | |||
| 752 | const Locale &operator()(const char *tag) { return locale = Locale(tag); } | |||
| 753 | ||||
| 754 | private: | |||
| 755 | // Store the locale in the converter, rather than return a reference to a temporary, | |||
| 756 | // or a value which could go out of scope with the caller's reference to it. | |||
| 757 | Locale locale; | |||
| 758 | }; | |||
| 759 | ||||
| 760 | int32_t acceptLanguage(UEnumeration &supportedLocales, Locale::Iterator &desiredLocales, | |||
| 761 | char *dest, int32_t capacity, UAcceptResult *acceptResult, | |||
| 762 | UErrorCode &errorCode) { | |||
| 763 | if (U_FAILURE(errorCode)) { return 0; } | |||
| 764 | LocaleMatcher::Builder builder; | |||
| 765 | const char *locString; | |||
| 766 | while ((locString = uenum_nextuenum_next_77(&supportedLocales, nullptr, &errorCode)) != nullptr) { | |||
| 767 | Locale loc(locString); | |||
| 768 | if (loc.isBogus()) { | |||
| 769 | errorCode = U_ILLEGAL_ARGUMENT_ERROR; | |||
| 770 | return 0; | |||
| 771 | } | |||
| 772 | builder.addSupportedLocale(loc); | |||
| 773 | } | |||
| 774 | LocaleMatcher matcher = builder.build(errorCode); | |||
| 775 | LocaleMatcher::Result result = matcher.getBestMatchResult(desiredLocales, errorCode); | |||
| 776 | if (U_FAILURE(errorCode)) { return 0; } | |||
| 777 | if (result.getDesiredIndex() >= 0) { | |||
| 778 | if (acceptResult != nullptr) { | |||
| 779 | *acceptResult = *result.getDesiredLocale() == *result.getSupportedLocale() ? | |||
| 780 | ULOC_ACCEPT_VALID : ULOC_ACCEPT_FALLBACK; | |||
| 781 | } | |||
| 782 | const char *bestStr = result.getSupportedLocale()->getName(); | |||
| 783 | int32_t bestLength = static_cast<int32_t>(uprv_strlen(bestStr):: strlen(bestStr)); | |||
| 784 | if (bestLength <= capacity) { | |||
| 785 | uprv_memcpy(dest, bestStr, bestLength)do { clang diagnostic push
clang diagnostic ignored "-Waddress" (static_cast <bool> (dest != __null) ? void (0) : __assert_fail ("dest != __null", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); (static_cast <bool> (bestStr != __null) ? void (0) : __assert_fail ("bestStr != __null", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); clang diagnostic pop :: memcpy(dest, bestStr, bestLength); } while (false); | |||
| 786 | } | |||
| 787 | return u_terminateCharsu_terminateChars_77(dest, capacity, bestLength, &errorCode); | |||
| 788 | } else { | |||
| 789 | if (acceptResult != nullptr) { | |||
| 790 | *acceptResult = ULOC_ACCEPT_FAILED; | |||
| 791 | } | |||
| 792 | return u_terminateCharsu_terminateChars_77(dest, capacity, 0, &errorCode); | |||
| 793 | } | |||
| 794 | } | |||
| 795 | ||||
| 796 | } // namespace | |||
| 797 | ||||
| 798 | U_CAPIextern "C" int32_t U_EXPORT2 | |||
| 799 | uloc_acceptLanguageuloc_acceptLanguage_77(char *result, int32_t resultAvailable, | |||
| 800 | UAcceptResult *outResult, | |||
| 801 | const char **acceptList, int32_t acceptListCount, | |||
| 802 | UEnumeration *availableLocales, | |||
| 803 | UErrorCode *status) { | |||
| 804 | if (U_FAILURE(*status)) { return 0; } | |||
| 805 | if ((result == nullptr ? resultAvailable != 0 : resultAvailable < 0) || | |||
| 806 | (acceptList == nullptr ? acceptListCount != 0 : acceptListCount < 0) || | |||
| 807 | availableLocales == nullptr) { | |||
| 808 | *status = U_ILLEGAL_ARGUMENT_ERROR; | |||
| 809 | return 0; | |||
| 810 | } | |||
| 811 | LocaleFromTag converter; | |||
| 812 | Locale::ConvertingIterator<const char **, LocaleFromTag> desiredLocales( | |||
| 813 | acceptList, acceptList + acceptListCount, converter); | |||
| 814 | return acceptLanguage(*availableLocales, desiredLocales, | |||
| 815 | result, resultAvailable, outResult, *status); | |||
| 816 | } | |||
| 817 | ||||
| 818 | U_CAPIextern "C" int32_t U_EXPORT2 | |||
| 819 | uloc_acceptLanguageFromHTTPuloc_acceptLanguageFromHTTP_77(char *result, int32_t resultAvailable, | |||
| 820 | UAcceptResult *outResult, | |||
| 821 | const char *httpAcceptLanguage, | |||
| 822 | UEnumeration *availableLocales, | |||
| 823 | UErrorCode *status) { | |||
| 824 | if (U_FAILURE(*status)) { return 0; } | |||
| 825 | if ((result == nullptr ? resultAvailable != 0 : resultAvailable < 0) || | |||
| ||||
| 826 | httpAcceptLanguage == nullptr || availableLocales == nullptr) { | |||
| 827 | *status = U_ILLEGAL_ARGUMENT_ERROR; | |||
| 828 | return 0; | |||
| 829 | } | |||
| 830 | LocalePriorityList list(httpAcceptLanguage, *status); | |||
| 831 | LocalePriorityList::Iterator desiredLocales = list.iterator(); | |||
| 832 | return acceptLanguage(*availableLocales, desiredLocales, | |||
| 833 | result, resultAvailable, outResult, *status); | |||
| 834 | } |