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