U_CDECL_END /* do not close UCA returned by ucol_initUCA! */ UCollator * ucol_initUCA(UErrorCode *status) { if(U_FAILURE(*status)) { return NULL; } UBool needsInit; UMTX_CHECK(NULL, (_staticUCA == NULL), needsInit); if(needsInit) { UDataMemory *result = udata_openChoice(U_ICUDATA_COLL, UCA_DATA_TYPE, UCA_DATA_NAME, isAcceptableUCA, NULL, status); if(U_SUCCESS(*status)){ UCollator *newUCA = ucol_initCollator((const UCATableHeader *)udata_getMemory(result), NULL, NULL, status); if(U_SUCCESS(*status)){ // Initalize variables for implicit generation uprv_uca_initImplicitConstants(status); umtx_lock(NULL); if(_staticUCA == NULL) { UCA_DATA_MEM = result; _staticUCA = newUCA; newUCA = NULL; result = NULL; } umtx_unlock(NULL); ucln_i18n_registerCleanup(UCLN_I18N_UCOL_RES, ucol_res_cleanup); if(newUCA != NULL) { ucol_close(newUCA); udata_close(result); } }else{ ucol_close(newUCA); udata_close(result); } } else { udata_close(result); } } return _staticUCA; }
U_CFUNC UCollator* ucol_open_internal(const char *loc, UErrorCode *status) { const UCollator* UCA = ucol_initUCA(status); /* New version */ if(U_FAILURE(*status)) return 0; UCollator *result = NULL; UResourceBundle *b = ures_open(U_ICUDATA_COLL, loc, status); /* we try to find stuff from keyword */ UResourceBundle *collations = ures_getByKey(b, "collations", NULL, status); UResourceBundle *collElem = NULL; char keyBuffer[256]; // if there is a keyword, we pick it up and try to get elements if(!uloc_getKeywordValue(loc, "collation", keyBuffer, 256, status)) { // no keyword. we try to find the default setting, which will give us the keyword value UErrorCode intStatus = U_ZERO_ERROR; // finding default value does not affect collation fallback status UResourceBundle *defaultColl = ures_getByKeyWithFallback(collations, "default", NULL, &intStatus); if(U_SUCCESS(intStatus)) { int32_t defaultKeyLen = 0; const UChar *defaultKey = ures_getString(defaultColl, &defaultKeyLen, &intStatus); u_UCharsToChars(defaultKey, keyBuffer, defaultKeyLen); keyBuffer[defaultKeyLen] = 0; } else { *status = U_INTERNAL_PROGRAM_ERROR; return NULL; } ures_close(defaultColl); } collElem = ures_getByKeyWithFallback(collations, keyBuffer, collElem, status); UResourceBundle *binary = NULL; if(*status == U_MISSING_RESOURCE_ERROR) { /* We didn't find the tailoring data, we fallback to the UCA */ *status = U_USING_DEFAULT_WARNING; result = ucol_initCollator(UCA->image, result, UCA, status); // if we use UCA, real locale is root result->rb = ures_open(U_ICUDATA_COLL, "", status); result->elements = ures_open(U_ICUDATA_COLL, "", status); if(U_FAILURE(*status)) { goto clean; } ures_close(b); result->hasRealData = FALSE; } else if(U_SUCCESS(*status)) { int32_t len = 0; UErrorCode binaryStatus = U_ZERO_ERROR; binary = ures_getByKey(collElem, "%%CollationBin", NULL, &binaryStatus); if(binaryStatus == U_MISSING_RESOURCE_ERROR) { /* we didn't find the binary image, we should use the rules */ binary = NULL; result = tryOpeningFromRules(collElem, status); if(U_FAILURE(*status)) { goto clean; } } else if(U_SUCCESS(*status)) { /* otherwise, we'll pick a collation data that exists */ const uint8_t *inData = ures_getBinary(binary, &len, status); UCATableHeader *colData = (UCATableHeader *)inData; if(uprv_memcmp(colData->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo)) != 0 || uprv_memcmp(colData->UCDVersion, UCA->image->UCDVersion, sizeof(UVersionInfo)) != 0 || colData->version[0] != UCOL_BUILDER_VERSION) { *status = U_DIFFERENT_UCA_VERSION; result = tryOpeningFromRules(collElem, status); } else { if(U_FAILURE(*status)){ goto clean; } if((uint32_t)len > (paddedsize(sizeof(UCATableHeader)) + paddedsize(sizeof(UColOptionSet)))) { result = ucol_initCollator((const UCATableHeader *)inData, result, UCA, status); if(U_FAILURE(*status)){ goto clean; } result->hasRealData = TRUE; } else { result = ucol_initCollator(UCA->image, result, UCA, status); ucol_setOptionsFromHeader(result, (UColOptionSet *)(inData+((const UCATableHeader *)inData)->options), status); if(U_FAILURE(*status)){ goto clean; } result->hasRealData = FALSE; } result->freeImageOnClose = FALSE; } } result->rb = b; result->elements = collElem; len = 0; binaryStatus = U_ZERO_ERROR; result->rules = ures_getStringByKey(result->elements, "Sequence", &len, &binaryStatus); result->rulesLength = len; result->freeRulesOnClose = FALSE; } else { /* There is another error, and we're just gonna clean up */ goto clean; } result->validLocale = NULL; // default is to use rb info if(loc == NULL) { loc = ures_getLocale(result->rb, status); } result->requestedLocale = (char *)uprv_malloc((uprv_strlen(loc)+1)*sizeof(char)); /* test for NULL */ if (result->requestedLocale == NULL) { *status = U_MEMORY_ALLOCATION_ERROR; goto clean; } uprv_strcpy(result->requestedLocale, loc); ures_close(binary); ures_close(collations); //??? we have to decide on that. Probably affects something :) result->resCleaner = ucol_prv_closeResources; return result; clean: ures_close(b); ures_close(collElem); ures_close(collations); ures_close(binary); return NULL; }
U_CAPI UCollator* U_EXPORT2 ucol_openRules( const UChar *rules, int32_t rulesLength, UColAttributeValue normalizationMode, UCollationStrength strength, UParseError *parseError, UErrorCode *status) { UColTokenParser src; UColAttributeValue norm; UParseError tErr; if(status == NULL || U_FAILURE(*status)){ return 0; } u_init(status); if (U_FAILURE(*status)) { return NULL; } if(rules == NULL || rulesLength < -1) { *status = U_ILLEGAL_ARGUMENT_ERROR; return 0; } if(rulesLength == -1) { rulesLength = u_strlen(rules); } if(parseError == NULL){ parseError = &tErr; } switch(normalizationMode) { case UCOL_OFF: case UCOL_ON: case UCOL_DEFAULT: norm = normalizationMode; break; default: *status = U_ILLEGAL_ARGUMENT_ERROR; return 0; } UCollator *UCA = ucol_initUCA(status); if(U_FAILURE(*status)){ return NULL; } ucol_tok_initTokenList(&src, rules, rulesLength, UCA, status); ucol_tok_assembleTokenList(&src,parseError, status); if(U_FAILURE(*status)) { /* if status is U_ILLEGAL_ARGUMENT_ERROR, src->current points at the offending option */ /* if status is U_INVALID_FORMAT_ERROR, src->current points after the problematic part of the rules */ /* so something might be done here... or on lower level */ #ifdef UCOL_DEBUG if(*status == U_ILLEGAL_ARGUMENT_ERROR) { fprintf(stderr, "bad option starting at offset %i\n", src.current-src.source); } else { fprintf(stderr, "invalid rule just before offset %i\n", src.current-src.source); } #endif ucol_tok_closeTokenList(&src); return NULL; } UCollator *result = NULL; UCATableHeader *table = NULL; if(src.resultLen > 0 || src.removeSet != NULL) { /* we have a set of rules, let's make something of it */ /* also, if we wanted to remove some contractions, we should make a tailoring */ table = ucol_assembleTailoringTable(&src, status); if(U_SUCCESS(*status)) { // builder version table->version[0] = UCOL_BUILDER_VERSION; // no tailoring information on this level table->version[1] = table->version[2] = table->version[3] = 0; // set UCD version u_getUnicodeVersion(table->UCDVersion); // set UCA version uprv_memcpy(table->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo)); result = ucol_initCollator(table, 0, UCA, status); result->hasRealData = TRUE; result->freeImageOnClose = TRUE; } } else { /* no rules, but no error either */ // must be only options // We will init the collator from UCA result = ucol_initCollator(UCA->image, 0, UCA, status); // And set only the options UColOptionSet *opts = (UColOptionSet *)uprv_malloc(sizeof(UColOptionSet)); /* test for NULL */ if (opts == NULL) { *status = U_MEMORY_ALLOCATION_ERROR; goto cleanup; } uprv_memcpy(opts, src.opts, sizeof(UColOptionSet)); ucol_setOptionsFromHeader(result, opts, status); result->freeOptionsOnClose = TRUE; result->hasRealData = FALSE; result->freeImageOnClose = FALSE; } if(U_SUCCESS(*status)) { UChar *newRules; result->dataVersion[0] = UCOL_BUILDER_VERSION; if(rulesLength > 0) { newRules = (UChar *)uprv_malloc((rulesLength+1)*U_SIZEOF_UCHAR); /* test for NULL */ if (newRules == NULL) { *status = U_MEMORY_ALLOCATION_ERROR; goto cleanup; } uprv_memcpy(newRules, rules, rulesLength*U_SIZEOF_UCHAR); newRules[rulesLength]=0; result->rules = newRules; result->rulesLength = rulesLength; result->freeRulesOnClose = TRUE; } result->rb = NULL; result->elements = NULL; result->validLocale = NULL; result->requestedLocale = NULL; ucol_setAttribute(result, UCOL_STRENGTH, strength, status); ucol_setAttribute(result, UCOL_NORMALIZATION_MODE, norm, status); } else { cleanup: if(result != NULL) { ucol_close(result); } else { if(table != NULL) { uprv_free(table); } } result = NULL; } ucol_tok_closeTokenList(&src); return result; }