michael@0: /* michael@0: ******************************************************************************* michael@0: * michael@0: * Copyright (C) 2001-2012, International Business Machines michael@0: * Corporation and others. All Rights Reserved. michael@0: * michael@0: ******************************************************************************* michael@0: * file name: ucaelems.cpp michael@0: * encoding: US-ASCII michael@0: * tab size: 8 (not used) michael@0: * indentation:4 michael@0: * michael@0: * created 02/22/2001 michael@0: * created by: Vladimir Weinstein michael@0: * michael@0: * This program reads the Franctional UCA table and generates michael@0: * internal format for UCA table as well as inverse UCA table. michael@0: * It then writes binary files containing the data: ucadata.dat michael@0: * & invuca.dat michael@0: * michael@0: * date name comments michael@0: * 03/02/2001 synwee added setMaxExpansion michael@0: * 03/07/2001 synwee merged UCA's maxexpansion and tailoring's michael@0: */ michael@0: michael@0: #include "unicode/utypes.h" michael@0: michael@0: #if !UCONFIG_NO_COLLATION michael@0: michael@0: #include "unicode/uchar.h" michael@0: #include "unicode/unistr.h" michael@0: #include "unicode/ucoleitr.h" michael@0: #include "unicode/normlzr.h" michael@0: #include "unicode/utf16.h" michael@0: #include "normalizer2impl.h" michael@0: #include "ucol_elm.h" michael@0: #include "ucol_tok.h" michael@0: #include "ucol_cnt.h" michael@0: #include "unicode/caniter.h" michael@0: #include "cmemory.h" michael@0: #include "uassert.h" michael@0: michael@0: U_NAMESPACE_USE michael@0: michael@0: static uint32_t uprv_uca_processContraction(CntTable *contractions, UCAElements *element, uint32_t existingCE, UErrorCode *status); michael@0: michael@0: U_CDECL_BEGIN michael@0: static int32_t U_CALLCONV michael@0: prefixLookupHash(const UHashTok e) { michael@0: UCAElements *element = (UCAElements *)e.pointer; michael@0: UChar buf[256]; michael@0: UHashTok key; michael@0: key.pointer = buf; michael@0: uprv_memcpy(buf, element->cPoints, element->cSize*sizeof(UChar)); michael@0: buf[element->cSize] = 0; michael@0: //key.pointer = element->cPoints; michael@0: //element->cPoints[element->cSize] = 0; michael@0: return uhash_hashUChars(key); michael@0: } michael@0: michael@0: static int8_t U_CALLCONV michael@0: prefixLookupComp(const UHashTok e1, const UHashTok e2) { michael@0: UCAElements *element1 = (UCAElements *)e1.pointer; michael@0: UCAElements *element2 = (UCAElements *)e2.pointer; michael@0: michael@0: UChar buf1[256]; michael@0: UHashTok key1; michael@0: key1.pointer = buf1; michael@0: uprv_memcpy(buf1, element1->cPoints, element1->cSize*sizeof(UChar)); michael@0: buf1[element1->cSize] = 0; michael@0: michael@0: UChar buf2[256]; michael@0: UHashTok key2; michael@0: key2.pointer = buf2; michael@0: uprv_memcpy(buf2, element2->cPoints, element2->cSize*sizeof(UChar)); michael@0: buf2[element2->cSize] = 0; michael@0: michael@0: return uhash_compareUChars(key1, key2); michael@0: } michael@0: U_CDECL_END michael@0: michael@0: static int32_t uprv_uca_addExpansion(ExpansionTable *expansions, uint32_t value, UErrorCode *status) { michael@0: if(U_FAILURE(*status)) { michael@0: return 0; michael@0: } michael@0: if(expansions->CEs == NULL) { michael@0: expansions->CEs = (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE*sizeof(uint32_t)); michael@0: /* test for NULL */ michael@0: if (expansions->CEs == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: expansions->size = INIT_EXP_TABLE_SIZE; michael@0: expansions->position = 0; michael@0: } michael@0: michael@0: if(expansions->position == expansions->size) { michael@0: uint32_t *newData = (uint32_t *)uprv_realloc(expansions->CEs, 2*expansions->size*sizeof(uint32_t)); michael@0: if(newData == NULL) { michael@0: #ifdef UCOL_DEBUG michael@0: fprintf(stderr, "out of memory for expansions\n"); michael@0: #endif michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return -1; michael@0: } michael@0: expansions->CEs = newData; michael@0: expansions->size *= 2; michael@0: } michael@0: michael@0: expansions->CEs[expansions->position] = value; michael@0: return(expansions->position++); michael@0: } michael@0: michael@0: U_CAPI tempUCATable* U_EXPORT2 michael@0: uprv_uca_initTempTable(UCATableHeader *image, UColOptionSet *opts, const UCollator *UCA, UColCETags initTag, UColCETags supplementaryInitTag, UErrorCode *status) { michael@0: MaxJamoExpansionTable *maxjet; michael@0: MaxExpansionTable *maxet; michael@0: tempUCATable *t = (tempUCATable *)uprv_malloc(sizeof(tempUCATable)); michael@0: /* test for NULL */ michael@0: if (t == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return NULL; michael@0: } michael@0: uprv_memset(t, 0, sizeof(tempUCATable)); michael@0: michael@0: maxet = (MaxExpansionTable *)uprv_malloc(sizeof(MaxExpansionTable)); michael@0: if (maxet == NULL) { michael@0: goto allocation_failure; michael@0: } michael@0: uprv_memset(maxet, 0, sizeof(MaxExpansionTable)); michael@0: t->maxExpansions = maxet; michael@0: michael@0: maxjet = (MaxJamoExpansionTable *)uprv_malloc(sizeof(MaxJamoExpansionTable)); michael@0: if (maxjet == NULL) { michael@0: goto allocation_failure; michael@0: } michael@0: uprv_memset(maxjet, 0, sizeof(MaxJamoExpansionTable)); michael@0: t->maxJamoExpansions = maxjet; michael@0: michael@0: t->image = image; michael@0: t->options = opts; michael@0: michael@0: t->UCA = UCA; michael@0: t->expansions = (ExpansionTable *)uprv_malloc(sizeof(ExpansionTable)); michael@0: /* test for NULL */ michael@0: if (t->expansions == NULL) { michael@0: goto allocation_failure; michael@0: } michael@0: uprv_memset(t->expansions, 0, sizeof(ExpansionTable)); michael@0: michael@0: t->mapping = utrie_open(NULL, NULL, UCOL_ELM_TRIE_CAPACITY, michael@0: UCOL_SPECIAL_FLAG | (initTag<<24), michael@0: UCOL_SPECIAL_FLAG | (supplementaryInitTag << 24), michael@0: TRUE); // Do your own mallocs for the structure, array and have linear Latin 1 michael@0: if (U_FAILURE(*status)) { michael@0: goto allocation_failure; michael@0: } michael@0: t->prefixLookup = uhash_open(prefixLookupHash, prefixLookupComp, NULL, status); michael@0: if (U_FAILURE(*status)) { michael@0: goto allocation_failure; michael@0: } michael@0: uhash_setValueDeleter(t->prefixLookup, uprv_free); michael@0: michael@0: t->contractions = uprv_cnttab_open(t->mapping, status); michael@0: if (U_FAILURE(*status)) { michael@0: goto cleanup; michael@0: } michael@0: michael@0: /* copy UCA's maxexpansion and merge as we go along */ michael@0: if (UCA != NULL) { michael@0: /* adding an extra initial value for easier manipulation */ michael@0: maxet->size = (int32_t)(UCA->lastEndExpansionCE - UCA->endExpansionCE) + 2; michael@0: maxet->position = maxet->size - 1; michael@0: maxet->endExpansionCE = michael@0: (uint32_t *)uprv_malloc(sizeof(uint32_t) * maxet->size); michael@0: /* test for NULL */ michael@0: if (maxet->endExpansionCE == NULL) { michael@0: goto allocation_failure; michael@0: } michael@0: maxet->expansionCESize = michael@0: (uint8_t *)uprv_malloc(sizeof(uint8_t) * maxet->size); michael@0: /* test for NULL */ michael@0: if (maxet->expansionCESize == NULL) { michael@0: goto allocation_failure; michael@0: } michael@0: /* initialized value */ michael@0: *(maxet->endExpansionCE) = 0; michael@0: *(maxet->expansionCESize) = 0; michael@0: uprv_memcpy(maxet->endExpansionCE + 1, UCA->endExpansionCE, michael@0: sizeof(uint32_t) * (maxet->size - 1)); michael@0: uprv_memcpy(maxet->expansionCESize + 1, UCA->expansionCESize, michael@0: sizeof(uint8_t) * (maxet->size - 1)); michael@0: } michael@0: else { michael@0: maxet->size = 0; michael@0: } michael@0: maxjet->endExpansionCE = NULL; michael@0: maxjet->isV = NULL; michael@0: maxjet->size = 0; michael@0: maxjet->position = 0; michael@0: maxjet->maxLSize = 1; michael@0: maxjet->maxVSize = 1; michael@0: maxjet->maxTSize = 1; michael@0: michael@0: t->unsafeCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE); michael@0: /* test for NULL */ michael@0: if (t->unsafeCP == NULL) { michael@0: goto allocation_failure; michael@0: } michael@0: t->contrEndCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE); michael@0: /* test for NULL */ michael@0: if (t->contrEndCP == NULL) { michael@0: goto allocation_failure; michael@0: } michael@0: uprv_memset(t->unsafeCP, 0, UCOL_UNSAFECP_TABLE_SIZE); michael@0: uprv_memset(t->contrEndCP, 0, UCOL_UNSAFECP_TABLE_SIZE); michael@0: t->cmLookup = NULL; michael@0: return t; michael@0: michael@0: allocation_failure: michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: cleanup: michael@0: uprv_uca_closeTempTable(t); michael@0: return NULL; michael@0: } michael@0: michael@0: static tempUCATable* U_EXPORT2 michael@0: uprv_uca_cloneTempTable(tempUCATable *t, UErrorCode *status) { michael@0: if(U_FAILURE(*status)) { michael@0: return NULL; michael@0: } michael@0: michael@0: tempUCATable *r = (tempUCATable *)uprv_malloc(sizeof(tempUCATable)); michael@0: /* test for NULL */ michael@0: if (r == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return NULL; michael@0: } michael@0: uprv_memset(r, 0, sizeof(tempUCATable)); michael@0: michael@0: /* mapping */ michael@0: if(t->mapping != NULL) { michael@0: /*r->mapping = ucmpe32_clone(t->mapping, status);*/ michael@0: r->mapping = utrie_clone(NULL, t->mapping, NULL, 0); michael@0: } michael@0: michael@0: // a hashing clone function would be very nice. We have none currently... michael@0: // However, we should be good, as closing should not produce any prefixed elements. michael@0: r->prefixLookup = NULL; // prefixes are not used in closing michael@0: michael@0: /* expansions */ michael@0: if(t->expansions != NULL) { michael@0: r->expansions = (ExpansionTable *)uprv_malloc(sizeof(ExpansionTable)); michael@0: /* test for NULL */ michael@0: if (r->expansions == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: goto cleanup; michael@0: } michael@0: r->expansions->position = t->expansions->position; michael@0: r->expansions->size = t->expansions->size; michael@0: if(t->expansions->CEs != NULL) { michael@0: r->expansions->CEs = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->expansions->size); michael@0: /* test for NULL */ michael@0: if (r->expansions->CEs == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: goto cleanup; michael@0: } michael@0: uprv_memcpy(r->expansions->CEs, t->expansions->CEs, sizeof(uint32_t)*t->expansions->position); michael@0: } else { michael@0: r->expansions->CEs = NULL; michael@0: } michael@0: } michael@0: michael@0: if(t->contractions != NULL) { michael@0: r->contractions = uprv_cnttab_clone(t->contractions, status); michael@0: // Check for cloning failure. michael@0: if (r->contractions == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: goto cleanup; michael@0: } michael@0: r->contractions->mapping = r->mapping; michael@0: } michael@0: michael@0: if(t->maxExpansions != NULL) { michael@0: r->maxExpansions = (MaxExpansionTable *)uprv_malloc(sizeof(MaxExpansionTable)); michael@0: /* test for NULL */ michael@0: if (r->maxExpansions == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: goto cleanup; michael@0: } michael@0: r->maxExpansions->size = t->maxExpansions->size; michael@0: r->maxExpansions->position = t->maxExpansions->position; michael@0: if(t->maxExpansions->endExpansionCE != NULL) { michael@0: r->maxExpansions->endExpansionCE = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->maxExpansions->size); michael@0: /* test for NULL */ michael@0: if (r->maxExpansions->endExpansionCE == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: goto cleanup; michael@0: } michael@0: uprv_memset(r->maxExpansions->endExpansionCE, 0xDB, sizeof(uint32_t)*t->maxExpansions->size); michael@0: uprv_memcpy(r->maxExpansions->endExpansionCE, t->maxExpansions->endExpansionCE, t->maxExpansions->position*sizeof(uint32_t)); michael@0: } else { michael@0: r->maxExpansions->endExpansionCE = NULL; michael@0: } michael@0: if(t->maxExpansions->expansionCESize != NULL) { michael@0: r->maxExpansions->expansionCESize = (uint8_t *)uprv_malloc(sizeof(uint8_t)*t->maxExpansions->size); michael@0: /* test for NULL */ michael@0: if (r->maxExpansions->expansionCESize == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: goto cleanup; michael@0: } michael@0: uprv_memset(r->maxExpansions->expansionCESize, 0xDB, sizeof(uint8_t)*t->maxExpansions->size); michael@0: uprv_memcpy(r->maxExpansions->expansionCESize, t->maxExpansions->expansionCESize, t->maxExpansions->position*sizeof(uint8_t)); michael@0: } else { michael@0: r->maxExpansions->expansionCESize = NULL; michael@0: } michael@0: } michael@0: michael@0: if(t->maxJamoExpansions != NULL) { michael@0: r->maxJamoExpansions = (MaxJamoExpansionTable *)uprv_malloc(sizeof(MaxJamoExpansionTable)); michael@0: /* test for NULL */ michael@0: if (r->maxJamoExpansions == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: goto cleanup; michael@0: } michael@0: r->maxJamoExpansions->size = t->maxJamoExpansions->size; michael@0: r->maxJamoExpansions->position = t->maxJamoExpansions->position; michael@0: r->maxJamoExpansions->maxLSize = t->maxJamoExpansions->maxLSize; michael@0: r->maxJamoExpansions->maxVSize = t->maxJamoExpansions->maxVSize; michael@0: r->maxJamoExpansions->maxTSize = t->maxJamoExpansions->maxTSize; michael@0: if(t->maxJamoExpansions->size != 0) { michael@0: r->maxJamoExpansions->endExpansionCE = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->maxJamoExpansions->size); michael@0: /* test for NULL */ michael@0: if (r->maxJamoExpansions->endExpansionCE == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: goto cleanup; michael@0: } michael@0: uprv_memcpy(r->maxJamoExpansions->endExpansionCE, t->maxJamoExpansions->endExpansionCE, t->maxJamoExpansions->position*sizeof(uint32_t)); michael@0: r->maxJamoExpansions->isV = (UBool *)uprv_malloc(sizeof(UBool)*t->maxJamoExpansions->size); michael@0: /* test for NULL */ michael@0: if (r->maxJamoExpansions->isV == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: goto cleanup; michael@0: } michael@0: uprv_memcpy(r->maxJamoExpansions->isV, t->maxJamoExpansions->isV, t->maxJamoExpansions->position*sizeof(UBool)); michael@0: } else { michael@0: r->maxJamoExpansions->endExpansionCE = NULL; michael@0: r->maxJamoExpansions->isV = NULL; michael@0: } michael@0: } michael@0: michael@0: if(t->unsafeCP != NULL) { michael@0: r->unsafeCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE); michael@0: /* test for NULL */ michael@0: if (r->unsafeCP == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: goto cleanup; michael@0: } michael@0: uprv_memcpy(r->unsafeCP, t->unsafeCP, UCOL_UNSAFECP_TABLE_SIZE); michael@0: } michael@0: michael@0: if(t->contrEndCP != NULL) { michael@0: r->contrEndCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE); michael@0: /* test for NULL */ michael@0: if (r->contrEndCP == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: goto cleanup; michael@0: } michael@0: uprv_memcpy(r->contrEndCP, t->contrEndCP, UCOL_UNSAFECP_TABLE_SIZE); michael@0: } michael@0: michael@0: r->UCA = t->UCA; michael@0: r->image = t->image; michael@0: r->options = t->options; michael@0: michael@0: return r; michael@0: cleanup: michael@0: uprv_uca_closeTempTable(t); michael@0: return NULL; michael@0: } michael@0: michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: uprv_uca_closeTempTable(tempUCATable *t) { michael@0: if(t != NULL) { michael@0: if (t->expansions != NULL) { michael@0: uprv_free(t->expansions->CEs); michael@0: uprv_free(t->expansions); michael@0: } michael@0: if(t->contractions != NULL) { michael@0: uprv_cnttab_close(t->contractions); michael@0: } michael@0: if (t->mapping != NULL) { michael@0: utrie_close(t->mapping); michael@0: } michael@0: michael@0: if(t->prefixLookup != NULL) { michael@0: uhash_close(t->prefixLookup); michael@0: } michael@0: michael@0: if (t->maxExpansions != NULL) { michael@0: uprv_free(t->maxExpansions->endExpansionCE); michael@0: uprv_free(t->maxExpansions->expansionCESize); michael@0: uprv_free(t->maxExpansions); michael@0: } michael@0: michael@0: if (t->maxJamoExpansions->size > 0) { michael@0: uprv_free(t->maxJamoExpansions->endExpansionCE); michael@0: uprv_free(t->maxJamoExpansions->isV); michael@0: } michael@0: uprv_free(t->maxJamoExpansions); michael@0: michael@0: uprv_free(t->unsafeCP); michael@0: uprv_free(t->contrEndCP); michael@0: michael@0: if (t->cmLookup != NULL) { michael@0: uprv_free(t->cmLookup->cPoints); michael@0: uprv_free(t->cmLookup); michael@0: } michael@0: michael@0: uprv_free(t); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Looks for the maximum length of all expansion sequences ending with the same michael@0: * collation element. The size required for maxexpansion and maxsize is michael@0: * returned if the arrays are too small. michael@0: * @param endexpansion the last expansion collation element to be added michael@0: * @param expansionsize size of the expansion michael@0: * @param maxexpansion data structure to store the maximum expansion data. michael@0: * @param status error status michael@0: * @returns size of the maxexpansion and maxsize used. michael@0: */ michael@0: static int uprv_uca_setMaxExpansion(uint32_t endexpansion, michael@0: uint8_t expansionsize, michael@0: MaxExpansionTable *maxexpansion, michael@0: UErrorCode *status) michael@0: { michael@0: if (maxexpansion->size == 0) { michael@0: /* we'll always make the first element 0, for easier manipulation */ michael@0: maxexpansion->endExpansionCE = michael@0: (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(int32_t)); michael@0: /* test for NULL */ michael@0: if (maxexpansion->endExpansionCE == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: *(maxexpansion->endExpansionCE) = 0; michael@0: maxexpansion->expansionCESize = michael@0: (uint8_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(uint8_t)); michael@0: /* test for NULL */; michael@0: if (maxexpansion->expansionCESize == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: *(maxexpansion->expansionCESize) = 0; michael@0: maxexpansion->size = INIT_EXP_TABLE_SIZE; michael@0: maxexpansion->position = 0; michael@0: } michael@0: michael@0: if (maxexpansion->position + 1 == maxexpansion->size) { michael@0: uint32_t *neweece = (uint32_t *)uprv_realloc(maxexpansion->endExpansionCE, michael@0: 2 * maxexpansion->size * sizeof(uint32_t)); michael@0: if (neweece == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: maxexpansion->endExpansionCE = neweece; michael@0: michael@0: uint8_t *neweces = (uint8_t *)uprv_realloc(maxexpansion->expansionCESize, michael@0: 2 * maxexpansion->size * sizeof(uint8_t)); michael@0: if (neweces == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: maxexpansion->expansionCESize = neweces; michael@0: maxexpansion->size *= 2; michael@0: } michael@0: michael@0: uint32_t *pendexpansionce = maxexpansion->endExpansionCE; michael@0: uint8_t *pexpansionsize = maxexpansion->expansionCESize; michael@0: int pos = maxexpansion->position; michael@0: michael@0: uint32_t *start = pendexpansionce; michael@0: uint32_t *limit = pendexpansionce + pos; michael@0: michael@0: /* using binary search to determine if last expansion element is michael@0: already in the array */ michael@0: uint32_t *mid; michael@0: int result = -1; michael@0: while (start < limit - 1) { michael@0: mid = start + ((limit - start) >> 1); michael@0: if (endexpansion <= *mid) { michael@0: limit = mid; michael@0: } michael@0: else { michael@0: start = mid; michael@0: } michael@0: } michael@0: michael@0: if (*start == endexpansion) { michael@0: result = (int)(start - pendexpansionce); michael@0: } michael@0: else if (*limit == endexpansion) { michael@0: result = (int)(limit - pendexpansionce); michael@0: } michael@0: michael@0: if (result > -1) { michael@0: /* found the ce in expansion, we'll just modify the size if it is michael@0: smaller */ michael@0: uint8_t *currentsize = pexpansionsize + result; michael@0: if (*currentsize < expansionsize) { michael@0: *currentsize = expansionsize; michael@0: } michael@0: } michael@0: else { michael@0: /* we'll need to squeeze the value into the array. michael@0: initial implementation. */ michael@0: /* shifting the subarray down by 1 */ michael@0: int shiftsize = (int)((pendexpansionce + pos) - start); michael@0: uint32_t *shiftpos = start + 1; michael@0: uint8_t *sizeshiftpos = pexpansionsize + (shiftpos - pendexpansionce); michael@0: michael@0: /* okay need to rearrange the array into sorted order */ michael@0: if (shiftsize == 0 /*|| *(pendexpansionce + pos) < endexpansion*/) { /* the commented part is actually both redundant and dangerous */ michael@0: *(pendexpansionce + pos + 1) = endexpansion; michael@0: *(pexpansionsize + pos + 1) = expansionsize; michael@0: } michael@0: else { michael@0: uprv_memmove(shiftpos + 1, shiftpos, shiftsize * sizeof(int32_t)); michael@0: uprv_memmove(sizeshiftpos + 1, sizeshiftpos, michael@0: shiftsize * sizeof(uint8_t)); michael@0: *shiftpos = endexpansion; michael@0: *sizeshiftpos = expansionsize; michael@0: } michael@0: maxexpansion->position ++; michael@0: michael@0: #ifdef UCOL_DEBUG michael@0: int temp; michael@0: UBool found = FALSE; michael@0: for (temp = 0; temp < maxexpansion->position; temp ++) { michael@0: if (pendexpansionce[temp] >= pendexpansionce[temp + 1]) { michael@0: fprintf(stderr, "expansions %d\n", temp); michael@0: } michael@0: if (pendexpansionce[temp] == endexpansion) { michael@0: found =TRUE; michael@0: if (pexpansionsize[temp] < expansionsize) { michael@0: fprintf(stderr, "expansions size %d\n", temp); michael@0: } michael@0: } michael@0: } michael@0: if (pendexpansionce[temp] == endexpansion) { michael@0: found =TRUE; michael@0: if (pexpansionsize[temp] < expansionsize) { michael@0: fprintf(stderr, "expansions size %d\n", temp); michael@0: } michael@0: } michael@0: if (!found) michael@0: fprintf(stderr, "expansion not found %d\n", temp); michael@0: #endif michael@0: } michael@0: michael@0: return maxexpansion->position; michael@0: } michael@0: michael@0: /** michael@0: * Sets the maximum length of all jamo expansion sequences ending with the same michael@0: * collation element. The size required for maxexpansion and maxsize is michael@0: * returned if the arrays are too small. michael@0: * @param ch the jamo codepoint michael@0: * @param endexpansion the last expansion collation element to be added michael@0: * @param expansionsize size of the expansion michael@0: * @param maxexpansion data structure to store the maximum expansion data. michael@0: * @param status error status michael@0: * @returns size of the maxexpansion and maxsize used. michael@0: */ michael@0: static int uprv_uca_setMaxJamoExpansion(UChar ch, michael@0: uint32_t endexpansion, michael@0: uint8_t expansionsize, michael@0: MaxJamoExpansionTable *maxexpansion, michael@0: UErrorCode *status) michael@0: { michael@0: UBool isV = TRUE; michael@0: if (((uint32_t)ch - 0x1100) <= (0x1112 - 0x1100)) { michael@0: /* determines L for Jamo, doesn't need to store this since it is never michael@0: at the end of a expansion */ michael@0: if (maxexpansion->maxLSize < expansionsize) { michael@0: maxexpansion->maxLSize = expansionsize; michael@0: } michael@0: return maxexpansion->position; michael@0: } michael@0: michael@0: if (((uint32_t)ch - 0x1161) <= (0x1175 - 0x1161)) { michael@0: /* determines V for Jamo */ michael@0: if (maxexpansion->maxVSize < expansionsize) { michael@0: maxexpansion->maxVSize = expansionsize; michael@0: } michael@0: } michael@0: michael@0: if (((uint32_t)ch - 0x11A8) <= (0x11C2 - 0x11A8)) { michael@0: isV = FALSE; michael@0: /* determines T for Jamo */ michael@0: if (maxexpansion->maxTSize < expansionsize) { michael@0: maxexpansion->maxTSize = expansionsize; michael@0: } michael@0: } michael@0: michael@0: if (maxexpansion->size == 0) { michael@0: /* we'll always make the first element 0, for easier manipulation */ michael@0: maxexpansion->endExpansionCE = michael@0: (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(uint32_t)); michael@0: /* test for NULL */; michael@0: if (maxexpansion->endExpansionCE == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: *(maxexpansion->endExpansionCE) = 0; michael@0: maxexpansion->isV = michael@0: (UBool *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(UBool)); michael@0: /* test for NULL */; michael@0: if (maxexpansion->isV == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: uprv_free(maxexpansion->endExpansionCE); michael@0: maxexpansion->endExpansionCE = NULL; michael@0: return 0; michael@0: } michael@0: *(maxexpansion->isV) = 0; michael@0: maxexpansion->size = INIT_EXP_TABLE_SIZE; michael@0: maxexpansion->position = 0; michael@0: } michael@0: michael@0: if (maxexpansion->position + 1 == maxexpansion->size) { michael@0: maxexpansion->size *= 2; michael@0: maxexpansion->endExpansionCE = (uint32_t *)uprv_realloc(maxexpansion->endExpansionCE, michael@0: maxexpansion->size * sizeof(uint32_t)); michael@0: if (maxexpansion->endExpansionCE == NULL) { michael@0: #ifdef UCOL_DEBUG michael@0: fprintf(stderr, "out of memory for maxExpansions\n"); michael@0: #endif michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: maxexpansion->isV = (UBool *)uprv_realloc(maxexpansion->isV, michael@0: maxexpansion->size * sizeof(UBool)); michael@0: if (maxexpansion->isV == NULL) { michael@0: #ifdef UCOL_DEBUG michael@0: fprintf(stderr, "out of memory for maxExpansions\n"); michael@0: #endif michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: uprv_free(maxexpansion->endExpansionCE); michael@0: maxexpansion->endExpansionCE = NULL; michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: uint32_t *pendexpansionce = maxexpansion->endExpansionCE; michael@0: int pos = maxexpansion->position; michael@0: michael@0: while (pos > 0) { michael@0: pos --; michael@0: if (*(pendexpansionce + pos) == endexpansion) { michael@0: return maxexpansion->position; michael@0: } michael@0: } michael@0: michael@0: *(pendexpansionce + maxexpansion->position) = endexpansion; michael@0: *(maxexpansion->isV + maxexpansion->position) = isV; michael@0: maxexpansion->position ++; michael@0: michael@0: return maxexpansion->position; michael@0: } michael@0: michael@0: michael@0: static void ContrEndCPSet(uint8_t *table, UChar c) { michael@0: uint32_t hash; michael@0: uint8_t *htByte; michael@0: michael@0: hash = c; michael@0: if (hash >= UCOL_UNSAFECP_TABLE_SIZE*8) { michael@0: hash = (hash & UCOL_UNSAFECP_TABLE_MASK) + 256; michael@0: } michael@0: htByte = &table[hash>>3]; michael@0: *htByte |= (1 << (hash & 7)); michael@0: } michael@0: michael@0: michael@0: static void unsafeCPSet(uint8_t *table, UChar c) { michael@0: uint32_t hash; michael@0: uint8_t *htByte; michael@0: michael@0: hash = c; michael@0: if (hash >= UCOL_UNSAFECP_TABLE_SIZE*8) { michael@0: if (hash >= 0xd800 && hash <= 0xf8ff) { michael@0: /* Part of a surrogate, or in private use area. */ michael@0: /* These don't go in the table */ michael@0: return; michael@0: } michael@0: hash = (hash & UCOL_UNSAFECP_TABLE_MASK) + 256; michael@0: } michael@0: htByte = &table[hash>>3]; michael@0: *htByte |= (1 << (hash & 7)); michael@0: } michael@0: michael@0: static void michael@0: uprv_uca_createCMTable(tempUCATable *t, int32_t noOfCM, UErrorCode *status) { michael@0: t->cmLookup = (CombinClassTable *)uprv_malloc(sizeof(CombinClassTable)); michael@0: if (t->cmLookup==NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return; michael@0: } michael@0: t->cmLookup->cPoints=(UChar *)uprv_malloc(noOfCM*sizeof(UChar)); michael@0: if (t->cmLookup->cPoints ==NULL) { michael@0: uprv_free(t->cmLookup); michael@0: t->cmLookup = NULL; michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return; michael@0: } michael@0: michael@0: t->cmLookup->size=noOfCM; michael@0: uprv_memset(t->cmLookup->index, 0, sizeof(t->cmLookup->index)); michael@0: michael@0: return; michael@0: } michael@0: michael@0: static void michael@0: uprv_uca_copyCMTable(tempUCATable *t, UChar *cm, uint16_t *index) { michael@0: int32_t count=0; michael@0: michael@0: for (int32_t i=0; i<256; ++i) { michael@0: if (index[i]>0) { michael@0: // cPoints is ordered by combining class value. michael@0: uprv_memcpy(t->cmLookup->cPoints+count, cm+(i<<8), index[i]*sizeof(UChar)); michael@0: count += index[i]; michael@0: } michael@0: t->cmLookup->index[i]=count; michael@0: } michael@0: return; michael@0: } michael@0: michael@0: /* 1. to the UnsafeCP hash table, add all chars with combining class != 0 */ michael@0: /* 2. build combining marks table for all chars with combining class != 0 */ michael@0: static void uprv_uca_unsafeCPAddCCNZ(tempUCATable *t, UErrorCode *status) { michael@0: michael@0: UChar c; michael@0: uint16_t fcd; // Hi byte is lead combining class. lo byte is trailing combing class. michael@0: UBool buildCMTable = (t->cmLookup==NULL); // flag for building combining class table michael@0: UChar *cm=NULL; michael@0: uint16_t index[256]; michael@0: int32_t count=0; michael@0: const Normalizer2Impl *nfcImpl = Normalizer2Factory::getNFCImpl(*status); michael@0: if (U_FAILURE(*status)) { michael@0: return; michael@0: } michael@0: michael@0: if (buildCMTable) { michael@0: if (cm==NULL) { michael@0: cm = (UChar *)uprv_malloc(sizeof(UChar)*UCOL_MAX_CM_TAB); michael@0: if (cm==NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return; michael@0: } michael@0: } michael@0: uprv_memset(index, 0, sizeof(index)); michael@0: } michael@0: for (c=0; c<0xffff; c++) { michael@0: if (U16_IS_LEAD(c)) { michael@0: fcd = 0; michael@0: if (nfcImpl->singleLeadMightHaveNonZeroFCD16(c)) { michael@0: UChar32 supp = U16_GET_SUPPLEMENTARY(c, 0xdc00); michael@0: UChar32 suppLimit = supp + 0x400; michael@0: while (supp < suppLimit) { michael@0: fcd |= nfcImpl->getFCD16FromNormData(supp++); michael@0: } michael@0: } michael@0: } else { michael@0: fcd = nfcImpl->getFCD16(c); michael@0: } michael@0: if (fcd >= 0x100 || // if the leading combining class(c) > 0 || michael@0: (U16_IS_LEAD(c) && fcd != 0)) {// c is a leading surrogate with some FCD data michael@0: if (buildCMTable) { michael@0: uint32_t cClass = fcd & 0xff; michael@0: //uint32_t temp=(cClass<<8)+index[cClass]; michael@0: cm[(cClass<<8)+index[cClass]] = c; // michael@0: index[cClass]++; michael@0: count++; michael@0: } michael@0: unsafeCPSet(t->unsafeCP, c); michael@0: } michael@0: } michael@0: michael@0: // copy to cm table michael@0: if (buildCMTable) { michael@0: uprv_uca_createCMTable(t, count, status); michael@0: if(U_FAILURE(*status)) { michael@0: if (cm!=NULL) { michael@0: uprv_free(cm); michael@0: } michael@0: return; michael@0: } michael@0: uprv_uca_copyCMTable(t, cm, index); michael@0: } michael@0: michael@0: if(t->prefixLookup != NULL) { michael@0: int32_t i = -1; michael@0: const UHashElement *e = NULL; michael@0: UCAElements *element = NULL; michael@0: UChar NFCbuf[256]; michael@0: while((e = uhash_nextElement(t->prefixLookup, &i)) != NULL) { michael@0: element = (UCAElements *)e->value.pointer; michael@0: // codepoints here are in the NFD form. We need to add the michael@0: // first code point of the NFC form to unsafe, because michael@0: // strcoll needs to backup over them. michael@0: unorm_normalize(element->cPoints, element->cSize, UNORM_NFC, 0, michael@0: NFCbuf, 256, status); michael@0: unsafeCPSet(t->unsafeCP, NFCbuf[0]); michael@0: } michael@0: } michael@0: michael@0: if (cm!=NULL) { michael@0: uprv_free(cm); michael@0: } michael@0: } michael@0: michael@0: static uint32_t uprv_uca_addPrefix(tempUCATable *t, uint32_t CE, michael@0: UCAElements *element, UErrorCode *status) michael@0: { michael@0: // currently the longest prefix we're supporting in Japanese is two characters michael@0: // long. Although this table could quite easily mimic complete contraction stuff michael@0: // there is no good reason to make a general solution, as it would require some michael@0: // error prone messing. michael@0: CntTable *contractions = t->contractions; michael@0: UChar32 cp; michael@0: uint32_t cpsize = 0; michael@0: UChar *oldCP = element->cPoints; michael@0: uint32_t oldCPSize = element->cSize; michael@0: michael@0: michael@0: contractions->currentTag = SPEC_PROC_TAG; michael@0: michael@0: // here, we will normalize & add prefix to the table. michael@0: uint32_t j = 0; michael@0: #ifdef UCOL_DEBUG michael@0: for(j=0; jcSize; j++) { michael@0: fprintf(stdout, "CP: %04X ", element->cPoints[j]); michael@0: } michael@0: fprintf(stdout, "El: %08X Pref: ", CE); michael@0: for(j=0; jprefixSize; j++) { michael@0: fprintf(stdout, "%04X ", element->prefix[j]); michael@0: } michael@0: fprintf(stdout, "%08X ", element->mapCE); michael@0: #endif michael@0: michael@0: for (j = 1; jprefixSize; j++) { /* First add NFD prefix chars to unsafe CP hash table */ michael@0: // Unless it is a trail surrogate, which is handled algoritmically and michael@0: // shouldn't take up space in the table. michael@0: if(!(U16_IS_TRAIL(element->prefix[j]))) { michael@0: unsafeCPSet(t->unsafeCP, element->prefix[j]); michael@0: } michael@0: } michael@0: michael@0: UChar tempPrefix = 0; michael@0: michael@0: for(j = 0; j < /*nfcSize*/element->prefixSize/2; j++) { // prefixes are going to be looked up backwards michael@0: // therefore, we will promptly reverse the prefix buffer... michael@0: tempPrefix = *(/*nfcBuffer*/element->prefix+element->prefixSize-j-1); michael@0: *(/*nfcBuffer*/element->prefix+element->prefixSize-j-1) = element->prefix[j]; michael@0: element->prefix[j] = tempPrefix; michael@0: } michael@0: michael@0: #ifdef UCOL_DEBUG michael@0: fprintf(stdout, "Reversed: "); michael@0: for(j=0; jprefixSize; j++) { michael@0: fprintf(stdout, "%04X ", element->prefix[j]); michael@0: } michael@0: fprintf(stdout, "%08X\n", element->mapCE); michael@0: #endif michael@0: michael@0: // the first codepoint is also unsafe, as it forms a 'contraction' with the prefix michael@0: if(!(U16_IS_TRAIL(element->cPoints[0]))) { michael@0: unsafeCPSet(t->unsafeCP, element->cPoints[0]); michael@0: } michael@0: michael@0: // Maybe we need this... To handle prefixes completely in the forward direction... michael@0: //if(element->cSize == 1) { michael@0: // if(!(U16_IS_TRAIL(element->cPoints[0]))) { michael@0: // ContrEndCPSet(t->contrEndCP, element->cPoints[0]); michael@0: // } michael@0: //} michael@0: michael@0: element->cPoints = element->prefix; michael@0: element->cSize = element->prefixSize; michael@0: michael@0: // Add the last char of the contraction to the contraction-end hash table. michael@0: // unless it is a trail surrogate, which is handled algorithmically and michael@0: // shouldn't be in the table michael@0: if(!(U16_IS_TRAIL(element->cPoints[element->cSize -1]))) { michael@0: ContrEndCPSet(t->contrEndCP, element->cPoints[element->cSize -1]); michael@0: } michael@0: michael@0: // First we need to check if contractions starts with a surrogate michael@0: U16_NEXT(element->cPoints, cpsize, element->cSize, cp); michael@0: michael@0: // If there are any Jamos in the contraction, we should turn on special michael@0: // processing for Jamos michael@0: if(UCOL_ISJAMO(element->prefix[0])) { michael@0: t->image->jamoSpecial = TRUE; michael@0: } michael@0: /* then we need to deal with it */ michael@0: /* we could aready have something in table - or we might not */ michael@0: michael@0: if(!isPrefix(CE)) { michael@0: /* if it wasn't contraction, we wouldn't end up here*/ michael@0: int32_t firstContractionOffset = 0; michael@0: firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, CE, status); michael@0: uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status); michael@0: uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->prefix, newCE, status); michael@0: uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, CE, status); michael@0: CE = constructContractCE(SPEC_PROC_TAG, firstContractionOffset); michael@0: } else { /* we are adding to existing contraction */ michael@0: /* there were already some elements in the table, so we need to add a new contraction */ michael@0: /* Two things can happen here: either the codepoint is already in the table, or it is not */ michael@0: int32_t position = uprv_cnttab_findCP(contractions, CE, *element->prefix, status); michael@0: if(position > 0) { /* if it is we just continue down the chain */ michael@0: uint32_t eCE = uprv_cnttab_getCE(contractions, CE, position, status); michael@0: uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status); michael@0: uprv_cnttab_setContraction(contractions, CE, position, *(element->prefix), newCE, status); michael@0: } else { /* if it isn't, we will have to create a new sequence */ michael@0: uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status); michael@0: uprv_cnttab_insertContraction(contractions, CE, *(element->prefix), element->mapCE, status); michael@0: } michael@0: } michael@0: michael@0: element->cPoints = oldCP; michael@0: element->cSize = oldCPSize; michael@0: michael@0: return CE; michael@0: } michael@0: michael@0: // Note regarding surrogate handling: We are interested only in the single michael@0: // or leading surrogates in a contraction. If a surrogate is somewhere else michael@0: // in the contraction, it is going to be handled as a pair of code units, michael@0: // as it doesn't affect the performance AND handling surrogates specially michael@0: // would complicate code way too much. michael@0: static uint32_t uprv_uca_addContraction(tempUCATable *t, uint32_t CE, michael@0: UCAElements *element, UErrorCode *status) michael@0: { michael@0: CntTable *contractions = t->contractions; michael@0: UChar32 cp; michael@0: uint32_t cpsize = 0; michael@0: michael@0: contractions->currentTag = CONTRACTION_TAG; michael@0: michael@0: // First we need to check if contractions starts with a surrogate michael@0: U16_NEXT(element->cPoints, cpsize, element->cSize, cp); michael@0: michael@0: if(cpsizecSize) { // This is a real contraction, if there are other characters after the first michael@0: uint32_t j = 0; michael@0: for (j=1; jcSize; j++) { /* First add contraction chars to unsafe CP hash table */ michael@0: // Unless it is a trail surrogate, which is handled algoritmically and michael@0: // shouldn't take up space in the table. michael@0: if(!(U16_IS_TRAIL(element->cPoints[j]))) { michael@0: unsafeCPSet(t->unsafeCP, element->cPoints[j]); michael@0: } michael@0: } michael@0: // Add the last char of the contraction to the contraction-end hash table. michael@0: // unless it is a trail surrogate, which is handled algorithmically and michael@0: // shouldn't be in the table michael@0: if(!(U16_IS_TRAIL(element->cPoints[element->cSize -1]))) { michael@0: ContrEndCPSet(t->contrEndCP, element->cPoints[element->cSize -1]); michael@0: } michael@0: michael@0: // If there are any Jamos in the contraction, we should turn on special michael@0: // processing for Jamos michael@0: if(UCOL_ISJAMO(element->cPoints[0])) { michael@0: t->image->jamoSpecial = TRUE; michael@0: } michael@0: /* then we need to deal with it */ michael@0: /* we could aready have something in table - or we might not */ michael@0: element->cPoints+=cpsize; michael@0: element->cSize-=cpsize; michael@0: if(!isContraction(CE)) { michael@0: /* if it wasn't contraction, we wouldn't end up here*/ michael@0: int32_t firstContractionOffset = 0; michael@0: firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, CE, status); michael@0: uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status); michael@0: uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->cPoints, newCE, status); michael@0: uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, CE, status); michael@0: CE = constructContractCE(CONTRACTION_TAG, firstContractionOffset); michael@0: } else { /* we are adding to existing contraction */ michael@0: /* there were already some elements in the table, so we need to add a new contraction */ michael@0: /* Two things can happen here: either the codepoint is already in the table, or it is not */ michael@0: int32_t position = uprv_cnttab_findCP(contractions, CE, *element->cPoints, status); michael@0: if(position > 0) { /* if it is we just continue down the chain */ michael@0: uint32_t eCE = uprv_cnttab_getCE(contractions, CE, position, status); michael@0: uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status); michael@0: uprv_cnttab_setContraction(contractions, CE, position, *(element->cPoints), newCE, status); michael@0: } else { /* if it isn't, we will have to create a new sequence */ michael@0: uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status); michael@0: uprv_cnttab_insertContraction(contractions, CE, *(element->cPoints), newCE, status); michael@0: } michael@0: } michael@0: element->cPoints-=cpsize; michael@0: element->cSize+=cpsize; michael@0: /*ucmpe32_set(t->mapping, cp, CE);*/ michael@0: utrie_set32(t->mapping, cp, CE); michael@0: } else if(!isContraction(CE)) { /* this is just a surrogate, and there is no contraction */ michael@0: /*ucmpe32_set(t->mapping, cp, element->mapCE);*/ michael@0: utrie_set32(t->mapping, cp, element->mapCE); michael@0: } else { /* fill out the first stage of the contraction with the surrogate CE */ michael@0: uprv_cnttab_changeContraction(contractions, CE, 0, element->mapCE, status); michael@0: uprv_cnttab_changeContraction(contractions, CE, 0xFFFF, element->mapCE, status); michael@0: } michael@0: return CE; michael@0: } michael@0: michael@0: michael@0: static uint32_t uprv_uca_processContraction(CntTable *contractions, UCAElements *element, uint32_t existingCE, UErrorCode *status) { michael@0: int32_t firstContractionOffset = 0; michael@0: // uint32_t contractionElement = UCOL_NOT_FOUND; michael@0: michael@0: if(U_FAILURE(*status)) { michael@0: return UCOL_NOT_FOUND; michael@0: } michael@0: michael@0: /* end of recursion */ michael@0: if(element->cSize == 1) { michael@0: if(isCntTableElement(existingCE) && ((UColCETags)getCETag(existingCE) == contractions->currentTag)) { michael@0: uprv_cnttab_changeContraction(contractions, existingCE, 0, element->mapCE, status); michael@0: uprv_cnttab_changeContraction(contractions, existingCE, 0xFFFF, element->mapCE, status); michael@0: return existingCE; michael@0: } else { michael@0: return element->mapCE; /*can't do just that. existingCe might be a contraction, meaning that we need to do another step */ michael@0: } michael@0: } michael@0: michael@0: /* this recursion currently feeds on the only element we have... We will have to copy it in order to accomodate */ michael@0: /* for both backward and forward cycles */ michael@0: michael@0: /* we encountered either an empty space or a non-contraction element */ michael@0: /* this means we are constructing a new contraction sequence */ michael@0: element->cPoints++; michael@0: element->cSize--; michael@0: if(!isCntTableElement(existingCE)) { michael@0: /* if it wasn't contraction, we wouldn't end up here*/ michael@0: firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, existingCE, status); michael@0: uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status); michael@0: uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->cPoints, newCE, status); michael@0: uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, existingCE, status); michael@0: existingCE = constructContractCE(contractions->currentTag, firstContractionOffset); michael@0: } else { /* we are adding to existing contraction */ michael@0: /* there were already some elements in the table, so we need to add a new contraction */ michael@0: /* Two things can happen here: either the codepoint is already in the table, or it is not */ michael@0: int32_t position = uprv_cnttab_findCP(contractions, existingCE, *element->cPoints, status); michael@0: if(position > 0) { /* if it is we just continue down the chain */ michael@0: uint32_t eCE = uprv_cnttab_getCE(contractions, existingCE, position, status); michael@0: uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status); michael@0: uprv_cnttab_setContraction(contractions, existingCE, position, *(element->cPoints), newCE, status); michael@0: } else { /* if it isn't, we will have to create a new sequence */ michael@0: uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status); michael@0: uprv_cnttab_insertContraction(contractions, existingCE, *(element->cPoints), newCE, status); michael@0: } michael@0: } michael@0: element->cPoints--; michael@0: element->cSize++; michael@0: return existingCE; michael@0: } michael@0: michael@0: static uint32_t uprv_uca_finalizeAddition(tempUCATable *t, UCAElements *element, UErrorCode *status) { michael@0: uint32_t CE = UCOL_NOT_FOUND; michael@0: // This should add a completely ignorable element to the michael@0: // unsafe table, so that backward iteration will skip michael@0: // over it when treating contractions. michael@0: uint32_t i = 0; michael@0: if(element->mapCE == 0) { michael@0: for(i = 0; i < element->cSize; i++) { michael@0: if(!U16_IS_TRAIL(element->cPoints[i])) { michael@0: unsafeCPSet(t->unsafeCP, element->cPoints[i]); michael@0: } michael@0: } michael@0: } michael@0: if(element->cSize > 1) { /* we're adding a contraction */ michael@0: uint32_t i = 0; michael@0: UChar32 cp; michael@0: michael@0: U16_NEXT(element->cPoints, i, element->cSize, cp); michael@0: /*CE = ucmpe32_get(t->mapping, cp);*/ michael@0: CE = utrie_get32(t->mapping, cp, NULL); michael@0: michael@0: CE = uprv_uca_addContraction(t, CE, element, status); michael@0: } else { /* easy case, */ michael@0: /*CE = ucmpe32_get(t->mapping, element->cPoints[0]);*/ michael@0: CE = utrie_get32(t->mapping, element->cPoints[0], NULL); michael@0: michael@0: if( CE != UCOL_NOT_FOUND) { michael@0: if(isCntTableElement(CE) /*isContraction(CE)*/) { /* adding a non contraction element (thai, expansion, single) to already existing contraction */ michael@0: if(!isPrefix(element->mapCE)) { // we cannot reenter prefix elements - as we are going to create a dead loop michael@0: // Only expansions and regular CEs can go here... Contractions will never happen in this place michael@0: uprv_cnttab_setContraction(t->contractions, CE, 0, 0, element->mapCE, status); michael@0: /* This loop has to change the CE at the end of contraction REDO!*/ michael@0: uprv_cnttab_changeLastCE(t->contractions, CE, element->mapCE, status); michael@0: } michael@0: } else { michael@0: /*ucmpe32_set(t->mapping, element->cPoints[0], element->mapCE);*/ michael@0: utrie_set32(t->mapping, element->cPoints[0], element->mapCE); michael@0: if ((element->prefixSize!=0) && (!isSpecial(CE) || (getCETag(CE)!=IMPLICIT_TAG))) { michael@0: UCAElements *origElem = (UCAElements *)uprv_malloc(sizeof(UCAElements)); michael@0: /* test for NULL */ michael@0: if (origElem== NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: /* copy the original UCA value */ michael@0: origElem->prefixSize = 0; michael@0: origElem->prefix = NULL; michael@0: origElem->cPoints = origElem->uchars; michael@0: origElem->cPoints[0] = element->cPoints[0]; michael@0: origElem->cSize = 1; michael@0: origElem->CEs[0]=CE; michael@0: origElem->mapCE=CE; michael@0: origElem->noOfCEs=1; michael@0: uprv_uca_finalizeAddition(t, origElem, status); michael@0: uprv_free(origElem); michael@0: } michael@0: #ifdef UCOL_DEBUG michael@0: fprintf(stderr, "Warning - trying to overwrite existing data %08X for cp %04X with %08X\n", CE, element->cPoints[0], element->CEs[0]); michael@0: //*status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: #endif michael@0: } michael@0: } else { michael@0: /*ucmpe32_set(t->mapping, element->cPoints[0], element->mapCE);*/ michael@0: utrie_set32(t->mapping, element->cPoints[0], element->mapCE); michael@0: } michael@0: } michael@0: return CE; michael@0: } michael@0: michael@0: /* This adds a read element, while testing for existence */ michael@0: U_CAPI uint32_t U_EXPORT2 michael@0: uprv_uca_addAnElement(tempUCATable *t, UCAElements *element, UErrorCode *status) { michael@0: U_NAMESPACE_USE michael@0: michael@0: ExpansionTable *expansions = t->expansions; michael@0: michael@0: uint32_t i = 1; michael@0: uint32_t expansion = 0; michael@0: uint32_t CE; michael@0: michael@0: if(U_FAILURE(*status)) { michael@0: return 0xFFFF; michael@0: } michael@0: michael@0: element->mapCE = 0; // clear mapCE so that we can catch expansions michael@0: michael@0: if(element->noOfCEs == 1) { michael@0: element->mapCE = element->CEs[0]; michael@0: } else { michael@0: /* ICU 2.1 long primaries */ michael@0: /* unfortunately, it looks like we have to look for a long primary here */ michael@0: /* since in canonical closure we are going to hit some long primaries from */ michael@0: /* the first phase, and they will come back as continuations/expansions */ michael@0: /* destroying the effect of the previous opitimization */ michael@0: /* A long primary is a three byte primary with starting secondaries and tertiaries */ michael@0: /* It can appear in long runs of only primary differences (like east Asian tailorings) */ michael@0: /* also, it should not be an expansion, as expansions would break with this */ michael@0: // This part came in from ucol_bld.cpp michael@0: //if(tok->expansion == 0 michael@0: //&& noOfBytes[0] == 3 && noOfBytes[1] == 1 && noOfBytes[2] == 1 michael@0: //&& CEparts[1] == (UCOL_BYTE_COMMON << 24) && CEparts[2] == (UCOL_BYTE_COMMON << 24)) { michael@0: /* we will construct a special CE that will go unchanged to the table */ michael@0: if(element->noOfCEs == 2 // a two CE expansion michael@0: && isContinuation(element->CEs[1]) // which is a continuation michael@0: && (element->CEs[1] & (~(0xFF << 24 | UCOL_CONTINUATION_MARKER))) == 0 // that has only primaries in continuation, michael@0: && (((element->CEs[0]>>8) & 0xFF) == UCOL_BYTE_COMMON) // a common secondary michael@0: && ((element->CEs[0] & 0xFF) == UCOL_BYTE_COMMON) // and a common tertiary michael@0: ) michael@0: { michael@0: #ifdef UCOL_DEBUG michael@0: fprintf(stdout, "Long primary %04X\n", element->cPoints[0]); michael@0: #endif michael@0: element->mapCE = UCOL_SPECIAL_FLAG | (LONG_PRIMARY_TAG<<24) // a long primary special michael@0: | ((element->CEs[0]>>8) & 0xFFFF00) // first and second byte of primary michael@0: | ((element->CEs[1]>>24) & 0xFF); // third byte of primary michael@0: } michael@0: else { michael@0: expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (EXPANSION_TAG<CEs[0], status)+(headersize>>2))<<4) michael@0: & 0xFFFFF0)); michael@0: michael@0: for(i = 1; inoOfCEs; i++) { michael@0: uprv_uca_addExpansion(expansions, element->CEs[i], status); michael@0: } michael@0: if(element->noOfCEs <= 0xF) { michael@0: expansion |= element->noOfCEs; michael@0: } else { michael@0: uprv_uca_addExpansion(expansions, 0, status); michael@0: } michael@0: element->mapCE = expansion; michael@0: uprv_uca_setMaxExpansion(element->CEs[element->noOfCEs - 1], michael@0: (uint8_t)element->noOfCEs, michael@0: t->maxExpansions, michael@0: status); michael@0: if(UCOL_ISJAMO(element->cPoints[0])) { michael@0: t->image->jamoSpecial = TRUE; michael@0: uprv_uca_setMaxJamoExpansion(element->cPoints[0], michael@0: element->CEs[element->noOfCEs - 1], michael@0: (uint8_t)element->noOfCEs, michael@0: t->maxJamoExpansions, michael@0: status); michael@0: } michael@0: if (U_FAILURE(*status)) { michael@0: return 0; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // We treat digits differently - they are "uber special" and should be michael@0: // processed differently if numeric collation is on. michael@0: UChar32 uniChar = 0; michael@0: //printElement(element); michael@0: if ((element->cSize == 2) && U16_IS_LEAD(element->cPoints[0])){ michael@0: uniChar = U16_GET_SUPPLEMENTARY(element->cPoints[0], element->cPoints[1]); michael@0: } else if (element->cSize == 1){ michael@0: uniChar = element->cPoints[0]; michael@0: } michael@0: michael@0: // Here, we either have one normal CE OR mapCE is set. Therefore, we stuff only michael@0: // one element to the expansion buffer. When we encounter a digit and we don't michael@0: // do numeric collation, we will just pick the CE we have and break out of case michael@0: // (see ucol.cpp ucol_prv_getSpecialCE && ucol_prv_getSpecialPrevCE). If we picked michael@0: // a special, further processing will occur. If it's a simple CE, we'll return due michael@0: // to how the loop is constructed. michael@0: if (uniChar != 0 && u_isdigit(uniChar)){ michael@0: expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (DIGIT_TAG<mapCE) { // if there is an expansion, we'll pick it here michael@0: expansion |= ((uprv_uca_addExpansion(expansions, element->mapCE, status)+(headersize>>2))<<4); michael@0: } else { michael@0: expansion |= ((uprv_uca_addExpansion(expansions, element->CEs[0], status)+(headersize>>2))<<4); michael@0: } michael@0: element->mapCE = expansion; michael@0: michael@0: // Need to go back to the beginning of the digit string if in the middle! michael@0: if(uniChar <= 0xFFFF) { // supplementaries are always unsafe. API takes UChars michael@0: unsafeCPSet(t->unsafeCP, (UChar)uniChar); michael@0: } michael@0: } michael@0: michael@0: // here we want to add the prefix structure. michael@0: // I will try to process it as a reverse contraction, if possible. michael@0: // prefix buffer is already reversed. michael@0: michael@0: if(element->prefixSize!=0) { michael@0: // We keep the seen prefix starter elements in a hashtable michael@0: // we need it to be able to distinguish between the simple michael@0: // codepoints and prefix starters. Also, we need to use it michael@0: // for canonical closure. michael@0: michael@0: UCAElements *composed = (UCAElements *)uprv_malloc(sizeof(UCAElements)); michael@0: /* test for NULL */ michael@0: if (composed == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: uprv_memcpy(composed, element, sizeof(UCAElements)); michael@0: composed->cPoints = composed->uchars; michael@0: composed->prefix = composed->prefixChars; michael@0: michael@0: composed->prefixSize = unorm_normalize(element->prefix, element->prefixSize, UNORM_NFC, 0, composed->prefix, 128, status); michael@0: michael@0: michael@0: if(t->prefixLookup != NULL) { michael@0: UCAElements *uCE = (UCAElements *)uhash_get(t->prefixLookup, element); michael@0: if(uCE != NULL) { // there is already a set of code points here michael@0: element->mapCE = uprv_uca_addPrefix(t, uCE->mapCE, element, status); michael@0: } else { // no code points, so this spot is clean michael@0: element->mapCE = uprv_uca_addPrefix(t, UCOL_NOT_FOUND, element, status); michael@0: uCE = (UCAElements *)uprv_malloc(sizeof(UCAElements)); michael@0: /* test for NULL */ michael@0: if (uCE == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: uprv_memcpy(uCE, element, sizeof(UCAElements)); michael@0: uCE->cPoints = uCE->uchars; michael@0: uhash_put(t->prefixLookup, uCE, uCE, status); michael@0: } michael@0: if(composed->prefixSize != element->prefixSize || uprv_memcmp(composed->prefix, element->prefix, element->prefixSize)) { michael@0: // do it! michael@0: composed->mapCE = uprv_uca_addPrefix(t, element->mapCE, composed, status); michael@0: } michael@0: } michael@0: uprv_free(composed); michael@0: } michael@0: michael@0: // We need to use the canonical iterator here michael@0: // the way we do it is to generate the canonically equivalent strings michael@0: // for the contraction and then add the sequences that pass FCD check michael@0: if(element->cSize > 1 && !(element->cSize==2 && U16_IS_LEAD(element->cPoints[0]) && U16_IS_TRAIL(element->cPoints[1]))) { // this is a contraction, we should check whether a composed form should also be included michael@0: UnicodeString source(element->cPoints, element->cSize); michael@0: CanonicalIterator it(source, *status); michael@0: source = it.next(); michael@0: while(!source.isBogus()) { michael@0: if(Normalizer::quickCheck(source, UNORM_FCD, *status) != UNORM_NO) { michael@0: element->cSize = source.extract(element->cPoints, 128, *status); michael@0: uprv_uca_finalizeAddition(t, element, status); michael@0: } michael@0: source = it.next(); michael@0: } michael@0: CE = element->mapCE; michael@0: } else { michael@0: CE = uprv_uca_finalizeAddition(t, element, status); michael@0: } michael@0: michael@0: return CE; michael@0: } michael@0: michael@0: michael@0: /*void uprv_uca_getMaxExpansionJamo(CompactEIntArray *mapping, */ michael@0: static void uprv_uca_getMaxExpansionJamo(UNewTrie *mapping, michael@0: MaxExpansionTable *maxexpansion, michael@0: MaxJamoExpansionTable *maxjamoexpansion, michael@0: UBool jamospecial, michael@0: UErrorCode *status) michael@0: { michael@0: const uint32_t VBASE = 0x1161; michael@0: const uint32_t TBASE = 0x11A8; michael@0: const uint32_t VCOUNT = 21; michael@0: const uint32_t TCOUNT = 28; michael@0: michael@0: uint32_t v = VBASE + VCOUNT - 1; michael@0: uint32_t t = TBASE + TCOUNT - 1; michael@0: uint32_t ce; michael@0: michael@0: while (v >= VBASE) { michael@0: /*ce = ucmpe32_get(mapping, v);*/ michael@0: ce = utrie_get32(mapping, v, NULL); michael@0: if (ce < UCOL_SPECIAL_FLAG) { michael@0: uprv_uca_setMaxExpansion(ce, 2, maxexpansion, status); michael@0: } michael@0: v --; michael@0: } michael@0: michael@0: while (t >= TBASE) michael@0: { michael@0: /*ce = ucmpe32_get(mapping, t);*/ michael@0: ce = utrie_get32(mapping, t, NULL); michael@0: if (ce < UCOL_SPECIAL_FLAG) { michael@0: uprv_uca_setMaxExpansion(ce, 3, maxexpansion, status); michael@0: } michael@0: t --; michael@0: } michael@0: /* According to the docs, 99% of the time, the Jamo will not be special */ michael@0: if (jamospecial) { michael@0: /* gets the max expansion in all unicode characters */ michael@0: int count = maxjamoexpansion->position; michael@0: uint8_t maxTSize = (uint8_t)(maxjamoexpansion->maxLSize + michael@0: maxjamoexpansion->maxVSize + michael@0: maxjamoexpansion->maxTSize); michael@0: uint8_t maxVSize = (uint8_t)(maxjamoexpansion->maxLSize + michael@0: maxjamoexpansion->maxVSize); michael@0: michael@0: while (count > 0) { michael@0: count --; michael@0: if (*(maxjamoexpansion->isV + count) == TRUE) { michael@0: uprv_uca_setMaxExpansion( michael@0: *(maxjamoexpansion->endExpansionCE + count), michael@0: maxVSize, maxexpansion, status); michael@0: } michael@0: else { michael@0: uprv_uca_setMaxExpansion( michael@0: *(maxjamoexpansion->endExpansionCE + count), michael@0: maxTSize, maxexpansion, status); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: U_CDECL_BEGIN michael@0: static inline uint32_t U_CALLCONV michael@0: getFoldedValue(UNewTrie *trie, UChar32 start, int32_t offset) michael@0: { michael@0: uint32_t value; michael@0: uint32_t tag; michael@0: UChar32 limit; michael@0: UBool inBlockZero; michael@0: michael@0: limit=start+0x400; michael@0: while(start UCOL_NOT_FOUND && getCETag(data) == SURROGATE_TAG) { michael@0: return (data&0xFFFFFF); michael@0: } else { michael@0: return 0; michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: U_CAPI UCATableHeader* U_EXPORT2 michael@0: uprv_uca_assembleTable(tempUCATable *t, UErrorCode *status) { michael@0: /*CompactEIntArray *mapping = t->mapping;*/ michael@0: UNewTrie *mapping = t->mapping; michael@0: ExpansionTable *expansions = t->expansions; michael@0: CntTable *contractions = t->contractions; michael@0: MaxExpansionTable *maxexpansion = t->maxExpansions; michael@0: michael@0: if(U_FAILURE(*status)) { michael@0: return NULL; michael@0: } michael@0: michael@0: uint32_t beforeContractions = (uint32_t)((headersize+paddedsize(expansions->position*sizeof(uint32_t)))/sizeof(UChar)); michael@0: michael@0: int32_t contractionsSize = 0; michael@0: contractionsSize = uprv_cnttab_constructTable(contractions, beforeContractions, status); michael@0: michael@0: /* the following operation depends on the trie data. Therefore, we have to do it before */ michael@0: /* the trie is compacted */ michael@0: /* sets jamo expansions */ michael@0: uprv_uca_getMaxExpansionJamo(mapping, maxexpansion, t->maxJamoExpansions, michael@0: t->image->jamoSpecial, status); michael@0: michael@0: /*ucmpe32_compact(mapping);*/ michael@0: /*UMemoryStream *ms = uprv_mstrm_openNew(8192);*/ michael@0: /*int32_t mappingSize = ucmpe32_flattenMem(mapping, ms);*/ michael@0: /*const uint8_t *flattened = uprv_mstrm_getBuffer(ms, &mappingSize);*/ michael@0: michael@0: // After setting the jamo expansions, compact the trie and get the needed size michael@0: int32_t mappingSize = utrie_serialize(mapping, NULL, 0, getFoldedValue /*getFoldedValue*/, FALSE, status); michael@0: michael@0: uint32_t tableOffset = 0; michael@0: uint8_t *dataStart; michael@0: michael@0: /* TODO: LATIN1 array is now in the utrie - it should be removed from the calculation */ michael@0: michael@0: uint32_t toAllocate =(uint32_t)(headersize+ michael@0: paddedsize(expansions->position*sizeof(uint32_t))+ michael@0: paddedsize(mappingSize)+ michael@0: paddedsize(contractionsSize*(sizeof(UChar)+sizeof(uint32_t)))+ michael@0: //paddedsize(0x100*sizeof(uint32_t)) /* Latin1 is now included in the trie */ michael@0: /* maxexpansion array */ michael@0: + paddedsize(maxexpansion->position * sizeof(uint32_t)) + michael@0: /* maxexpansion size array */ michael@0: paddedsize(maxexpansion->position * sizeof(uint8_t)) + michael@0: paddedsize(UCOL_UNSAFECP_TABLE_SIZE) + /* Unsafe chars */ michael@0: paddedsize(UCOL_UNSAFECP_TABLE_SIZE)); /* Contraction Ending chars */ michael@0: michael@0: michael@0: dataStart = (uint8_t *)uprv_malloc(toAllocate); michael@0: /* test for NULL */ michael@0: if (dataStart == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return NULL; michael@0: } michael@0: michael@0: UCATableHeader *myData = (UCATableHeader *)dataStart; michael@0: // Please, do reset all the fields! michael@0: uprv_memset(dataStart, 0, toAllocate); michael@0: // Make sure we know this is reset michael@0: myData->magic = UCOL_HEADER_MAGIC; michael@0: myData->isBigEndian = U_IS_BIG_ENDIAN; michael@0: myData->charSetFamily = U_CHARSET_FAMILY; michael@0: myData->formatVersion[0] = UCA_FORMAT_VERSION_0; michael@0: myData->formatVersion[1] = UCA_FORMAT_VERSION_1; michael@0: myData->formatVersion[2] = UCA_FORMAT_VERSION_2; michael@0: myData->formatVersion[3] = UCA_FORMAT_VERSION_3; michael@0: myData->jamoSpecial = t->image->jamoSpecial; michael@0: michael@0: // Don't copy stuff from UCA header! michael@0: //uprv_memcpy(myData, t->image, sizeof(UCATableHeader)); michael@0: michael@0: myData->contractionSize = contractionsSize; michael@0: michael@0: tableOffset += (uint32_t)(paddedsize(sizeof(UCATableHeader))); michael@0: michael@0: myData->options = tableOffset; michael@0: uprv_memcpy(dataStart+tableOffset, t->options, sizeof(UColOptionSet)); michael@0: tableOffset += (uint32_t)(paddedsize(sizeof(UColOptionSet))); michael@0: michael@0: /* copy expansions */ michael@0: /*myData->expansion = (uint32_t *)dataStart+tableOffset;*/ michael@0: myData->expansion = tableOffset; michael@0: uprv_memcpy(dataStart+tableOffset, expansions->CEs, expansions->position*sizeof(uint32_t)); michael@0: tableOffset += (uint32_t)(paddedsize(expansions->position*sizeof(uint32_t))); michael@0: michael@0: /* contractions block */ michael@0: if(contractionsSize != 0) { michael@0: /* copy contraction index */ michael@0: /*myData->contractionIndex = (UChar *)(dataStart+tableOffset);*/ michael@0: myData->contractionIndex = tableOffset; michael@0: uprv_memcpy(dataStart+tableOffset, contractions->codePoints, contractionsSize*sizeof(UChar)); michael@0: tableOffset += (uint32_t)(paddedsize(contractionsSize*sizeof(UChar))); michael@0: michael@0: /* copy contraction collation elements */ michael@0: /*myData->contractionCEs = (uint32_t *)(dataStart+tableOffset);*/ michael@0: myData->contractionCEs = tableOffset; michael@0: uprv_memcpy(dataStart+tableOffset, contractions->CEs, contractionsSize*sizeof(uint32_t)); michael@0: tableOffset += (uint32_t)(paddedsize(contractionsSize*sizeof(uint32_t))); michael@0: } else { michael@0: myData->contractionIndex = 0; michael@0: myData->contractionCEs = 0; michael@0: } michael@0: michael@0: /* copy mapping table */ michael@0: /*myData->mappingPosition = dataStart+tableOffset;*/ michael@0: /*myData->mappingPosition = tableOffset;*/ michael@0: /*uprv_memcpy(dataStart+tableOffset, flattened, mappingSize);*/ michael@0: michael@0: myData->mappingPosition = tableOffset; michael@0: utrie_serialize(mapping, dataStart+tableOffset, toAllocate-tableOffset, getFoldedValue, FALSE, status); michael@0: #ifdef UCOL_DEBUG michael@0: // This is debug code to dump the contents of the trie. It needs two functions defined above michael@0: { michael@0: UTrie UCAt = { 0 }; michael@0: uint32_t trieWord; michael@0: utrie_unserialize(&UCAt, dataStart+tableOffset, 9999999, status); michael@0: UCAt.getFoldingOffset = myGetFoldingOffset; michael@0: if(U_SUCCESS(*status)) { michael@0: utrie_enum(&UCAt, NULL, enumRange, NULL); michael@0: } michael@0: trieWord = UTRIE_GET32_FROM_LEAD(&UCAt, 0xDC01); michael@0: } michael@0: #endif michael@0: tableOffset += paddedsize(mappingSize); michael@0: michael@0: michael@0: int32_t i = 0; michael@0: michael@0: /* copy max expansion table */ michael@0: myData->endExpansionCE = tableOffset; michael@0: myData->endExpansionCECount = maxexpansion->position - 1; michael@0: /* not copying the first element which is a dummy */ michael@0: uprv_memcpy(dataStart + tableOffset, maxexpansion->endExpansionCE + 1, michael@0: (maxexpansion->position - 1) * sizeof(uint32_t)); michael@0: tableOffset += (uint32_t)(paddedsize((maxexpansion->position)* sizeof(uint32_t))); michael@0: myData->expansionCESize = tableOffset; michael@0: uprv_memcpy(dataStart + tableOffset, maxexpansion->expansionCESize + 1, michael@0: (maxexpansion->position - 1) * sizeof(uint8_t)); michael@0: tableOffset += (uint32_t)(paddedsize((maxexpansion->position)* sizeof(uint8_t))); michael@0: michael@0: /* Unsafe chars table. Finish it off, then copy it. */ michael@0: uprv_uca_unsafeCPAddCCNZ(t, status); michael@0: if (t->UCA != 0) { /* Or in unsafebits from UCA, making a combined table. */ michael@0: for (i=0; iunsafeCP[i] |= t->UCA->unsafeCP[i]; michael@0: } michael@0: } michael@0: myData->unsafeCP = tableOffset; michael@0: uprv_memcpy(dataStart + tableOffset, t->unsafeCP, UCOL_UNSAFECP_TABLE_SIZE); michael@0: tableOffset += paddedsize(UCOL_UNSAFECP_TABLE_SIZE); michael@0: michael@0: michael@0: /* Finish building Contraction Ending chars hash table and then copy it out. */ michael@0: if (t->UCA != 0) { /* Or in unsafebits from UCA, making a combined table. */ michael@0: for (i=0; icontrEndCP[i] |= t->UCA->contrEndCP[i]; michael@0: } michael@0: } michael@0: myData->contrEndCP = tableOffset; michael@0: uprv_memcpy(dataStart + tableOffset, t->contrEndCP, UCOL_UNSAFECP_TABLE_SIZE); michael@0: tableOffset += paddedsize(UCOL_UNSAFECP_TABLE_SIZE); michael@0: michael@0: if(tableOffset != toAllocate) { michael@0: #ifdef UCOL_DEBUG michael@0: fprintf(stderr, "calculation screwup!!! Expected to write %i but wrote %i instead!!!\n", toAllocate, tableOffset); michael@0: #endif michael@0: *status = U_INTERNAL_PROGRAM_ERROR; michael@0: uprv_free(dataStart); michael@0: return 0; michael@0: } michael@0: michael@0: myData->size = tableOffset; michael@0: /* This should happen upon ressurection */ michael@0: /*const uint8_t *mapPosition = (uint8_t*)myData+myData->mappingPosition;*/ michael@0: /*uprv_mstrm_close(ms);*/ michael@0: return myData; michael@0: } michael@0: michael@0: michael@0: struct enumStruct { michael@0: tempUCATable *t; michael@0: UCollator *tempColl; michael@0: UCollationElements* colEl; michael@0: const Normalizer2Impl *nfcImpl; michael@0: UnicodeSet *closed; michael@0: int32_t noOfClosures; michael@0: UErrorCode *status; michael@0: }; michael@0: U_CDECL_BEGIN michael@0: static UBool U_CALLCONV michael@0: _enumCategoryRangeClosureCategory(const void *context, UChar32 start, UChar32 limit, UCharCategory type) { michael@0: michael@0: if (type != U_UNASSIGNED && type != U_PRIVATE_USE_CHAR) { // if the range is assigned - we might ommit more categories later michael@0: UErrorCode *status = ((enumStruct *)context)->status; michael@0: tempUCATable *t = ((enumStruct *)context)->t; michael@0: UCollator *tempColl = ((enumStruct *)context)->tempColl; michael@0: UCollationElements* colEl = ((enumStruct *)context)->colEl; michael@0: UCAElements el; michael@0: UChar decompBuffer[4]; michael@0: const UChar *decomp; michael@0: int32_t noOfDec = 0; michael@0: michael@0: UChar32 u32 = 0; michael@0: UChar comp[2]; michael@0: uint32_t len = 0; michael@0: michael@0: for(u32 = start; u32 < limit; u32++) { michael@0: decomp = ((enumStruct *)context)->nfcImpl-> michael@0: getDecomposition(u32, decompBuffer, noOfDec); michael@0: //if((noOfDec = unorm_normalize(comp, len, UNORM_NFD, 0, decomp, 256, status)) > 1 michael@0: //|| (noOfDec == 1 && *decomp != (UChar)u32)) michael@0: if(decomp != NULL) michael@0: { michael@0: len = 0; michael@0: U16_APPEND_UNSAFE(comp, len, u32); michael@0: if(ucol_strcoll(tempColl, comp, len, decomp, noOfDec) != UCOL_EQUAL) { michael@0: #ifdef UCOL_DEBUG michael@0: fprintf(stderr, "Closure: U+%04X -> ", u32); michael@0: UChar32 c; michael@0: int32_t i = 0; michael@0: while(i < noOfDec) { michael@0: U16_NEXT(decomp, i, noOfDec, c); michael@0: fprintf(stderr, "%04X ", c); michael@0: } michael@0: fprintf(stderr, "\n"); michael@0: // print CEs for code point vs. decomposition michael@0: fprintf(stderr, "U+%04X CEs: ", u32); michael@0: UCollationElements *iter = ucol_openElements(tempColl, comp, len, status); michael@0: int32_t ce; michael@0: while((ce = ucol_next(iter, status)) != UCOL_NULLORDER) { michael@0: fprintf(stderr, "%08X ", ce); michael@0: } michael@0: fprintf(stderr, "\nDecomp CEs: "); michael@0: ucol_setText(iter, decomp, noOfDec, status); michael@0: while((ce = ucol_next(iter, status)) != UCOL_NULLORDER) { michael@0: fprintf(stderr, "%08X ", ce); michael@0: } michael@0: fprintf(stderr, "\n"); michael@0: ucol_closeElements(iter); michael@0: #endif michael@0: if(((enumStruct *)context)->closed != NULL) { michael@0: ((enumStruct *)context)->closed->add(u32); michael@0: } michael@0: ((enumStruct *)context)->noOfClosures++; michael@0: el.cPoints = (UChar *)decomp; michael@0: el.cSize = noOfDec; michael@0: el.noOfCEs = 0; michael@0: el.prefix = el.prefixChars; michael@0: el.prefixSize = 0; michael@0: michael@0: UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, &el); michael@0: el.cPoints = comp; michael@0: el.cSize = len; michael@0: el.prefix = el.prefixChars; michael@0: el.prefixSize = 0; michael@0: if(prefix == NULL) { michael@0: el.noOfCEs = 0; michael@0: ucol_setText(colEl, decomp, noOfDec, status); michael@0: while((el.CEs[el.noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) { michael@0: el.noOfCEs++; michael@0: } michael@0: } else { michael@0: el.noOfCEs = 1; michael@0: el.CEs[0] = prefix->mapCE; michael@0: // This character uses a prefix. We have to add it michael@0: // to the unsafe table, as it decomposed form is already michael@0: // in. In Japanese, this happens for \u309e & \u30fe michael@0: // Since unsafeCPSet is static in ucol_elm, we are going michael@0: // to wrap it up in the uprv_uca_unsafeCPAddCCNZ function michael@0: } michael@0: uprv_uca_addAnElement(t, &el, status); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return TRUE; michael@0: } michael@0: U_CDECL_END michael@0: michael@0: static void michael@0: uprv_uca_setMapCE(tempUCATable *t, UCAElements *element, UErrorCode *status) { michael@0: uint32_t expansion = 0; michael@0: int32_t j; michael@0: michael@0: ExpansionTable *expansions = t->expansions; michael@0: if(element->noOfCEs == 2 // a two CE expansion michael@0: && isContinuation(element->CEs[1]) // which is a continuation michael@0: && (element->CEs[1] & (~(0xFF << 24 | UCOL_CONTINUATION_MARKER))) == 0 // that has only primaries in continuation, michael@0: && (((element->CEs[0]>>8) & 0xFF) == UCOL_BYTE_COMMON) // a common secondary michael@0: && ((element->CEs[0] & 0xFF) == UCOL_BYTE_COMMON) // and a common tertiary michael@0: ) { michael@0: element->mapCE = UCOL_SPECIAL_FLAG | (LONG_PRIMARY_TAG<<24) // a long primary special michael@0: | ((element->CEs[0]>>8) & 0xFFFF00) // first and second byte of primary michael@0: | ((element->CEs[1]>>24) & 0xFF); // third byte of primary michael@0: } else { michael@0: expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (EXPANSION_TAG<CEs[0], status)+(headersize>>2))<<4) michael@0: & 0xFFFFF0)); michael@0: michael@0: for(j = 1; j<(int32_t)element->noOfCEs; j++) { michael@0: uprv_uca_addExpansion(expansions, element->CEs[j], status); michael@0: } michael@0: if(element->noOfCEs <= 0xF) { michael@0: expansion |= element->noOfCEs; michael@0: } else { michael@0: uprv_uca_addExpansion(expansions, 0, status); michael@0: } michael@0: element->mapCE = expansion; michael@0: uprv_uca_setMaxExpansion(element->CEs[element->noOfCEs - 1], michael@0: (uint8_t)element->noOfCEs, michael@0: t->maxExpansions, michael@0: status); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: uprv_uca_addFCD4AccentedContractions(tempUCATable *t, michael@0: UCollationElements* colEl, michael@0: UChar *data, michael@0: int32_t len, michael@0: UCAElements *el, michael@0: UErrorCode *status) { michael@0: UChar decomp[256], comp[256]; michael@0: int32_t decLen, compLen; michael@0: michael@0: decLen = unorm_normalize(data, len, UNORM_NFD, 0, decomp, 256, status); michael@0: compLen = unorm_normalize(data, len, UNORM_NFC, 0, comp, 256, status); michael@0: decomp[decLen] = comp[compLen] = 0; michael@0: michael@0: el->cPoints = decomp; michael@0: el->cSize = decLen; michael@0: el->noOfCEs = 0; michael@0: el->prefixSize = 0; michael@0: el->prefix = el->prefixChars; michael@0: michael@0: UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, el); michael@0: el->cPoints = comp; michael@0: el->cSize = compLen; michael@0: el->prefix = el->prefixChars; michael@0: el->prefixSize = 0; michael@0: if(prefix == NULL) { michael@0: el->noOfCEs = 0; michael@0: ucol_setText(colEl, decomp, decLen, status); michael@0: while((el->CEs[el->noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) { michael@0: el->noOfCEs++; michael@0: } michael@0: uprv_uca_setMapCE(t, el, status); michael@0: uprv_uca_addAnElement(t, el, status); michael@0: } michael@0: el->cPoints=NULL; /* don't leak reference to stack */ michael@0: } michael@0: michael@0: static void michael@0: uprv_uca_addMultiCMContractions(tempUCATable *t, michael@0: UCollationElements* colEl, michael@0: tempTailorContext *c, michael@0: UCAElements *el, michael@0: UErrorCode *status) { michael@0: CombinClassTable *cmLookup = t->cmLookup; michael@0: UChar newDecomp[256]; michael@0: int32_t maxComp, newDecLen; michael@0: const Normalizer2Impl *nfcImpl = Normalizer2Factory::getNFCImpl(*status); michael@0: if (U_FAILURE(*status)) { michael@0: return; michael@0: } michael@0: int16_t curClass = nfcImpl->getFCD16(c->tailoringCM) & 0xff; michael@0: CompData *precomp = c->precomp; michael@0: int32_t compLen = c->compLen; michael@0: UChar *comp = c->comp; michael@0: maxComp = c->precompLen; michael@0: michael@0: for (int32_t j=0; j < maxComp; j++) { michael@0: int32_t count=0; michael@0: do { michael@0: if ( count == 0 ) { // Decompose the saved precomposed char. michael@0: UChar temp[2]; michael@0: temp[0]=precomp[j].cp; michael@0: temp[1]=0; michael@0: newDecLen = unorm_normalize(temp, 1, UNORM_NFD, 0, michael@0: newDecomp, sizeof(newDecomp)/sizeof(UChar), status); michael@0: newDecomp[newDecLen++] = cmLookup->cPoints[c->cmPos]; michael@0: } michael@0: else { // swap 2 combining marks when they are equal. michael@0: uprv_memcpy(newDecomp, c->decomp, sizeof(UChar)*(c->decompLen)); michael@0: newDecLen = c->decompLen; michael@0: newDecomp[newDecLen++] = precomp[j].cClass; michael@0: } michael@0: newDecomp[newDecLen] = 0; michael@0: compLen = unorm_normalize(newDecomp, newDecLen, UNORM_NFC, 0, michael@0: comp, 256, status); michael@0: if (compLen==1) { michael@0: comp[compLen++] = newDecomp[newDecLen++] = c->tailoringCM; michael@0: comp[compLen] = newDecomp[newDecLen] = 0; michael@0: el->cPoints = newDecomp; michael@0: el->cSize = newDecLen; michael@0: michael@0: UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, el); michael@0: el->cPoints = c->comp; michael@0: el->cSize = compLen; michael@0: el->prefix = el->prefixChars; michael@0: el->prefixSize = 0; michael@0: if(prefix == NULL) { michael@0: el->noOfCEs = 0; michael@0: ucol_setText(colEl, newDecomp, newDecLen, status); michael@0: while((el->CEs[el->noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) { michael@0: el->noOfCEs++; michael@0: } michael@0: uprv_uca_setMapCE(t, el, status); michael@0: uprv_uca_finalizeAddition(t, el, status); michael@0: michael@0: // Save the current precomposed char and its class to find any michael@0: // other combining mark combinations. michael@0: precomp[c->precompLen].cp=comp[0]; michael@0: precomp[c->precompLen].cClass = curClass; michael@0: c->precompLen++; michael@0: } michael@0: } michael@0: } while (++count<2 && (precomp[j].cClass == curClass)); michael@0: } michael@0: michael@0: } michael@0: michael@0: static void michael@0: uprv_uca_addTailCanonicalClosures(tempUCATable *t, michael@0: UCollationElements* colEl, michael@0: UChar baseCh, michael@0: UChar cMark, michael@0: UCAElements *el, michael@0: UErrorCode *status) { michael@0: CombinClassTable *cmLookup = t->cmLookup; michael@0: const Normalizer2Impl *nfcImpl = Normalizer2Factory::getNFCImpl(*status); michael@0: if (U_FAILURE(*status)) { michael@0: return; michael@0: } michael@0: int16_t maxIndex = nfcImpl->getFCD16(cMark) & 0xff; michael@0: UCAElements element; michael@0: uint16_t *index; michael@0: UChar decomp[256]; michael@0: UChar comp[256]; michael@0: CompData precomp[256]; // precomposed array michael@0: int32_t precompLen = 0; // count for precomp michael@0: int32_t i, len, decompLen, replacedPos; michael@0: tempTailorContext c; michael@0: michael@0: if ( cmLookup == NULL ) { michael@0: return; michael@0: } michael@0: index = cmLookup->index; michael@0: int32_t cClass=nfcImpl->getFCD16(cMark) & 0xff; michael@0: maxIndex = (int32_t)index[(nfcImpl->getFCD16(cMark) & 0xff)-1]; michael@0: c.comp = comp; michael@0: c.decomp = decomp; michael@0: c.precomp = precomp; michael@0: c.tailoringCM = cMark; michael@0: michael@0: if (cClass>0) { michael@0: maxIndex = (int32_t)index[cClass-1]; michael@0: } michael@0: else { michael@0: maxIndex=0; michael@0: } michael@0: decomp[0]=baseCh; michael@0: for ( i=0; icPoints[i]; michael@0: decomp[2]=0; michael@0: decompLen=2; michael@0: len = unorm_normalize(decomp, decompLen, UNORM_NFC, 0, comp, 256, status); michael@0: if (len==1) { michael@0: // Save the current precomposed char and its class to find any michael@0: // other combining mark combinations. michael@0: precomp[precompLen].cp=comp[0]; michael@0: precomp[precompLen].cClass = michael@0: index[nfcImpl->getFCD16(decomp[1]) & 0xff]; michael@0: precompLen++; michael@0: replacedPos=0; michael@0: for (decompLen=0; decompLen< (int32_t)el->cSize; decompLen++) { michael@0: decomp[decompLen] = el->cPoints[decompLen]; michael@0: if (decomp[decompLen]==cMark) { michael@0: replacedPos = decompLen; // record the position for later use michael@0: } michael@0: } michael@0: if ( replacedPos != 0 ) { michael@0: decomp[replacedPos]=cmLookup->cPoints[i]; michael@0: } michael@0: decomp[decompLen] = 0; michael@0: len = unorm_normalize(decomp, decompLen, UNORM_NFC, 0, comp, 256, status); michael@0: comp[len++] = decomp[decompLen++] = cMark; michael@0: comp[len] = decomp[decompLen] = 0; michael@0: element.cPoints = decomp; michael@0: element.cSize = decompLen; michael@0: element.noOfCEs = 0; michael@0: element.prefix = el->prefixChars; michael@0: element.prefixSize = 0; michael@0: michael@0: UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, &element); michael@0: element.cPoints = comp; michael@0: element.cSize = len; michael@0: element.prefix = el->prefixChars; michael@0: element.prefixSize = 0; michael@0: if(prefix == NULL) { michael@0: element.noOfCEs = 0; michael@0: ucol_setText(colEl, decomp, decompLen, status); michael@0: while((element.CEs[element.noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) { michael@0: element.noOfCEs++; michael@0: } michael@0: uprv_uca_setMapCE(t, &element, status); michael@0: uprv_uca_finalizeAddition(t, &element, status); michael@0: } michael@0: michael@0: // This is a fix for tailoring contractions with accented michael@0: // character at the end of contraction string. michael@0: if ((len>2) && michael@0: (nfcImpl->getFCD16(comp[len-2]) & 0xff00)==0) { michael@0: uprv_uca_addFCD4AccentedContractions(t, colEl, comp, len, &element, status); michael@0: } michael@0: michael@0: if (precompLen >1) { michael@0: c.compLen = len; michael@0: c.decompLen = decompLen; michael@0: c.precompLen = precompLen; michael@0: c.cmPos = i; michael@0: uprv_uca_addMultiCMContractions(t, colEl, &c, &element, status); michael@0: precompLen = c.precompLen; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: U_CFUNC int32_t U_EXPORT2 michael@0: uprv_uca_canonicalClosure(tempUCATable *t, michael@0: UColTokenParser *src, michael@0: UnicodeSet *closed, michael@0: UErrorCode *status) michael@0: { michael@0: enumStruct context; michael@0: context.closed = closed; michael@0: context.noOfClosures = 0; michael@0: UCAElements el; michael@0: UColToken *tok; michael@0: uint32_t i = 0, j = 0; michael@0: UChar baseChar, firstCM; michael@0: context.nfcImpl=Normalizer2Factory::getNFCImpl(*status); michael@0: if(U_FAILURE(*status)) { michael@0: return 0; michael@0: } michael@0: michael@0: UCollator *tempColl = NULL; michael@0: tempUCATable *tempTable = uprv_uca_cloneTempTable(t, status); michael@0: // Check for null pointer michael@0: if (U_FAILURE(*status)) { michael@0: return 0; michael@0: } michael@0: michael@0: UCATableHeader *tempData = uprv_uca_assembleTable(tempTable, status); michael@0: tempColl = ucol_initCollator(tempData, 0, t->UCA, status); michael@0: if ( tempTable->cmLookup != NULL ) { michael@0: t->cmLookup = tempTable->cmLookup; // copy over to t michael@0: tempTable->cmLookup = NULL; michael@0: } michael@0: uprv_uca_closeTempTable(tempTable); michael@0: michael@0: if(U_SUCCESS(*status)) { michael@0: tempColl->ucaRules = NULL; michael@0: tempColl->actualLocale = NULL; michael@0: tempColl->validLocale = NULL; michael@0: tempColl->requestedLocale = NULL; michael@0: tempColl->hasRealData = TRUE; michael@0: tempColl->freeImageOnClose = TRUE; michael@0: } else if(tempData != 0) { michael@0: uprv_free(tempData); michael@0: } michael@0: michael@0: /* produce canonical closure */ michael@0: UCollationElements* colEl = ucol_openElements(tempColl, NULL, 0, status); michael@0: // Check for null pointer michael@0: if (U_FAILURE(*status)) { michael@0: return 0; michael@0: } michael@0: context.t = t; michael@0: context.tempColl = tempColl; michael@0: context.colEl = colEl; michael@0: context.status = status; michael@0: u_enumCharTypes(_enumCategoryRangeClosureCategory, &context); michael@0: michael@0: if ( (src==NULL) || !src->buildCCTabFlag ) { michael@0: ucol_closeElements(colEl); michael@0: ucol_close(tempColl); michael@0: return context.noOfClosures; // no extra contraction needed to add michael@0: } michael@0: michael@0: for (i=0; i < src->resultLen; i++) { michael@0: baseChar = firstCM= (UChar)0; michael@0: tok = src->lh[i].first; michael@0: while (tok != NULL && U_SUCCESS(*status)) { michael@0: el.prefix = el.prefixChars; michael@0: el.cPoints = el.uchars; michael@0: if(tok->prefix != 0) { michael@0: el.prefixSize = tok->prefix>>24; michael@0: uprv_memcpy(el.prefix, src->source + (tok->prefix & 0x00FFFFFF), el.prefixSize*sizeof(UChar)); michael@0: michael@0: el.cSize = (tok->source >> 24)-(tok->prefix>>24); michael@0: uprv_memcpy(el.uchars, (tok->source & 0x00FFFFFF)+(tok->prefix>>24) + src->source, el.cSize*sizeof(UChar)); michael@0: } else { michael@0: el.prefixSize = 0; michael@0: *el.prefix = 0; michael@0: michael@0: el.cSize = (tok->source >> 24); michael@0: uprv_memcpy(el.uchars, (tok->source & 0x00FFFFFF) + src->source, el.cSize*sizeof(UChar)); michael@0: } michael@0: if(src->UCA != NULL) { michael@0: for(j = 0; jgetFCD16(el.cPoints[j]); michael@0: if ( (fcd & 0xff) == 0 ) { michael@0: baseChar = el.cPoints[j]; // last base character michael@0: firstCM=0; // reset combining mark value michael@0: } michael@0: else { michael@0: if ( (baseChar!=0) && (firstCM==0) ) { michael@0: firstCM = el.cPoints[j]; // first combining mark michael@0: } michael@0: } michael@0: } michael@0: } michael@0: if ( (baseChar!= (UChar)0) && (firstCM != (UChar)0) ) { michael@0: // find all the canonical rules michael@0: uprv_uca_addTailCanonicalClosures(t, colEl, baseChar, firstCM, &el, status); michael@0: } michael@0: tok = tok->next; michael@0: } michael@0: } michael@0: ucol_closeElements(colEl); michael@0: ucol_close(tempColl); michael@0: michael@0: return context.noOfClosures; michael@0: } michael@0: michael@0: #endif /* #if !UCONFIG_NO_COLLATION */